summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.c662
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.h536
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.c395
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.h427
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.c464
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.h352
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.c214
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.h186
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c1031
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h761
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c470
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h245
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.c303
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.h254
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.c602
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.h463
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.c314
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.h325
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.c371
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.h321
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.c86
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.h641
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.c249
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.h837
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_dsp.h170
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.c1417
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.h730
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.c200
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.h418
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.c913
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.h735
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.c174
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.h380
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.c1461
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.h580
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.c91
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.h189
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.c2858
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.h1018
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.c387
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.h767
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.c625
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.h562
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.c3993
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.h2046
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.c140
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.h218
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.c4613
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.h2241
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan_edma.h188
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.c433
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.h735
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera.h230
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera_edma.h130
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.c1377
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.h485
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.c903
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.h560
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_dma.h198
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.c445
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.h201
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd.h685
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_edma.h153
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_smartdma.h158
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.c1553
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.h719
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_dma.h205
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.c565
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.h207
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.c1009
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.h581
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_dma.h176
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.c407
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.h178
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.c423
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.h508
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.c1271
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.h886
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_dma.h144
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.c366
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.h150
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.c103
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.h231
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.c127
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.h509
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.c141
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.h181
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.c391
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.h124
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.c183
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.h344
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.c218
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.h181
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c203
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h180
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c527
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.h655
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.c708
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.h1070
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c2608
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h1320
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c616
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h158
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h107
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c2421
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h1158
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c1052
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h301
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h107
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.c2368
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.h1068
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_dma.h186
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.c503
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.h189
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_freertos.h192
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.c340
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.h396
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.c260
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.h383
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c1433
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.h824
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.c414
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.h752
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c406
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h211
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c963
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h1213
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c459
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h254
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h140
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.c146
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.h334
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.c949
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.h335
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.c1328
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.h1225
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.c2188
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.h2712
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.c777
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.h563
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.c310
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.h447
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.c236
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.h194
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.c148
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.h425
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.c3831
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.h1586
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.c1033
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.h367
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_sdma.h238
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.c252
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.h260
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.c1385
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.h924
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h274
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c1143
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h182
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h127
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c227
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.c565
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.h649
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.c1358
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.h733
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c849
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h753
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c598
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h192
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.c49
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.h602
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.c179
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.h474
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.c204
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.h127
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.c368
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.h186
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.c2009
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.h239
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.c2480
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.h1703
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.c214
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.h305
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.c229
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.h186
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.c126
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.h82
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.c148
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.h322
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.c925
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.h690
190 files changed, 124232 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.c b/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.c
new file mode 100644
index 0000000000..80ae4320f3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_acmp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.acmp"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the ACMP instance from the peripheral base address.
+ *
+ * @param base ACMP peripheral base address.
+ * @return ACMP instance.
+ */
+static uint32_t ACMP_GetInstance(CMP_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Array of ACMP peripheral base address. */
+static CMP_Type *const s_acmpBases[] = CMP_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name of ACMP. */
+static const clock_ip_name_t s_acmpClock[] = CMP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t ACMP_GetInstance(CMP_Type *base)
+{
+ uint32_t instance = 0U;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_acmpBases); instance++)
+ {
+ if (s_acmpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_acmpBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the ACMP.
+ *
+ * The default configuration can be got by calling ACMP_GetDefaultConfig().
+ *
+ * param base ACMP peripheral base address.
+ * param config Pointer to ACMP configuration structure.
+ */
+void ACMP_Init(CMP_Type *base, const acmp_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Open clock gate. */
+ CLOCK_EnableClock(s_acmpClock[ACMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Disable the module before configuring it. */
+ ACMP_Enable(base, false);
+
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ tmp32 = (base->C0 & (~(CMP_C0_PMODE_MASK | CMP_C0_INVT_MASK | CMP_C0_COS_MASK | CMP_C0_OPE_MASK |
+ CMP_C0_HYSTCTR_MASK | CMP_C0_CFx_MASK)));
+#if defined(FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT) && (FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT == 1U)
+ tmp32 &= ~CMP_C0_OFFSET_MASK;
+#endif /* FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT */
+ if (config->enableHighSpeed)
+ {
+ tmp32 |= CMP_C0_PMODE_MASK;
+ }
+ if (config->enableInvertOutput)
+ {
+ tmp32 |= CMP_C0_INVT_MASK;
+ }
+ if (config->useUnfilteredOutput)
+ {
+ tmp32 |= CMP_C0_COS_MASK;
+ }
+ if (config->enablePinOut)
+ {
+ tmp32 |= CMP_C0_OPE_MASK;
+ }
+ tmp32 |= CMP_C0_HYSTCTR(config->hysteresisMode);
+#if defined(FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT) && (FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT == 1U)
+ tmp32 |= CMP_C0_OFFSET(config->offsetMode);
+#endif /* FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT */
+ base->C0 = tmp32;
+}
+
+/*!
+ * brief Deinitializes the ACMP.
+ *
+ * param base ACMP peripheral base address.
+ */
+void ACMP_Deinit(CMP_Type *base)
+{
+ /* Disable the module. */
+ ACMP_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable clock gate. */
+ CLOCK_DisableClock(s_acmpClock[ACMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration for ACMP.
+ *
+ * This function initializes the user configuration structure to default value. The default value are:
+ *
+ * Example:
+ code
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+ config->enableHysteresisBothDirections = false;
+ config->hysteresisMode = kACMP_hysteresisMode0;
+ endcode
+ *
+ * param config Pointer to ACMP configuration structure.
+ */
+void ACMP_GetDefaultConfig(acmp_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Fill default configuration */
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+#if defined(FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT) && (FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT == 1U)
+ config->offsetMode = kACMP_OffsetLevel0;
+#endif /* FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT */
+ config->hysteresisMode = kACMP_HysteresisLevel0;
+}
+
+/*!
+ * brief Enables or disables the ACMP.
+ *
+ * param base ACMP peripheral base address.
+ * param enable True to enable the ACMP.
+ */
+void ACMP_Enable(CMP_Type *base, bool enable)
+{
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ if (enable)
+ {
+ base->C0 = ((base->C0 | CMP_C0_EN_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ else
+ {
+ base->C0 &= ~(CMP_C0_EN_MASK | CMP_C0_CFx_MASK);
+ }
+}
+
+#if defined(FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT) && (FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT == 1U)
+/*!
+ * brief Enables the link from CMP to DAC enable.
+ *
+ * When this bit is set, the DAC enable/disable is controlled by the bit CMP_C0[EN] instead of CMP_C1[DACEN].
+ *
+ * param base ACMP peripheral base address.
+ * param enable Enable the feature or not.
+ */
+void ACMP_EnableLinkToDAC(CMP_Type *base, bool enable)
+{
+ /* CMPx_C0_LINKEN
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ if (enable)
+ {
+ base->C0 = ((base->C0 | CMP_C0_LINKEN_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ else
+ {
+ base->C0 &= ~(CMP_C0_LINKEN_MASK | CMP_C0_CFx_MASK);
+ }
+}
+#endif /* FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT */
+
+/*!
+ * brief Sets the channel configuration.
+ *
+ * Note that the plus/minus mux's setting is only valid when the positive/negative port's input isn't from DAC but
+ * from channel mux.
+ *
+ * Example:
+ code
+ acmp_channel_config_t configStruct = {0};
+ configStruct.positivePortInput = kACMP_PortInputFromDAC;
+ configStruct.negativePortInput = kACMP_PortInputFromMux;
+ configStruct.minusMuxInput = 1U;
+ ACMP_SetChannelConfig(CMP0, &configStruct);
+ endcode
+ *
+ * param base ACMP peripheral base address.
+ * param config Pointer to channel configuration structure.
+ */
+void ACMP_SetChannelConfig(CMP_Type *base, const acmp_channel_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32 = (base->C1 & (~(CMP_C1_PSEL_MASK | CMP_C1_MSEL_MASK)));
+
+/* CMPx_C1
+ * Set the input of CMP's positive port.
+ */
+#if (defined(FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT) && (FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT == 1U))
+ tmp32 &= ~CMP_C1_INPSEL_MASK;
+ tmp32 |= CMP_C1_INPSEL(config->positivePortInput);
+#endif /* FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT */
+
+#if (defined(FSL_FEATURE_ACMP_HAS_C1_INNSEL_BIT) && (FSL_FEATURE_ACMP_HAS_C1_INNSEL_BIT == 1U))
+ tmp32 &= ~CMP_C1_INNSEL_MASK;
+ tmp32 |= CMP_C1_INNSEL(config->negativePortInput);
+#endif /* FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT */
+
+ tmp32 |= CMP_C1_PSEL(config->plusMuxInput) | CMP_C1_MSEL(config->minusMuxInput);
+
+ base->C1 = tmp32;
+}
+
+/*!
+ * brief Enables or disables DMA.
+ *
+ * param base ACMP peripheral base address.
+ * param enable True to enable DMA.
+ */
+void ACMP_EnableDMA(CMP_Type *base, bool enable)
+{
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ if (enable)
+ {
+ base->C0 = ((base->C0 | CMP_C0_DMAEN_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ else
+ {
+ base->C0 &= ~(CMP_C0_DMAEN_MASK | CMP_C0_CFx_MASK);
+ }
+}
+
+/*!
+ * brief Enables or disables window mode.
+ *
+ * param base ACMP peripheral base address.
+ * param enable True to enable window mode.
+ */
+void ACMP_EnableWindowMode(CMP_Type *base, bool enable)
+{
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ if (enable)
+ {
+ base->C0 = ((base->C0 | CMP_C0_WE_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ else
+ {
+ base->C0 &= ~(CMP_C0_WE_MASK | CMP_C0_CFx_MASK);
+ }
+}
+
+/*!
+ * brief Configures the filter.
+ *
+ * The filter can be enabled when the filter count is bigger than 1, the filter period is greater than 0 and the sample
+ * clock is from divided bus clock or the filter is bigger than 1 and the sample clock is from external clock. Detailed
+ * usage can be got from the reference manual.
+ *
+ * Example:
+ code
+ acmp_filter_config_t configStruct = {0};
+ configStruct.filterCount = 5U;
+ configStruct.filterPeriod = 200U;
+ configStruct.enableSample = false;
+ ACMP_SetFilterConfig(CMP0, &configStruct);
+ endcode
+ *
+ * param base ACMP peripheral base address.
+ * param config Pointer to filter configuration structure.
+ */
+void ACMP_SetFilterConfig(CMP_Type *base, const acmp_filter_config_t *config)
+{
+ assert(NULL != config);
+
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ uint32_t tmp32 = (base->C0 & (~(CMP_C0_FILTER_CNT_MASK | CMP_C0_FPR_MASK | CMP_C0_SE_MASK | CMP_C0_CFx_MASK)));
+
+ if (config->enableSample)
+ {
+ tmp32 |= CMP_C0_SE_MASK;
+ }
+ tmp32 |= (CMP_C0_FILTER_CNT(config->filterCount) | CMP_C0_FPR(config->filterPeriod));
+ base->C0 = tmp32;
+}
+
+/*!
+ * brief Configures the internal DAC.
+ *
+ * Example:
+ code
+ acmp_dac_config_t configStruct = {0};
+ configStruct.referenceVoltageSource = kACMP_VrefSourceVin1;
+ configStruct.DACValue = 20U;
+ configStruct.enableOutput = false;
+ configStruct.workMode = kACMP_DACWorkLowSpeedMode;
+ ACMP_SetDACConfig(CMP0, &configStruct);
+ endcode
+ *
+ * param base ACMP peripheral base address.
+ * param config Pointer to DAC configuration structure. "NULL" is for disabling the feature.
+ */
+void ACMP_SetDACConfig(CMP_Type *base, const acmp_dac_config_t *config)
+{
+ uint32_t tmp32;
+
+ /* CMPx_C1
+ * NULL configuration means to disable the feature.
+ */
+ if (NULL == config)
+ {
+ base->C1 &= ~CMP_C1_DACEN_MASK;
+ return;
+ }
+
+ tmp32 = (base->C1 & (~(CMP_C1_VRSEL_MASK | CMP_C1_VOSEL_MASK)));
+ /* Set configuration and enable the feature. */
+ tmp32 |= (CMP_C1_VRSEL(config->referenceVoltageSource) | CMP_C1_VOSEL(config->DACValue) | CMP_C1_DACEN_MASK);
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT == 1U)
+ tmp32 &= ~CMP_C1_DACOE_MASK;
+ if (config->enableOutput)
+ {
+ tmp32 |= CMP_C1_DACOE_MASK;
+ }
+#endif /* FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT */
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT == 1U)
+ switch (config->workMode)
+ {
+ case kACMP_DACWorkLowSpeedMode:
+ tmp32 &= ~CMP_C1_DMODE_MASK;
+ break;
+ case kACMP_DACWorkHighSpeedMode:
+ tmp32 |= CMP_C1_DMODE_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+#endif /* FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT */
+
+ base->C1 = tmp32;
+}
+
+/*!
+ * brief Configures the round robin mode.
+ *
+ * Example:
+ code
+ acmp_round_robin_config_t configStruct = {0};
+ configStruct.fixedPort = kACMP_FixedPlusPort;
+ configStruct.fixedChannelNumber = 3U;
+ configStruct.checkerChannelMask = 0xF7U;
+ configStruct.sampleClockCount = 0U;
+ configStruct.delayModulus = 0U;
+ ACMP_SetRoundRobinConfig(CMP0, &configStruct);
+ endcode
+ * param base ACMP peripheral base address.
+ * param config Pointer to round robin mode configuration structure. "NULL" is for disabling the feature.
+ */
+void ACMP_SetRoundRobinConfig(CMP_Type *base, const acmp_round_robin_config_t *config)
+{
+ uint32_t tmp32;
+
+ /* CMPx_C2
+ * Set control bit. Avoid clearing status flags at the same time.
+ * NULL configuration means to disable the feature.
+ */
+ if (NULL == config)
+ {
+ tmp32 = CMP_C2_CHnF_MASK;
+#if defined(FSL_FEATURE_ACMP_HAS_C2_RRE_BIT) && (FSL_FEATURE_ACMP_HAS_C2_RRE_BIT == 1U)
+ tmp32 |= CMP_C2_RRE_MASK;
+#endif /* FSL_FEATURE_ACMP_HAS_C2_RRE_BIT */
+ base->C2 &= ~(tmp32);
+ return;
+ }
+
+ /* CMPx_C1
+ * Set all channel's round robin checker enable mask.
+ */
+ tmp32 = (base->C1 & ~(CMP_C1_CHNn_MASK));
+ tmp32 |= ((config->checkerChannelMask) << CMP_C1_CHN0_SHIFT);
+ base->C1 = tmp32;
+
+ /* CMPx_C2
+ * Set configuration and enable the feature.
+ */
+ tmp32 = (base->C2 &
+ (~(CMP_C2_FXMP_MASK | CMP_C2_FXMXCH_MASK | CMP_C2_NSAM_MASK | CMP_C2_INITMOD_MASK | CMP_C2_CHnF_MASK)));
+ tmp32 |= (CMP_C2_FXMP(config->fixedPort) | CMP_C2_FXMXCH(config->fixedChannelNumber) |
+ CMP_C2_NSAM(config->sampleClockCount) | CMP_C2_INITMOD(config->delayModulus));
+#if defined(FSL_FEATURE_ACMP_HAS_C2_RRE_BIT) && (FSL_FEATURE_ACMP_HAS_C2_RRE_BIT == 1U)
+ tmp32 |= CMP_C2_RRE_MASK;
+#endif /* FSL_FEATURE_ACMP_HAS_C2_RRE_BIT */
+ base->C2 = tmp32;
+}
+
+/*!
+ * brief Defines the pre-set state of channels in round robin mode.
+ *
+ * Note: The pre-state has different circuit with get-round-robin-result in the SOC even though they are same bits.
+ * So get-round-robin-result can't return the same value as the value are set by pre-state.
+ *
+ * param base ACMP peripheral base address.
+ * param mask Mask of round robin channel index. Available range is channel0:0x01 to channel7:0x80.
+ */
+void ACMP_SetRoundRobinPreState(CMP_Type *base, uint32_t mask)
+{
+ /* CMPx_C2
+ * Set control bit. Avoid clearing status flags at the same time.
+ */
+ uint32_t tmp32 = (base->C2 & ~(CMP_C2_ACOn_MASK | CMP_C2_CHnF_MASK));
+
+ tmp32 |= (mask << CMP_C2_ACOn_SHIFT);
+ base->C2 = tmp32;
+}
+
+/*!
+ * brief Clears the channel input changed flags in round robin mode.
+ *
+ * param base ACMP peripheral base address.
+ * param mask Mask of channel index. Available range is channel0:0x01 to channel7:0x80.
+ */
+void ACMP_ClearRoundRobinStatusFlags(CMP_Type *base, uint32_t mask)
+{
+ /* CMPx_C2 */
+ uint32_t tmp32 = (base->C2 & (~CMP_C2_CHnF_MASK));
+
+ tmp32 |= (mask << CMP_C2_CH0F_SHIFT);
+ base->C2 = tmp32;
+}
+
+/*!
+ * brief Enables interrupts.
+ *
+ * param base ACMP peripheral base address.
+ * param mask Interrupts mask. See "_acmp_interrupt_enable".
+ */
+void ACMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint32_t tmp32;
+
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ * Set CMP interrupt enable flag.
+ */
+ tmp32 = base->C0 & ~CMP_C0_CFx_MASK; /* To protect the W1C flags. */
+ if ((uint32_t)kACMP_OutputRisingInterruptEnable == (mask & (uint32_t)kACMP_OutputRisingInterruptEnable))
+ {
+ tmp32 = ((tmp32 | CMP_C0_IER_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ if ((uint32_t)kACMP_OutputFallingInterruptEnable == (mask & (uint32_t)kACMP_OutputFallingInterruptEnable))
+ {
+ tmp32 = ((tmp32 | CMP_C0_IEF_MASK) & ~CMP_C0_CFx_MASK);
+ }
+ base->C0 = tmp32;
+
+ /* CMPx_C2
+ * Set round robin interrupt enable flag.
+ */
+ if ((uint32_t)kACMP_RoundRobinInterruptEnable == (mask & (uint32_t)kACMP_RoundRobinInterruptEnable))
+ {
+ tmp32 = base->C2;
+ /* Set control bit. Avoid clearing status flags at the same time. */
+ tmp32 = ((tmp32 | CMP_C2_RRIE_MASK) & ~CMP_C2_CHnF_MASK);
+ base->C2 = tmp32;
+ }
+}
+
+/*!
+ * brief Disables interrupts.
+ *
+ * param base ACMP peripheral base address.
+ * param mask Interrupts mask. See "_acmp_interrupt_enable".
+ */
+void ACMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint32_t tmp32;
+
+ /* CMPx_C0
+ * Set control bit. Avoid clearing status flags at the same time.
+ * Clear CMP interrupt enable flag.
+ */
+ tmp32 = base->C0;
+ if ((uint32_t)kACMP_OutputRisingInterruptEnable == (mask & (uint32_t)kACMP_OutputRisingInterruptEnable))
+ {
+ tmp32 &= ~(CMP_C0_IER_MASK | CMP_C0_CFx_MASK);
+ }
+ if ((uint32_t)kACMP_OutputFallingInterruptEnable == (mask & (uint32_t)kACMP_OutputFallingInterruptEnable))
+ {
+ tmp32 &= ~(CMP_C0_IEF_MASK | CMP_C0_CFx_MASK);
+ }
+ base->C0 = tmp32;
+
+ /* CMPx_C2
+ * Clear round robin interrupt enable flag.
+ */
+ if ((uint32_t)kACMP_RoundRobinInterruptEnable == (mask & (uint32_t)kACMP_RoundRobinInterruptEnable))
+ {
+ tmp32 = base->C2;
+ /* Set control bit. Avoid clearing status flags at the same time. */
+ tmp32 &= ~(CMP_C2_RRIE_MASK | CMP_C2_CHnF_MASK);
+ base->C2 = tmp32;
+ }
+}
+
+/*!
+ * brief Gets status flags.
+ *
+ * param base ACMP peripheral base address.
+ * return Status flags asserted mask. See "_acmp_status_flags".
+ */
+uint32_t ACMP_GetStatusFlags(CMP_Type *base)
+{
+ uint32_t status = 0U;
+ uint32_t tmp32 = base->C0;
+
+ /* CMPx_C0
+ * Check if each flag is set.
+ */
+ if (CMP_C0_CFR_MASK == (tmp32 & CMP_C0_CFR_MASK))
+ {
+ status |= (uint32_t)kACMP_OutputRisingEventFlag;
+ }
+ if (CMP_C0_CFF_MASK == (tmp32 & CMP_C0_CFF_MASK))
+ {
+ status |= (uint32_t)kACMP_OutputFallingEventFlag;
+ }
+ if (CMP_C0_COUT_MASK == (tmp32 & CMP_C0_COUT_MASK))
+ {
+ status |= (uint32_t)kACMP_OutputAssertEventFlag;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Clears status flags.
+ *
+ * param base ACMP peripheral base address.
+ * param mask Status flags mask. See "_acmp_status_flags".
+ */
+void ACMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
+{
+ /* CMPx_C0 */
+ uint32_t tmp32 = (base->C0 & (~(CMP_C0_CFR_MASK | CMP_C0_CFF_MASK)));
+
+ /* Clear flag according to mask. */
+ if ((uint32_t)kACMP_OutputRisingEventFlag == (mask & (uint32_t)kACMP_OutputRisingEventFlag))
+ {
+ tmp32 |= CMP_C0_CFR_MASK;
+ }
+ if ((uint32_t)kACMP_OutputFallingEventFlag == (mask & (uint32_t)kACMP_OutputFallingEventFlag))
+ {
+ tmp32 |= CMP_C0_CFF_MASK;
+ }
+ base->C0 = tmp32;
+}
+
+#if defined(FSL_FEATURE_ACMP_HAS_C3_REG) && (FSL_FEATURE_ACMP_HAS_C3_REG == 1U)
+/*!
+ * brief Configure the discrete mode.
+ *
+ * Configure the discrete mode when supporting 3V domain with 1.8V core.
+ *
+ * param base ACMP peripheral base address.
+ * param config Pointer to configuration structure. See "acmp_discrete_mode_config_t".
+ */
+void ACMP_SetDiscreteModeConfig(CMP_Type *base, const acmp_discrete_mode_config_t *config)
+{
+ uint32_t tmp32 = 0U;
+
+ if (!config->enablePositiveChannelDiscreteMode)
+ {
+ tmp32 |= CMP_C3_PCHCTEN_MASK;
+ }
+ if (!config->enableNegativeChannelDiscreteMode)
+ {
+ tmp32 |= CMP_C3_NCHCTEN_MASK;
+ }
+ if (config->enableResistorDivider)
+ {
+ tmp32 |= CMP_C3_RDIVE_MASK;
+ }
+
+ tmp32 |= CMP_C3_DMCS(config->clockSource) /* Select the clock. */
+ | CMP_C3_ACSAT(config->sampleTime) /* Sample time period. */
+ | CMP_C3_ACPH1TC(config->phase1Time) /* Phase 1 sample time. */
+ | CMP_C3_ACPH2TC(config->phase2Time); /* Phase 2 sample time. */
+
+ base->C3 = tmp32;
+}
+
+/*!
+ * brief Get the default configuration for discrete mode setting.
+ *
+ * param config Pointer to configuration structure to be restored with the setting values.
+ */
+void ACMP_GetDefaultDiscreteModeConfig(acmp_discrete_mode_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enablePositiveChannelDiscreteMode = false;
+ config->enableNegativeChannelDiscreteMode = false;
+ config->enableResistorDivider = false;
+ config->clockSource = kACMP_DiscreteClockSlow;
+ config->sampleTime = kACMP_DiscreteSampleTimeAs1T;
+ config->phase1Time = kACMP_DiscretePhaseTimeAlt0;
+ config->phase2Time = kACMP_DiscretePhaseTimeAlt0;
+}
+
+#endif /* FSL_FEATURE_ACMP_HAS_C3_REG */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.h b/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.h
new file mode 100644
index 0000000000..d24051de9a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/acmp/fsl_acmp.h
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ACMP_H_
+#define _FSL_ACMP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup acmp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief ACMP driver version 2.0.6. */
+#define FSL_ACMP_DRIVER_VERSION (MAKE_VERSION(2U, 0U, 6U))
+/*@}*/
+
+/*! @brief The mask of status flags cleared by writing 1. */
+#define CMP_C0_CFx_MASK (CMP_C0_CFR_MASK | CMP_C0_CFF_MASK)
+#define CMP_C1_CHNn_MASK 0xFF0000U /* C1_CHN0 - C1_CHN7. */
+#define CMP_C2_CHnF_MASK 0xFF0000U /* C2_CH0F - C2_CH7F. */
+
+/*! @brief Interrupt enable/disable mask. */
+enum _acmp_interrupt_enable
+{
+ kACMP_OutputRisingInterruptEnable = (1U << 0U), /*!< Enable the interrupt when comparator outputs rising. */
+ kACMP_OutputFallingInterruptEnable = (1U << 1U), /*!< Enable the interrupt when comparator outputs falling. */
+ kACMP_RoundRobinInterruptEnable = (1U << 2U), /*!< Enable the Round-Robin interrupt. */
+};
+
+/*! @brief Status flag mask. */
+enum _acmp_status_flags
+{
+ kACMP_OutputRisingEventFlag = CMP_C0_CFR_MASK, /*!< Rising-edge on compare output has occurred. */
+ kACMP_OutputFallingEventFlag = CMP_C0_CFF_MASK, /*!< Falling-edge on compare output has occurred. */
+ kACMP_OutputAssertEventFlag = CMP_C0_COUT_MASK, /*!< Return the current value of the analog comparator output. */
+};
+
+#if defined(FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT) && (FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT == 1U)
+/*!
+ * @brief Comparator hard block offset control.
+ *
+ * If OFFSET level is 1, then there is no hysteresis in the case of positive port input crossing negative port
+ * input in the positive direction (or negative port input crossing positive port input in the negative direction).
+ * Hysteresis still exists for positive port input crossing negative port input in the falling direction.
+ * If OFFSET level is 0, then the hysteresis selected by acmp_hysteresis_mode_t is valid for both directions.
+ */
+typedef enum _acmp_offset_mode
+{
+ kACMP_OffsetLevel0 = 0U, /*!< The comparator hard block output has level 0 offset internally. */
+ kACMP_OffsetLevel1 = 1U, /*!< The comparator hard block output has level 1 offset internally. */
+} acmp_offset_mode_t;
+#endif /* FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT */
+
+/*!
+ * @brief Comparator hard block hysteresis control.
+ *
+ * See chip data sheet to get the actual hysteresis value with each level.
+ */
+typedef enum _acmp_hysteresis_mode
+{
+ kACMP_HysteresisLevel0 = 0U, /*!< Offset is level 0 and Hysteresis is level 0. */
+ kACMP_HysteresisLevel1 = 1U, /*!< Offset is level 0 and Hysteresis is level 1. */
+ kACMP_HysteresisLevel2 = 2U, /*!< Offset is level 0 and Hysteresis is level 2. */
+ kACMP_HysteresisLevel3 = 3U, /*!< Offset is level 0 and Hysteresis is level 3. */
+} acmp_hysteresis_mode_t;
+
+/*! @brief CMP Voltage Reference source. */
+typedef enum _acmp_reference_voltage_source
+{
+ kACMP_VrefSourceVin1 = 0U, /*!< Vin1 is selected as resistor ladder network supply reference Vin. */
+ kACMP_VrefSourceVin2 = 1U, /*!< Vin2 is selected as resistor ladder network supply reference Vin. */
+} acmp_reference_voltage_source_t;
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT) && (FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT == 1U)
+/*! @brief Port input source. */
+typedef enum _acmp_port_input
+{
+ kACMP_PortInputFromDAC = 0U, /*!< Port input from the 8-bit DAC output. */
+ kACMP_PortInputFromMux = 1U, /*!< Port input from the analog 8-1 mux. */
+} acmp_port_input_t;
+#endif /* FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT */
+
+/*! @brief Fixed mux port. */
+typedef enum _acmp_fixed_port
+{
+ kACMP_FixedPlusPort = 0U, /*!< Only the inputs to the Minus port are swept in each round. */
+ kACMP_FixedMinusPort = 1U, /*!< Only the inputs to the Plus port are swept in each round. */
+} acmp_fixed_port_t;
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT == 1U)
+/*! @brief Internal DAC's work mode. */
+typedef enum _acmp_dac_work_mode
+{
+ kACMP_DACWorkLowSpeedMode = 0U, /*!< DAC is selected to work in low speed and low power mode. */
+ kACMP_DACWorkHighSpeedMode = 1U, /*!< DAC is selected to work in high speed high power mode. */
+} acmp_dac_work_mode_t;
+#endif /* FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT */
+
+/*! @brief Configuration for ACMP. */
+typedef struct _acmp_config
+{
+#if defined(FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT) && (FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT == 1U)
+ acmp_offset_mode_t offsetMode; /*!< Offset mode. */
+#endif /* FSL_FEATURE_ACMP_HAS_C0_OFFSET_BIT */
+ acmp_hysteresis_mode_t hysteresisMode; /*!< Hysteresis mode. */
+ bool enableHighSpeed; /*!< Enable High Speed (HS) comparison mode. */
+ bool enableInvertOutput; /*!< Enable inverted comparator output. */
+ bool useUnfilteredOutput; /*!< Set compare output(COUT) to equal COUTA(true) or COUT(false). */
+ bool enablePinOut; /*!< The comparator output is available on the associated pin. */
+} acmp_config_t;
+
+/*!
+ * @brief Configuration for channel.
+ *
+ * The comparator's port can be input from channel mux or DAC. If port input is from channel mux, detailed channel
+ * number for the mux should be configured.
+ */
+typedef struct _acmp_channel_config
+{
+#if defined(FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT) && (FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT == 1U)
+ acmp_port_input_t positivePortInput; /*!< Input source of the comparator's positive port. */
+#endif /* FSL_FEATURE_ACMP_HAS_C1_INPSEL_BIT */
+ uint32_t plusMuxInput; /*!< Plus mux input channel(0~7). */
+#if defined(FSL_FEATURE_ACMP_HAS_C1_INNSEL_BIT) && (FSL_FEATURE_ACMP_HAS_C1_INNSEL_BIT == 1U)
+ acmp_port_input_t negativePortInput; /*!< Input source of the comparator's negative port. */
+#endif /* FSL_FEATURE_ACMP_HAS_C1_INNSEL_BIT */
+ uint32_t minusMuxInput; /*!< Minus mux input channel(0~7). */
+} acmp_channel_config_t;
+
+/*! @brief Configuration for filter. */
+typedef struct _acmp_filter_config
+{
+ bool enableSample; /*!< Using external SAMPLE as sampling clock input, or using divided bus clock. */
+ uint32_t filterCount; /*!< Filter Sample Count. Available range is 1-7, 0 would cause the filter disabled. */
+ uint32_t filterPeriod; /*!< Filter Sample Period. The divider to bus clock. Available range is 0-255. */
+} acmp_filter_config_t;
+
+/*! @brief Configuration for DAC. */
+typedef struct _acmp_dac_config
+{
+ acmp_reference_voltage_source_t referenceVoltageSource; /*!< Supply voltage reference source. */
+ uint32_t DACValue; /*!< Value for DAC Output Voltage. Available range is 0-255. */
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT == 1U)
+ bool enableOutput; /*!< Enable the DAC output. */
+#endif /* FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT */
+
+#if defined(FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT == 1U)
+ acmp_dac_work_mode_t workMode;
+#endif /* FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT */
+} acmp_dac_config_t;
+
+/*! @brief Configuration for round robin mode. */
+typedef struct _acmp_round_robin_config
+{
+ acmp_fixed_port_t fixedPort; /*!< Fixed mux port. */
+ uint32_t fixedChannelNumber; /*!< Indicates which channel is fixed in the fixed mux port. */
+ uint32_t checkerChannelMask; /*!< Mask of checker channel index. Available range is channel0:0x01 to channel7:0x80
+ for round-robin checker. */
+ uint32_t sampleClockCount; /*!< Specifies how many round-robin clock cycles(0~3) later the sample takes place. */
+ uint32_t delayModulus; /*!< Comparator and DAC initialization delay modulus. */
+} acmp_round_robin_config_t;
+
+#if defined(FSL_FEATURE_ACMP_HAS_C3_REG) && (FSL_FEATURE_ACMP_HAS_C3_REG == 1U)
+
+/*! @brief Discrete mode clock selection. */
+typedef enum _acmp_discrete_clock_source
+{
+ kACMP_DiscreteClockSlow = 0U, /*!< Slow clock (32kHz) is used as the discrete mode clock. */
+ kACMP_DiscreteClockFast = 1U, /*!< Fast clock (16-20MHz) is used as the discrete mode clock. */
+} acmp_discrete_clock_source_t;
+
+/*!
+ * @brief ACMP discrete sample selection.
+ * These values configures the analog comparator sampling timing (speicified by the discrete mode clock period T which
+ * is selected by #acmp_discrete_clock_source_t) in discrete mode.
+ */
+typedef enum _acmp_discrete_sample_time
+{
+ kACMP_DiscreteSampleTimeAs1T = 0U, /*!< The sampling time equals to 1xT. */
+ kACMP_DiscreteSampleTimeAs2T = 1U, /*!< The sampling time equals to 2xT. */
+ kACMP_DiscreteSampleTimeAs4T = 2U, /*!< The sampling time equals to 4xT. */
+ kACMP_DiscreteSampleTimeAs8T = 3U, /*!< The sampling time equals to 8xT. */
+ kACMP_DiscreteSampleTimeAs16T = 4U, /*!< The sampling time equals to 16xT. */
+ kACMP_DiscreteSampleTimeAs32T = 5U, /*!< The sampling time equals to 32xT. */
+ kACMP_DiscreteSampleTimeAs64T = 6U, /*!< The sampling time equals to 64xT. */
+ kACMP_DiscreteSampleTimeAs256T = 7U, /*!< The sampling time equals to 256xT. */
+} acmp_discrete_sample_time_t;
+
+/*!
+ * @brief ACMP discrete phase time selection.
+ * There are two phases for sampling input signals, phase 1 and phase 2.
+ */
+typedef enum _acmp_discrete_phase_time
+{
+ kACMP_DiscretePhaseTimeAlt0 = 0U, /*!< The phase x active in one sampling selection 0. */
+ kACMP_DiscretePhaseTimeAlt1 = 1U, /*!< The phase x active in one sampling selection 1. */
+ kACMP_DiscretePhaseTimeAlt2 = 2U, /*!< The phase x active in one sampling selection 2. */
+ kACMP_DiscretePhaseTimeAlt3 = 3U, /*!< The phase x active in one sampling selection 3. */
+ kACMP_DiscretePhaseTimeAlt4 = 4U, /*!< The phase x active in one sampling selection 4. */
+ kACMP_DiscretePhaseTimeAlt5 = 5U, /*!< The phase x active in one sampling selection 5. */
+ kACMP_DiscretePhaseTimeAlt6 = 6U, /*!< The phase x active in one sampling selection 6. */
+ kACMP_DiscretePhaseTimeAlt7 = 7U, /*!< The phase x active in one sampling selection 7. */
+} acmp_discrete_phase_time_t;
+
+/*! @brief Configuration for discrete mode. */
+typedef struct _acmp_discrete_mode_config
+{
+ bool enablePositiveChannelDiscreteMode; /*!< Positive Channel Continuous Mode Enable. By default, the continuous
+ mode is used. */
+ bool enableNegativeChannelDiscreteMode; /*!< Negative Channel Continuous Mode Enable. By default, the continuous
+ mode is used. */
+ bool enableResistorDivider; /*!< Resistor Divider Enable is used to enable the resistor divider for the inputs when
+ they come from 3v domain and their values are above 1.8v. */
+ acmp_discrete_clock_source_t clockSource; /*!< Select the clock source in order to generate the requiried timing for
+ comparator to work in discrete mode. */
+ acmp_discrete_sample_time_t sampleTime; /*!< Select the ACMP total sampling time period. */
+ acmp_discrete_phase_time_t phase1Time; /*!< Select the ACMP phase 1 sampling time. */
+ acmp_discrete_phase_time_t phase2Time; /*!< Select the ACMP phase 2 sampling time. */
+} acmp_discrete_mode_config_t;
+
+#endif /* FSL_FEATURE_ACMP_HAS_C3_REG */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the ACMP.
+ *
+ * The default configuration can be got by calling ACMP_GetDefaultConfig().
+ *
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to ACMP configuration structure.
+ */
+void ACMP_Init(CMP_Type *base, const acmp_config_t *config);
+
+/*!
+ * @brief Deinitializes the ACMP.
+ *
+ * @param base ACMP peripheral base address.
+ */
+void ACMP_Deinit(CMP_Type *base);
+
+/*!
+ * @brief Gets the default configuration for ACMP.
+ *
+ * This function initializes the user configuration structure to default value. The default value are:
+ *
+ * Example:
+ @code
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+ config->enableHysteresisBothDirections = false;
+ config->hysteresisMode = kACMP_hysteresisMode0;
+ @endcode
+ *
+ * @param config Pointer to ACMP configuration structure.
+ */
+void ACMP_GetDefaultConfig(acmp_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Basic Operations
+ * @{
+ */
+
+/*!
+ * @brief Enables or disables the ACMP.
+ *
+ * @param base ACMP peripheral base address.
+ * @param enable True to enable the ACMP.
+ */
+void ACMP_Enable(CMP_Type *base, bool enable);
+
+#if defined(FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT) && (FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT == 1U)
+/*!
+ * @brief Enables the link from CMP to DAC enable.
+ *
+ * When this bit is set, the DAC enable/disable is controlled by the bit CMP_C0[EN] instead of CMP_C1[DACEN].
+ *
+ * @param base ACMP peripheral base address.
+ * @param enable Enable the feature or not.
+ */
+void ACMP_EnableLinkToDAC(CMP_Type *base, bool enable);
+#endif /* FSL_FEATURE_ACMP_HAS_C0_LINKEN_BIT */
+
+/*!
+ * @brief Sets the channel configuration.
+ *
+ * Note that the plus/minus mux's setting is only valid when the positive/negative port's input isn't from DAC but
+ * from channel mux.
+ *
+ * Example:
+ @code
+ acmp_channel_config_t configStruct = {0};
+ configStruct.positivePortInput = kACMP_PortInputFromDAC;
+ configStruct.negativePortInput = kACMP_PortInputFromMux;
+ configStruct.minusMuxInput = 1U;
+ ACMP_SetChannelConfig(CMP0, &configStruct);
+ @endcode
+ *
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to channel configuration structure.
+ */
+void ACMP_SetChannelConfig(CMP_Type *base, const acmp_channel_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Advanced Operations
+ * @{
+ */
+
+/*!
+ * @brief Enables or disables DMA.
+ *
+ * @param base ACMP peripheral base address.
+ * @param enable True to enable DMA.
+ */
+void ACMP_EnableDMA(CMP_Type *base, bool enable);
+
+/*!
+ * @brief Enables or disables window mode.
+ *
+ * @param base ACMP peripheral base address.
+ * @param enable True to enable window mode.
+ */
+void ACMP_EnableWindowMode(CMP_Type *base, bool enable);
+
+/*!
+ * @brief Configures the filter.
+ *
+ * The filter can be enabled when the filter count is bigger than 1, the filter period is greater than 0 and the sample
+ * clock is from divided bus clock or the filter is bigger than 1 and the sample clock is from external clock. Detailed
+ * usage can be got from the reference manual.
+ *
+ * Example:
+ @code
+ acmp_filter_config_t configStruct = {0};
+ configStruct.filterCount = 5U;
+ configStruct.filterPeriod = 200U;
+ configStruct.enableSample = false;
+ ACMP_SetFilterConfig(CMP0, &configStruct);
+ @endcode
+ *
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to filter configuration structure.
+ */
+void ACMP_SetFilterConfig(CMP_Type *base, const acmp_filter_config_t *config);
+
+/*!
+ * @brief Configures the internal DAC.
+ *
+ * Example:
+ @code
+ acmp_dac_config_t configStruct = {0};
+ configStruct.referenceVoltageSource = kACMP_VrefSourceVin1;
+ configStruct.DACValue = 20U;
+ configStruct.enableOutput = false;
+ configStruct.workMode = kACMP_DACWorkLowSpeedMode;
+ ACMP_SetDACConfig(CMP0, &configStruct);
+ @endcode
+ *
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to DAC configuration structure. "NULL" is for disabling the feature.
+ */
+void ACMP_SetDACConfig(CMP_Type *base, const acmp_dac_config_t *config);
+
+/*!
+ * @brief Configures the round robin mode.
+ *
+ * Example:
+ @code
+ acmp_round_robin_config_t configStruct = {0};
+ configStruct.fixedPort = kACMP_FixedPlusPort;
+ configStruct.fixedChannelNumber = 3U;
+ configStruct.checkerChannelMask = 0xF7U;
+ configStruct.sampleClockCount = 0U;
+ configStruct.delayModulus = 0U;
+ ACMP_SetRoundRobinConfig(CMP0, &configStruct);
+ @endcode
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to round robin mode configuration structure. "NULL" is for disabling the feature.
+ */
+void ACMP_SetRoundRobinConfig(CMP_Type *base, const acmp_round_robin_config_t *config);
+
+/*!
+ * @brief Defines the pre-set state of channels in round robin mode.
+ *
+ * Note: The pre-state has different circuit with get-round-robin-result in the SOC even though they are same bits.
+ * So get-round-robin-result can't return the same value as the value are set by pre-state.
+ *
+ * @param base ACMP peripheral base address.
+ * @param mask Mask of round robin channel index. Available range is channel0:0x01 to channel7:0x80.
+ */
+void ACMP_SetRoundRobinPreState(CMP_Type *base, uint32_t mask);
+
+/*!
+ * @brief Gets the channel input changed flags in round robin mode.
+ *
+ * @param base ACMP peripheral base address.
+ * @return Mask of channel input changed asserted flags. Available range is channel0:0x01 to channel7:0x80.
+ */
+static inline uint32_t ACMP_GetRoundRobinStatusFlags(CMP_Type *base)
+{
+ return (((base->C2) & CMP_C2_CHnF_MASK) >> CMP_C2_CH0F_SHIFT);
+}
+
+/*!
+ * @brief Clears the channel input changed flags in round robin mode.
+ *
+ * @param base ACMP peripheral base address.
+ * @param mask Mask of channel index. Available range is channel0:0x01 to channel7:0x80.
+ */
+void ACMP_ClearRoundRobinStatusFlags(CMP_Type *base, uint32_t mask);
+
+/*!
+ * @brief Gets the round robin result.
+ *
+ * Note that the set-pre-state has different circuit with get-round-robin-result in the SOC even though they are same
+ * bits. So ACMP_GetRoundRobinResult() can't return the same value as the value are set by ACMP_SetRoundRobinPreState.
+
+ * @param base ACMP peripheral base address.
+ * @return Mask of round robin channel result. Available range is channel0:0x01 to channel7:0x80.
+ */
+static inline uint32_t ACMP_GetRoundRobinResult(CMP_Type *base)
+{
+ return ((base->C2 & CMP_C2_ACOn_MASK) >> CMP_C2_ACOn_SHIFT);
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables interrupts.
+ *
+ * @param base ACMP peripheral base address.
+ * @param mask Interrupts mask. See "_acmp_interrupt_enable".
+ */
+void ACMP_EnableInterrupts(CMP_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables interrupts.
+ *
+ * @param base ACMP peripheral base address.
+ * @param mask Interrupts mask. See "_acmp_interrupt_enable".
+ */
+void ACMP_DisableInterrupts(CMP_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets status flags.
+ *
+ * @param base ACMP peripheral base address.
+ * @return Status flags asserted mask. See "_acmp_status_flags".
+ */
+uint32_t ACMP_GetStatusFlags(CMP_Type *base);
+
+/*!
+ * @brief Clears status flags.
+ *
+ * @param base ACMP peripheral base address.
+ * @param mask Status flags mask. See "_acmp_status_flags".
+ */
+void ACMP_ClearStatusFlags(CMP_Type *base, uint32_t mask);
+
+/* @} */
+
+#if defined(FSL_FEATURE_ACMP_HAS_C3_REG) && (FSL_FEATURE_ACMP_HAS_C3_REG == 1U)
+/*!
+ * @name Discrete mode
+ * @{
+ */
+
+/*!
+ * @brief Configure the discrete mode.
+ *
+ * Configure the discrete mode when supporting 3V domain with 1.8V core.
+ *
+ * @param base ACMP peripheral base address.
+ * @param config Pointer to configuration structure. See "acmp_discrete_mode_config_t".
+ */
+void ACMP_SetDiscreteModeConfig(CMP_Type *base, const acmp_discrete_mode_config_t *config);
+
+/*!
+ * @brief Get the default configuration for discrete mode setting.
+ *
+ * @param config Pointer to configuration structure to be restored with the setting values.
+ */
+void ACMP_GetDefaultDiscreteModeConfig(acmp_discrete_mode_config_t *config);
+
+/* @} */
+#endif /* FSL_FEATURE_ACMP_HAS_C3_REG */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_ACMP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.c b/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.c
new file mode 100644
index 0000000000..909a6f3b50
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_adc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.adc_12b1msps_sar"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for ADC module.
+ *
+ * @param base ADC peripheral base address
+ */
+static uint32_t ADC_GetInstance(ADC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ADC bases for each instance. */
+static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC clocks for each instance. */
+static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ADC_GetInstance(ADC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_adcBases); instance++)
+ {
+ if (s_adcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_adcBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialize the ADC module.
+ *
+ * param base ADC peripheral base address.
+ * param config Pointer to "adc_config_t" structure.
+ */
+void ADC_Init(ADC_Type *base, const adc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* ADCx_CFG */
+ tmp32 = base->CFG & (ADC_CFG_AVGS_MASK | ADC_CFG_ADTRG_MASK); /* Reserve AVGS and ADTRG bits. */
+ tmp32 |= ADC_CFG_REFSEL(config->referenceVoltageSource) | ADC_CFG_ADSTS(config->samplePeriodMode) |
+ ADC_CFG_ADICLK(config->clockSource) | ADC_CFG_ADIV(config->clockDriver) | ADC_CFG_MODE(config->resolution);
+ if (config->enableOverWrite)
+ {
+ tmp32 |= ADC_CFG_OVWREN_MASK;
+ }
+ if (config->enableLongSample)
+ {
+ tmp32 |= ADC_CFG_ADLSMP_MASK;
+ }
+ if (config->enableLowPower)
+ {
+ tmp32 |= ADC_CFG_ADLPC_MASK;
+ }
+ if (config->enableHighSpeed)
+ {
+ tmp32 |= ADC_CFG_ADHSC_MASK;
+ }
+ base->CFG = tmp32;
+
+ /* ADCx_GC */
+ tmp32 = base->GC & ~(ADC_GC_ADCO_MASK | ADC_GC_ADACKEN_MASK);
+ if (config->enableContinuousConversion)
+ {
+ tmp32 |= ADC_GC_ADCO_MASK;
+ }
+ if (config->enableAsynchronousClockOutput)
+ {
+ tmp32 |= ADC_GC_ADACKEN_MASK;
+ }
+ base->GC = tmp32;
+}
+
+/*!
+ * brief De-initializes the ADC module.
+ *
+ * param base ADC peripheral base address.
+ */
+void ADC_Deinit(ADC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets an available pre-defined settings for the converter's configuration.
+ *
+ * This function initializes the converter configuration structure with available settings. The default values are:
+ * code
+ * config->enableAsynchronousClockOutput = true;
+ * config->enableOverWrite = false;
+ * config->enableContinuousConversion = false;
+ * config->enableHighSpeed = false;
+ * config->enableLowPower = false;
+ * config->enableLongSample = false;
+ * config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;
+ * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
+ * config->clockSource = kADC_ClockSourceAD;
+ * config->clockDriver = kADC_ClockDriver1;
+ * config->resolution = kADC_Resolution12Bit;
+ * endcode
+ * param base ADC peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ADC_GetDefaultConfig(adc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableAsynchronousClockOutput = true;
+ config->enableOverWrite = false;
+ config->enableContinuousConversion = false;
+ config->enableHighSpeed = false;
+ config->enableLowPower = false;
+ config->enableLongSample = false;
+ config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;
+ config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
+ config->clockSource = kADC_ClockSourceAD;
+ config->clockDriver = kADC_ClockDriver1;
+ config->resolution = kADC_Resolution12Bit;
+}
+
+/*!
+ * brief Configures the conversion channel.
+ *
+ * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
+ * configures the channel while the external trigger source helps to trigger the conversion.
+ *
+ * Note that the "Channel Group" has a detailed description.
+ * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
+ * group of status and control registers, one for each conversion. The channel group parameter indicates which group of
+ * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B
+ * registers. The
+ * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of
+ * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
+ * hardware
+ * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for
+ * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual
+ * about the
+ * number of SC1n registers (channel groups) specific to this device. None of the channel groups 1 or greater are used
+ * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
+ * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
+ * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
+ * conversion aborts the current conversion.
+ *
+ * param base ADC peripheral base address.
+ * param channelGroup Channel group index.
+ * param config Pointer to the "adc_channel_config_t" structure for the conversion channel.
+ */
+void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config)
+{
+ assert(NULL != config);
+ assert(channelGroup < (uint32_t)FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT);
+
+ uint32_t tmp32;
+
+ tmp32 = ADC_HC_ADCH(config->channelNumber);
+ if (config->enableInterruptOnConversionCompleted)
+ {
+ tmp32 |= ADC_HC_AIEN_MASK;
+ }
+ base->HC[channelGroup] = tmp32;
+}
+
+/*
+ *To complete calibration, the user must follow the below procedure:
+ * 1. Configure ADC_CFG with actual operating values for maximum accuracy.
+ * 2. Configure the ADC_GC values along with CAL bit.
+ * 3. Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC.
+ * 4. When CAL bit becomes '0' then check the CALF status and COCO[0] bit status.
+ */
+/*!
+ * brief Automates the hardware calibration.
+ *
+ * This auto calibration helps to adjust the plus/minus side gain automatically.
+ * Execute the calibration before using the converter. Note that the software trigger should be used
+ * during calibration.
+ *
+ * param base ADC peripheral base address.
+ *
+ * return Execution status.
+ * retval kStatus_Success Calibration is done successfully.
+ * retval kStatus_Fail Calibration has failed.
+ */
+status_t ADC_DoAutoCalibration(ADC_Type *base)
+{
+ status_t status = kStatus_Success;
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
+ bool bHWTrigger = false;
+
+ /* The calibration would be failed when in hardwar mode.
+ * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
+ if (0U != (ADC_CFG_ADTRG_MASK & base->CFG))
+ {
+ bHWTrigger = true;
+ ADC_EnableHardwareTrigger(base, false);
+ }
+#endif
+
+ /* Clear the CALF and launch the calibration. */
+ base->GS = ADC_GS_CALF_MASK; /* Clear the CALF. */
+ base->GC |= ADC_GC_CAL_MASK; /* Launch the calibration. */
+
+ /* Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC. */
+ while (0U != (base->GC & ADC_GC_CAL_MASK))
+ {
+ /* Check the CALF when the calibration is active. */
+ if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag))
+ {
+ status = kStatus_Fail;
+ break;
+ }
+ }
+
+ /* When CAL bit becomes '0' then check the CALF status and COCO[0] bit status. */
+ if (0U == ADC_GetChannelStatusFlags(base, 0U)) /* Check the COCO[0] bit status. */
+ {
+ status = kStatus_Fail;
+ }
+ if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag)) /* Check the CALF status. */
+ {
+ status = kStatus_Fail;
+ }
+
+ /* Clear conversion done flag. */
+ (void)ADC_GetChannelConversionValue(base, 0U);
+
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
+ /* Restore original trigger mode. */
+ if (true == bHWTrigger)
+ {
+ ADC_EnableHardwareTrigger(base, true);
+ }
+#endif
+
+ return status;
+}
+
+/*!
+ * brief Set user defined offset.
+ *
+ * param base ADC peripheral base address.
+ * param config Pointer to "adc_offest_config_t" structure.
+ */
+void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ tmp32 = ADC_OFS_OFS(config->offsetValue);
+ if (config->enableSigned)
+ {
+ tmp32 |= ADC_OFS_SIGN_MASK;
+ }
+ base->OFS = tmp32;
+}
+
+/*!
+ * brief Configures the hardware compare mode.
+ *
+ * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
+ * result
+ * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate
+ * reference
+ * manual for more information.
+ *
+ * param base ADC peripheral base address.
+ * param Pointer to "adc_hardware_compare_config_t" structure.
+ *
+ */
+void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config)
+{
+ uint32_t tmp32;
+
+ tmp32 = base->GC & ~(ADC_GC_ACFE_MASK | ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK);
+ if (NULL == config) /* Pass "NULL" to disable the feature. */
+ {
+ base->GC = tmp32;
+ return;
+ }
+ /* Enable the feature. */
+ tmp32 |= ADC_GC_ACFE_MASK;
+
+ /* Select the hardware compare working mode. */
+ switch (config->hardwareCompareMode)
+ {
+ case kADC_HardwareCompareMode0:
+ break;
+ case kADC_HardwareCompareMode1:
+ tmp32 |= ADC_GC_ACFGT_MASK;
+ break;
+ case kADC_HardwareCompareMode2:
+ tmp32 |= ADC_GC_ACREN_MASK;
+ break;
+ case kADC_HardwareCompareMode3:
+ tmp32 |= ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->GC = tmp32;
+
+ /* Load the compare values. */
+ tmp32 = ADC_CV_CV1(config->value1) | ADC_CV_CV2(config->value2);
+ base->CV = tmp32;
+}
+
+/*!
+ * brief Configures the hardware average mode.
+ *
+ * The hardware average mode provides a way to process the conversion result automatically by using hardware. The
+ * multiple
+ * conversion results are accumulated and averaged internally making them easier to read.
+ *
+ * param base ADC peripheral base address.
+ * param mode Setting the hardware average mode. See "adc_hardware_average_mode_t".
+ */
+void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode)
+{
+ uint32_t tmp32;
+
+ if (mode == kADC_HardwareAverageDiasable)
+ {
+ base->GC &= ~ADC_GC_AVGE_MASK;
+ }
+ else
+ {
+ tmp32 = base->CFG & ~ADC_CFG_AVGS_MASK;
+ tmp32 |= ADC_CFG_AVGS(mode);
+ base->CFG = tmp32;
+ base->GC |= ADC_GC_AVGE_MASK; /* Enable the hardware compare. */
+ }
+}
+
+/*!
+ * brief Clears the converter's status falgs.
+ *
+ * param base ADC peripheral base address.
+ * param mask Mask value for the cleared flags. See "adc_status_flags_t".
+ */
+void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask)
+{
+ uint32_t tmp32 = 0;
+
+ if (0U != (mask & (uint32_t)kADC_CalibrationFailedFlag))
+ {
+ tmp32 |= ADC_GS_CALF_MASK;
+ }
+ if (0U != (mask & (uint32_t)kADC_ConversionActiveFlag))
+ {
+ tmp32 |= ADC_GS_ADACT_MASK;
+ }
+ base->GS = tmp32;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.h b/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.h
new file mode 100644
index 0000000000..c033ba6349
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/adc_12b1msps_sar/fsl_adc.h
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ADC_H_
+#define _FSL_ADC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup adc_12b1msps_sar
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief ADC driver version */
+#define FSL_ADC_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) /*!< Version 2.0.4. */
+
+/*!
+ * @brief Converter's status flags.
+ */
+typedef enum _adc_status_flags
+{
+ kADC_ConversionActiveFlag = ADC_GS_ADACT_MASK, /*!< Conversion is active,not support w1c. */
+ kADC_CalibrationFailedFlag = ADC_GS_CALF_MASK, /*!< Calibration is failed,support w1c. */
+ kADC_AsynchronousWakeupInterruptFlag =
+ ADC_GS_AWKST_MASK, /*!< Asynchronous wakeup interrupt occurred, support w1c. */
+} adc_status_flags_t;
+
+/*!
+ * @brief Reference voltage source.
+ */
+typedef enum _adc_reference_voltage_source
+{
+ kADC_ReferenceVoltageSourceAlt0 = 0U, /*!< For external pins pair of VrefH and VrefL. */
+} adc_reference_voltage_source_t;
+
+/*!
+ * @brief Sample time duration.
+ */
+typedef enum _adc_sample_period_mode
+{
+ /* This group of enumeration is for internal use which is related to register setting. */
+ kADC_SamplePeriod2or12Clocks = 0U, /*!< Long sample 12 clocks or short sample 2 clocks. */
+ kADC_SamplePeriod4or16Clocks = 1U, /*!< Long sample 16 clocks or short sample 4 clocks. */
+ kADC_SamplePeriod6or20Clocks = 2U, /*!< Long sample 20 clocks or short sample 6 clocks. */
+ kADC_SamplePeriod8or24Clocks = 3U, /*!< Long sample 24 clocks or short sample 8 clocks. */
+ /* This group of enumeration is for a public user. */
+ /* For long sample mode. */
+ kADC_SamplePeriodLong12Clcoks = kADC_SamplePeriod2or12Clocks, /*!< Long sample 12 clocks. */
+ kADC_SamplePeriodLong16Clcoks = kADC_SamplePeriod4or16Clocks, /*!< Long sample 16 clocks. */
+ kADC_SamplePeriodLong20Clcoks = kADC_SamplePeriod6or20Clocks, /*!< Long sample 20 clocks. */
+ kADC_SamplePeriodLong24Clcoks = kADC_SamplePeriod8or24Clocks, /*!< Long sample 24 clocks. */
+ /* For short sample mode. */
+ kADC_SamplePeriodShort2Clocks = kADC_SamplePeriod2or12Clocks, /*!< Short sample 2 clocks. */
+ kADC_SamplePeriodShort4Clocks = kADC_SamplePeriod4or16Clocks, /*!< Short sample 4 clocks. */
+ kADC_SamplePeriodShort6Clocks = kADC_SamplePeriod6or20Clocks, /*!< Short sample 6 clocks. */
+ kADC_SamplePeriodShort8Clocks = kADC_SamplePeriod8or24Clocks, /*!< Short sample 8 clocks. */
+} adc_sample_period_mode_t;
+
+/*!
+ * @brief Clock source.
+ */
+typedef enum _adc_clock_source
+{
+ kADC_ClockSourceIPG = 0U, /*!< Select IPG clock to generate ADCK. */
+ kADC_ClockSourceIPGDiv2 = 1U, /*!< Select IPG clock divided by 2 to generate ADCK. */
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_ALTCLK_REMOVE) && FSL_FEATURE_ADC_SUPPORT_ALTCLK_REMOVE)
+ kADC_ClockSourceALT = 2U, /*!< Select alternate clock to generate ADCK. */
+#endif
+ kADC_ClockSourceAD = 3U, /*!< Select Asynchronous clock to generate ADCK. */
+} adc_clock_source_t;
+
+/*!
+ * @brief Clock divider for the converter.
+ */
+typedef enum _adc_clock_drvier
+{
+ kADC_ClockDriver1 = 0U, /*!< For divider 1 from the input clock to the module. */
+ kADC_ClockDriver2 = 1U, /*!< For divider 2 from the input clock to the module. */
+ kADC_ClockDriver4 = 2U, /*!< For divider 4 from the input clock to the module. */
+ kADC_ClockDriver8 = 3U, /*!< For divider 8 from the input clock to the module. */
+} adc_clock_driver_t;
+
+/*!
+ * @brief Converter's resolution.
+ */
+typedef enum _adc_resolution
+{
+ kADC_Resolution8Bit = 0U, /*!< Single End 8-bit resolution. */
+ kADC_Resolution10Bit = 1U, /*!< Single End 10-bit resolution. */
+ kADC_Resolution12Bit = 2U, /*!< Single End 12-bit resolution. */
+} adc_resolution_t;
+
+/*!
+ * @brief Converter hardware compare mode.
+ */
+typedef enum _adc_hardware_compare_mode
+{
+ kADC_HardwareCompareMode0 = 0U, /*!< Compare true if the result is less than the value1. */
+ kADC_HardwareCompareMode1 = 1U, /*!< Compare true if the result is greater than or equal to value1. */
+ kADC_HardwareCompareMode2 = 2U, /*!< Value1 <= Value2, compare true if the result is less than value1 Or
+ the result is Greater than value2.
+ Value1 > Value2, compare true if the result is less than value1 And the
+ result is greater than value2*/
+ kADC_HardwareCompareMode3 = 3U, /*!< Value1 <= Value2, compare true if the result is greater than or equal
+ to value1 And the result is less than or equal to value2.
+ Value1 > Value2, compare true if the result is greater than or equal to
+ value1 Or the result is less than or equal to value2. */
+} adc_hardware_compare_mode_t;
+
+/*!
+ * @brief Converter hardware average mode.
+ */
+typedef enum _adc_hardware_average_mode
+{
+ kADC_HardwareAverageCount4 = 0U, /*!< For hardware average with 4 samples. */
+ kADC_HardwareAverageCount8 = 1U, /*!< For hardware average with 8 samples. */
+ kADC_HardwareAverageCount16 = 2U, /*!< For hardware average with 16 samples. */
+ kADC_HardwareAverageCount32 = 3U, /*!< For hardware average with 32 samples. */
+ kADC_HardwareAverageDiasable = 4U, /*!< Disable the hardware average function. */
+} adc_hardware_average_mode_t;
+
+/*!
+ * @brief Converter configuration.
+ */
+typedef struct _adc_config
+{
+ bool enableOverWrite; /*!< Enable the overwriting. */
+ bool enableContinuousConversion; /*!< Enable the continuous conversion mode. */
+ bool enableHighSpeed; /*!< Enable the high-speed mode. */
+ bool enableLowPower; /*!< Enable the low power mode. */
+ bool enableLongSample; /*!< Enable the long sample mode. */
+ bool enableAsynchronousClockOutput; /*!< Enable the asynchronous clock output. */
+ adc_reference_voltage_source_t referenceVoltageSource; /*!< Select the reference voltage source. */
+ adc_sample_period_mode_t samplePeriodMode; /*!< Select the sample period in long sample mode or short mode. */
+ adc_clock_source_t clockSource; /*!< Select the input clock source to generate the internal clock ADCK. */
+ adc_clock_driver_t clockDriver; /*!< Select the divide ratio used by the ADC to generate the internal clock ADCK. */
+ adc_resolution_t resolution; /*!< Select the ADC resolution mode. */
+} adc_config_t;
+
+/*!
+ * @brief Converter Offset configuration.
+ */
+typedef struct _adc_offest_config
+{
+ bool enableSigned; /*!< if false,The offset value is added with the raw result.
+ if true,The offset value is subtracted from the raw converted value. */
+ uint32_t offsetValue; /*!< User configurable offset value(0-4095). */
+} adc_offest_config_t;
+
+/*!
+ * @brief ADC hardware compare configuration.
+ *
+ * In kADC_HardwareCompareMode0, compare true if the result is less than the value1.
+ * In kADC_HardwareCompareMode1, compare true if the result is greater than or equal to value1.
+ * In kADC_HardwareCompareMode2, Value1 <= Value2, compare true if the result is less than value1 Or the result is
+ * Greater than value2.
+ * Value1 > Value2, compare true if the result is less than value1 And the result is
+ * Greater than value2.
+ * In kADC_HardwareCompareMode3, Value1 <= Value2, compare true if the result is greater than or equal to value1 And the
+ * result is less than or equal to value2.
+ * Value1 > Value2, compare true if the result is greater than or equal to value1 Or the
+ * result is less than or equal to value2.
+ */
+typedef struct _adc_hardware_compare_config
+{
+ adc_hardware_compare_mode_t hardwareCompareMode; /*!< Select the hardware compare mode.
+ See "adc_hardware_compare_mode_t". */
+ uint16_t value1; /*!< Setting value1(0-4095) for hardware compare mode. */
+ uint16_t value2; /*!< Setting value2(0-4095) for hardware compare mode. */
+} adc_hardware_compare_config_t;
+
+/*!
+ * @brief ADC channel conversion configuration.
+ */
+typedef struct _adc_channel_config
+{
+ uint32_t channelNumber; /*!< Setting the conversion channel number. The available range is 0-31.
+ See channel connection information for each chip in Reference
+ Manual document. */
+ bool enableInterruptOnConversionCompleted; /*!< Generate an interrupt request once the conversion is completed. */
+} adc_channel_config_t;
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize the ADC module.
+ *
+ * @param base ADC peripheral base address.
+ * @param config Pointer to "adc_config_t" structure.
+ */
+void ADC_Init(ADC_Type *base, const adc_config_t *config);
+
+/*!
+ * @brief De-initializes the ADC module.
+ *
+ * @param base ADC peripheral base address.
+ */
+void ADC_Deinit(ADC_Type *base);
+
+/*!
+ * @brief Gets an available pre-defined settings for the converter's configuration.
+ *
+ * This function initializes the converter configuration structure with available settings. The default values are:
+ * @code
+ * config->enableAsynchronousClockOutput = true;
+ * config->enableOverWrite = false;
+ * config->enableContinuousConversion = false;
+ * config->enableHighSpeed = false;
+ * config->enableLowPower = false;
+ * config->enableLongSample = false;
+ * config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;
+ * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
+ * config->clockSource = kADC_ClockSourceAD;
+ * config->clockDriver = kADC_ClockDriver1;
+ * config->resolution = kADC_Resolution12Bit;
+ * @endcode
+ * @param config Pointer to the configuration structure.
+ */
+void ADC_GetDefaultConfig(adc_config_t *config);
+
+/*!
+ * @brief Configures the conversion channel.
+ *
+ * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
+ * configures the channel while the external trigger source helps to trigger the conversion.
+ *
+ * Note that the "Channel Group" has a detailed description.
+ * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
+ * group of status and control registers, one for each conversion. The channel group parameter indicates which group of
+ * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B
+ * registers. The
+ * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of
+ * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
+ * hardware
+ * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for
+ * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual
+ * about the
+ * number of SC1n registers (channel groups) specific to this device. None of the channel groups 1 or greater are used
+ * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
+ * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
+ * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
+ * conversion aborts the current conversion.
+ *
+ * @param base ADC peripheral base address.
+ * @param channelGroup Channel group index.
+ * @param config Pointer to the "adc_channel_config_t" structure for the conversion channel.
+ */
+void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config);
+
+/*!
+ * @brief Gets the conversion value.
+ *
+ * @param base ADC peripheral base address.
+ * @param channelGroup Channel group index.
+ *
+ * @return Conversion value.
+ */
+static inline uint32_t ADC_GetChannelConversionValue(ADC_Type *base, uint32_t channelGroup)
+{
+ assert(channelGroup < (uint32_t)FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT);
+
+ return base->R[channelGroup];
+}
+
+/*!
+ * @brief Gets the status flags of channel.
+ *
+ * A conversion is completed when the result of the conversion is transferred into the data
+ * result registers. (provided the compare function & hardware averaging is disabled), this is
+ * indicated by the setting of COCOn. If hardware averaging is enabled, COCOn sets only,
+ * if the last of the selected number of conversions is complete. If the compare function is
+ * enabled, COCOn sets and conversion result data is transferred only if the compare
+ * condition is true. If both hardware averaging and compare functions are enabled, then
+ * COCOn sets only if the last of the selected number of conversions is complete and the
+ * compare condition is true.
+ *
+ * @param base ADC peripheral base address.
+ * @param channelGroup Channel group index.
+ *
+ * @return Status flags of channel.return 0 means COCO flag is 0,return 1 means COCOflag is 1.
+ */
+static inline uint32_t ADC_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup)
+{
+ assert(channelGroup < (uint32_t)FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT);
+
+ /* If flag is set,return 1,otherwise, return 0. */
+ return (((base->HS) & (1UL << channelGroup)) >> channelGroup);
+}
+
+/*!
+ * @brief Automates the hardware calibration.
+ *
+ * This auto calibration helps to adjust the plus/minus side gain automatically.
+ * Execute the calibration before using the converter. Note that the software trigger should be used
+ * during calibration.
+ *
+ * @param base ADC peripheral base address.
+ *
+ * @return Execution status.
+ * @retval kStatus_Success Calibration is done successfully.
+ * @retval kStatus_Fail Calibration has failed.
+ */
+status_t ADC_DoAutoCalibration(ADC_Type *base);
+
+/*!
+ * @brief Set user defined offset.
+ *
+ * @param base ADC peripheral base address.
+ * @param config Pointer to "adc_offest_config_t" structure.
+ */
+void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config);
+
+/*!
+ * @brief Enables generating the DMA trigger when the conversion is complete.
+ *
+ * @param base ADC peripheral base address.
+ * @param enable Switcher of the DMA feature. "true" means enabled, "false" means not enabled.
+ */
+static inline void ADC_EnableDMA(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->GC |= ADC_GC_DMAEN_MASK;
+ }
+ else
+ {
+ base->GC &= ~ADC_GC_DMAEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables the hardware trigger mode.
+ *
+ * @param base ADC peripheral base address.
+ * @param enable Switcher of the trigger mode. "true" means hardware tirgger mode,"false" means software mode.
+ */
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
+static inline void ADC_EnableHardwareTrigger(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CFG |= ADC_CFG_ADTRG_MASK;
+ }
+ else
+ {
+ base->CFG &= ~ADC_CFG_ADTRG_MASK;
+ }
+}
+#endif
+
+/*!
+ * @brief Configures the hardware compare mode.
+ *
+ * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
+ * result
+ * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate
+ * reference
+ * manual for more information.
+ *
+ * @param base ADC peripheral base address.
+ * @param config Pointer to "adc_hardware_compare_config_t" structure.
+ *
+ */
+void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config);
+
+/*!
+ * @brief Configures the hardware average mode.
+ *
+ * The hardware average mode provides a way to process the conversion result automatically by using hardware. The
+ * multiple
+ * conversion results are accumulated and averaged internally making them easier to read.
+ *
+ * @param base ADC peripheral base address.
+ * @param mode Setting the hardware average mode. See "adc_hardware_average_mode_t".
+ */
+void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode);
+
+/*!
+ * @brief Gets the converter's status flags.
+ *
+ * @param base ADC peripheral base address.
+ *
+ * @return Flags' mask if indicated flags are asserted. See "adc_status_flags_t".
+ */
+static inline uint32_t ADC_GetStatusFlags(ADC_Type *base)
+{
+ return base->GS;
+}
+
+/*!
+ * @brief Clears the converter's status falgs.
+ *
+ * @param base ADC peripheral base address.
+ * @param mask Mask value for the cleared flags. See "adc_status_flags_t".
+ */
+void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask);
+
+/*!
+ *@}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ *@}
+ */
+
+#endif /* _FSL_ADC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.c b/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.c
new file mode 100644
index 0000000000..e98ed23e28
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_adc_etc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.adc_etc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if defined(ADC_ETC_CLOCKS)
+/*!
+ * @brief Get instance number for ADC_ETC module.
+ *
+ * @param base ADC_ETC peripheral base address
+ */
+static uint32_t ADC_ETC_GetInstance(ADC_ETC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ADC_ETC bases for each instance. */
+static ADC_ETC_Type *const s_adcetcBases[] = ADC_ETC_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC_ETC clocks for each instance. */
+static const clock_ip_name_t s_adcetcClocks[] = ADC_ETC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ADC_ETC_GetInstance(ADC_ETC_Type *base)
+{
+ uint32_t instance = 0U;
+ uint32_t adcetcArrayCount = (sizeof(s_adcetcBases) / sizeof(s_adcetcBases[0]));
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < adcetcArrayCount; instance++)
+ {
+ if (s_adcetcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < adcetcArrayCount);
+
+ return instance;
+}
+#endif /* ADC_ETC_CLOCKS */
+
+/*!
+ * brief Initialize the ADC_ETC module.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_Init(ADC_ETC_Type *base, const adc_etc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32 = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(ADC_ETC_CLOCKS)
+ /* Open clock gate. */
+ CLOCK_EnableClock(s_adcetcClocks[ADC_ETC_GetInstance(base)]);
+#endif /* ADC_ETC_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Disable software reset. */
+ ADC_ETC_DoSoftwareReset(base, false);
+
+ /* Set ADC_ETC_CTRL register. */
+ tmp32 =
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ ADC_ETC_CTRL_EXT0_TRIG_PRIORITY(config->TSC0triggerPriority) |
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ ADC_ETC_CTRL_EXT1_TRIG_PRIORITY(config->TSC1triggerPriority) |
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+ ADC_ETC_CTRL_PRE_DIVIDER(config->clockPreDivider) | ADC_ETC_CTRL_TRIG_ENABLE(config->XBARtriggerMask)
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+ | ADC_ETC_CTRL_DMA_MODE_SEL(config->dmaMode)
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+ ;
+
+#if (!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)) || \
+ (!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG))
+ if (config->enableTSCBypass)
+ {
+ tmp32 |= ADC_ETC_CTRL_TSC_BYPASS_MASK;
+ }
+#endif
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ if (config->enableTSC0Trigger)
+ {
+ tmp32 |= ADC_ETC_CTRL_EXT0_TRIG_ENABLE_MASK;
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ if (config->enableTSC1Trigger)
+ {
+ tmp32 |= ADC_ETC_CTRL_EXT1_TRIG_ENABLE_MASK;
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+ base->CTRL = tmp32;
+}
+
+/*!
+ * brief De-Initialize the ADC_ETC module.
+ *
+ * param base ADC_ETC peripheral base address.
+ */
+void ADC_ETC_Deinit(ADC_ETC_Type *base)
+{
+ /* Do software reset to clear all logical. */
+ ADC_ETC_DoSoftwareReset(base, true);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(ADC_ETC_CLOCKS)
+ /* Close clock gate. */
+ CLOCK_DisableClock(s_adcetcClocks[ADC_ETC_GetInstance(base)]);
+#endif /* ADC_ETC_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets an available pre-defined settings for the ADC_ETC's configuration.
+ * This function initializes the ADC_ETC's configuration structure with available settings. The default values are:
+ * code
+ * config->enableTSCBypass = true;
+ * config->enableTSC0Trigger = false;
+ * config->enableTSC1Trigger = false;
+ * config->TSC0triggerPriority = 0U;
+ * config->TSC1triggerPriority = 0U;
+ * config->clockPreDivider = 0U;
+ * config->XBARtriggerMask = 0U;
+ * endCode
+ *
+ * param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_GetDefaultConfig(adc_etc_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+#if (!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)) || \
+ (!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG))
+ config->enableTSCBypass = true;
+#endif
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ config->enableTSC0Trigger = false;
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ config->enableTSC1Trigger = false;
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+ config->dmaMode = kADC_ETC_TrigDMAWithLatchedSignal;
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ config->TSC0triggerPriority = 0U;
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ config->TSC1triggerPriority = 0U;
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+ config->clockPreDivider = 0U;
+ config->XBARtriggerMask = 0U;
+}
+
+/*!
+ * brief Set the external XBAR trigger configuration.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index.
+ * param config Pointer to "adc_etc_trigger_config_t" structure.
+ */
+void ADC_ETC_SetTriggerConfig(ADC_ETC_Type *base, uint32_t triggerGroup, const adc_etc_trigger_config_t *config)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_CTRL_COUNT);
+ assert(ADC_ETC_TRIGn_COUNTER_COUNT > triggerGroup);
+
+ uint32_t tmp32 = 0U;
+
+ /* Set ADC_ETC_TRGn_CTRL register. */
+ tmp32 = ADC_ETC_TRIGn_CTRL_TRIG_CHAIN(config->triggerChainLength) |
+ ADC_ETC_TRIGn_CTRL_TRIG_PRIORITY(config->triggerPriority);
+ if (config->enableSyncMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CTRL_SYNC_MODE_MASK;
+ }
+ if (config->enableSWTriggerMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CTRL_TRIG_MODE_MASK;
+ }
+ base->TRIG[triggerGroup].TRIGn_CTRL = tmp32;
+
+ /* Set ADC_ETC_TRGn_COUNTER register. */
+ tmp32 = ADC_ETC_TRIGn_COUNTER_INIT_DELAY(config->initialDelay) |
+ ADC_ETC_TRIGn_COUNTER_SAMPLE_INTERVAL(config->sampleIntervalDelay);
+ base->TRIG[triggerGroup].TRIGn_COUNTER = tmp32;
+}
+
+/*!
+ * brief Set the external XBAR trigger chain configuration.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means Trigger0 source's chain1 would be
+ * configurated.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index. Available number is 0~7.
+ * param chainGroup Trigger chain group index. Available number is 0~7.
+ * param config Pointer to "adc_etc_trigger_chain_config_t" structure.
+ */
+void ADC_ETC_SetTriggerChainConfig(ADC_ETC_Type *base,
+ uint32_t triggerGroup,
+ uint32_t chainGroup,
+ const adc_etc_trigger_chain_config_t *config)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_CTRL_COUNT);
+
+ uint32_t tmp32 = 0U;
+ uint32_t tmpReg = 0U;
+ uint8_t mRemainder = (uint8_t)(chainGroup % 2U);
+
+ /* Set ADC_ETC_TRIGn_CHAINm register. */
+ tmp32 = ADC_ETC_TRIGn_CHAIN_1_0_HWTS0(config->ADCHCRegisterSelect) |
+ ADC_ETC_TRIGn_CHAIN_1_0_CSEL0(config->ADCChannelSelect) |
+ ADC_ETC_TRIGn_CHAIN_1_0_IE0(config->InterruptEnable);
+ if (true == config->enableB2BMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CHAIN_1_0_B2B0_MASK;
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (true == config->enableIrq)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CHAIN_1_0_IE0_EN_MASK;
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ switch (chainGroup / 2U)
+ {
+ case 0U: /* Configurate trigger chain0 and chain 1. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_1_0;
+ if (mRemainder == 0U) /* Chain 0. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_1_0_CSEL0_MASK | ADC_ETC_TRIGn_CHAIN_1_0_HWTS0_MASK |
+ ADC_ETC_TRIGn_CHAIN_1_0_B2B0_MASK | ADC_ETC_TRIGn_CHAIN_1_0_IE0_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 1. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_1_0_CSEL1_MASK | ADC_ETC_TRIGn_CHAIN_1_0_HWTS1_MASK |
+ ADC_ETC_TRIGn_CHAIN_1_0_B2B1_MASK | ADC_ETC_TRIGn_CHAIN_1_0_IE1_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_1_0_CSEL1_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_1_0 = tmpReg;
+ break;
+ case 1U: /* Configurate trigger chain2 and chain 3. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_3_2;
+ if (mRemainder == 0U) /* Chain 2. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_3_2_CSEL2_MASK | ADC_ETC_TRIGn_CHAIN_3_2_HWTS2_MASK |
+ ADC_ETC_TRIGn_CHAIN_3_2_B2B2_MASK | ADC_ETC_TRIGn_CHAIN_3_2_IE2_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 3. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_3_2_CSEL3_MASK | ADC_ETC_TRIGn_CHAIN_3_2_HWTS3_MASK |
+ ADC_ETC_TRIGn_CHAIN_3_2_B2B3_MASK | ADC_ETC_TRIGn_CHAIN_3_2_IE3_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_3_2_CSEL3_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_3_2 = tmpReg;
+ break;
+ case 2U: /* Configurate trigger chain4 and chain 5. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_5_4;
+ if (mRemainder == 0U) /* Chain 4. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_5_4_CSEL4_MASK | ADC_ETC_TRIGn_CHAIN_5_4_HWTS4_MASK |
+ ADC_ETC_TRIGn_CHAIN_5_4_B2B4_MASK | ADC_ETC_TRIGn_CHAIN_5_4_IE4_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 5. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_5_4_CSEL5_MASK | ADC_ETC_TRIGn_CHAIN_5_4_HWTS5_MASK |
+ ADC_ETC_TRIGn_CHAIN_5_4_B2B5_MASK | ADC_ETC_TRIGn_CHAIN_5_4_IE5_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_5_4_CSEL5_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_5_4 = tmpReg;
+ break;
+ case 3U: /* Configurate trigger chain6 and chain 7. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_7_6;
+ if (mRemainder == 0U) /* Chain 6. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_7_6_CSEL6_MASK | ADC_ETC_TRIGn_CHAIN_7_6_HWTS6_MASK |
+ ADC_ETC_TRIGn_CHAIN_7_6_B2B6_MASK | ADC_ETC_TRIGn_CHAIN_7_6_IE6_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 7. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_7_6_CSEL7_MASK | ADC_ETC_TRIGn_CHAIN_7_6_HWTS7_MASK |
+ ADC_ETC_TRIGn_CHAIN_7_6_B2B7_MASK | ADC_ETC_TRIGn_CHAIN_7_6_IE7_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_7_6_CSEL7_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_7_6 = tmpReg;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Gets the interrupt status flags of external XBAR and TSC triggers.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param sourceIndex trigger source index.
+ *
+ * return Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+uint32_t ADC_ETC_GetInterruptStatusFlags(ADC_ETC_Type *base, adc_etc_external_trigger_source_t sourceIndex)
+{
+ uint32_t tmp32 = 0U;
+
+ if (((base->DONE0_1_IRQ) & ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE0_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done0StatusFlagMask; /* Customized DONE0 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ if (((base->DONE0_1_IRQ) & ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE1_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done1StatusFlagMask; /* Customized DONE1 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ if (((base->DONE2_3_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_DONE2_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done2StatusFlagMask; /* Customized DONE2 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (((base->DONE2_3_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_DONE3_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done3StatusFlagMask; /* Customized DONE3 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ if (((base->DONE2_3_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_ERR_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_ErrorStatusFlagMask; /* Customized ERROR status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ return tmp32;
+}
+
+/*!
+ * brief Clears the ADC_ETC's interrupt status falgs.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param sourceIndex trigger source index.
+ * param mask Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+void ADC_ETC_ClearInterruptStatusFlags(ADC_ETC_Type *base, adc_etc_external_trigger_source_t sourceIndex, uint32_t mask)
+{
+ if (0U != (mask & (uint32_t)kADC_ETC_Done0StatusFlagMask)) /* Write 1 to clear DONE0 status flags. */
+ {
+ base->DONE0_1_IRQ = ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE0_MASK << (uint32_t)sourceIndex);
+ }
+ if (0U != (mask & (uint32_t)kADC_ETC_Done1StatusFlagMask)) /* Write 1 to clear DONE1 status flags. */
+ {
+ base->DONE0_1_IRQ = ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE1_MASK << (uint32_t)sourceIndex);
+ }
+ if (0U != (mask & (uint32_t)kADC_ETC_Done2StatusFlagMask)) /* Write 1 to clear DONE2 status flags. */
+ {
+ base->DONE2_3_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_DONE2_MASK << (uint32_t)sourceIndex);
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (0U != (mask & (uint32_t)kADC_ETC_Done3StatusFlagMask)) /* Write 1 to clear DONE3 status flags. */
+ {
+ base->DONE2_3_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_DONE3_MASK << (uint32_t)sourceIndex);
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ if (0U != (mask & (uint32_t)kADC_ETC_ErrorStatusFlagMask)) /* Write 1 to clear ERROR status flags. */
+ {
+ base->DONE2_3_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_3_ERR_IRQ_TRIG0_ERR_MASK << (uint32_t)sourceIndex);
+ }
+}
+
+/*!
+ * brief Get ADC conversion result from external XBAR sources.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means the API would
+ * return Trigger0 source's chain1 conversion result.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index. Available number is 0~7.
+ * param chainGroup Trigger chain group index. Available number is 0~7.
+ * return ADC conversion result value.
+ */
+uint32_t ADC_ETC_GetADCConversionValue(ADC_ETC_Type *base, uint32_t triggerGroup, uint32_t chainGroup)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_RESULT_1_0_COUNT);
+
+ uint32_t mADCResult;
+ uint8_t mRemainder = (uint8_t)(chainGroup % 2U);
+
+ switch (chainGroup / 2U)
+ {
+ case 0U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_1_0_DATA0_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_1_0);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_1_0) >> ADC_ETC_TRIGn_RESULT_1_0_DATA1_SHIFT;
+ }
+ break;
+ case 1U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_3_2_DATA2_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_3_2);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_3_2) >> ADC_ETC_TRIGn_RESULT_3_2_DATA3_SHIFT;
+ }
+ break;
+ case 2U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_5_4_DATA4_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_5_4);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_5_4) >> ADC_ETC_TRIGn_RESULT_5_4_DATA5_SHIFT;
+ }
+ break;
+ case 3U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_7_6_DATA6_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_7_6);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_7_6) >> ADC_ETC_TRIGn_RESULT_7_6_DATA7_SHIFT;
+ }
+ break;
+ default:
+ mADCResult = 0U;
+ assert(false);
+ break;
+ }
+ return mADCResult;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.h b/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.h
new file mode 100644
index 0000000000..e34e19b00a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/adc_etc/fsl_adc_etc.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ADC_ETC_H_
+#define _FSL_ADC_ETC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup adc_etc
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief ADC_ETC driver version */
+#define FSL_ADC_ETC_DRIVER_VERSION (MAKE_VERSION(2, 2, 1)) /*!< Version 2.2.1. */
+/*! @brief The mask of status flags cleared by writing 1. */
+#define ADC_ETC_DMA_CTRL_TRGn_REQ_MASK 0xFF0000U
+
+/*!
+ * @brief ADC_ETC customized status flags mask.
+ */
+enum _adc_etc_status_flag_mask
+{
+ kADC_ETC_Done0StatusFlagMask = 1U << 0U,
+ kADC_ETC_Done1StatusFlagMask = 1U << 1U,
+ kADC_ETC_Done2StatusFlagMask = 1U << 2U,
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ kADC_ETC_Done3StatusFlagMask = 1U << 3U,
+ kADC_ETC_ErrorStatusFlagMask = 1U << 4U,
+#else
+ kADC_ETC_ErrorStatusFlagMask = 1U << 3U,
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+};
+
+/*!
+ * @brief External triggers sources.
+ */
+typedef enum _adc_etc_external_trigger_source
+{
+ /* External XBAR sources. Support HW or SW mode. */
+ kADC_ETC_Trg0TriggerSource = 0U, /* External XBAR trigger0 source. */
+ kADC_ETC_Trg1TriggerSource = 1U, /* External XBAR trigger1 source. */
+ kADC_ETC_Trg2TriggerSource = 2U, /* External XBAR trigger2 source. */
+ kADC_ETC_Trg3TriggerSource = 3U, /* External XBAR trigger3 source. */
+ kADC_ETC_Trg4TriggerSource = 4U, /* External XBAR trigger4 source. */
+ kADC_ETC_Trg5TriggerSource = 5U, /* External XBAR trigger5 source. */
+ kADC_ETC_Trg6TriggerSource = 6U, /* External XBAR trigger6 source. */
+ kADC_ETC_Trg7TriggerSource = 7U, /* External XBAR trigger7 source. */
+ /* External TSC sources. Only support HW mode. */
+ kADC_ETC_TSC0TriggerSource = 8U, /* External TSC trigger0 source. */
+ kADC_ETC_TSC1TriggerSource = 9U, /* External TSC trigger1 source. */
+} adc_etc_external_trigger_source_t;
+
+/*!
+ * @brief Interrupt enable/disable mask.
+ */
+typedef enum _adc_etc_interrupt_enable
+{
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ kADC_ETC_Done0InterruptEnable = 0U, /* Enable the DONE0 interrupt when ADC conversions complete. */
+ kADC_ETC_Done1InterruptEnable = 1U, /* Enable the DONE1 interrupt when ADC conversions complete. */
+ kADC_ETC_Done2InterruptEnable = 2U, /* Enable the DONE2 interrupt when ADC conversions complete. */
+ kADC_ETC_Done3InterruptEnable = 3U, /* Enable the DONE3 interrupt when ADC conversions complete. */
+#else
+ kADC_ETC_InterruptDisable = 0U, /* Disable the ADC_ETC interrupt. */
+ kADC_ETC_Done0InterruptEnable = 1U, /* Enable the DONE0 interrupt when ADC conversions complete. */
+ kADC_ETC_Done1InterruptEnable = 2U, /* Enable the DONE1 interrupt when ADC conversions complete. */
+ kADC_ETC_Done2InterruptEnable = 3U, /* Enable the DONE2 interrupt when ADC conversions complete. */
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+} adc_etc_interrupt_enable_t;
+
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+/*!
+ * @brief DMA mode selection.
+ */
+typedef enum _adc_etc_dma_mode_selection
+{
+ kADC_ETC_TrigDMAWithLatchedSignal =
+ 0U, /* Trig DMA_REQ with latched signal, REQ will be cleared when ACK and source request cleared. */
+ kADC_ETC_TrigDMAWithPulsedSignal = 1U, /* Trig DMA_REQ with pulsed signal, REQ will be cleared by ACK only. */
+} adc_etc_dma_mode_selection_t;
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+
+/*!
+ * @brief ADC_ETC configuration.
+ */
+typedef struct _adc_etc_config
+{
+#if ((!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)) || \
+ (!(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG)))
+ bool enableTSCBypass; /* If bypass TSC, TSC would trigger ADC directly.
+ Otherwise TSC would trigger ADC through ADC_ETC. */
+#endif
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ bool enableTSC0Trigger; /* Enable external TSC0 trigger. It is valid when enableTSCBypass = false. */
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG)
+ bool enableTSC1Trigger; /* Enable external TSC1 trigger. It is valid when enableTSCBypass = false.*/
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG */
+
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+ adc_etc_dma_mode_selection_t dmaMode; /* Select the ADC_ETC DMA mode. */
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG)
+ uint32_t TSC0triggerPriority; /* External TSC0 trigger priority, 7 is highest, 0 is lowest. */
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC0_TRIG */
+
+#if !(defined(FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG) && FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG)
+ uint32_t TSC1triggerPriority; /* External TSC1 trigger priority, 7 is highest, 0 is lowest. */
+#endif /* FSL_FEATURE_ADC_ETC_HAS_NO_TSC1_TRIG */
+ uint32_t clockPreDivider; /* Pre-divider for trig delay and interval. Available range is 0-255.
+ Clock would be divided by (clockPreDivider+1). */
+ uint32_t XBARtriggerMask; /* Enable the corresponding trigger source. Available range is trigger0:0x01 to
+ trigger7:0x80
+ For example, XBARtriggerMask = 0x7U, which means trigger0, trigger1 and trigger2 is
+ enabled. */
+} adc_etc_config_t;
+
+/*!
+ * @brief ADC_ETC trigger chain configuration.
+ */
+typedef struct _adc_etc_trigger_chain_config
+{
+ bool enableB2BMode; /* Enable ADC_ETC BackToBack mode. when not enabled B2B mode,
+ wait until interval delay is reached. */
+ uint32_t ADCHCRegisterSelect; /* Select relevant ADC_HCx register to trigger. 1U : HC0, 2U: HC1, 4U: HC2 ... */
+ uint32_t ADCChannelSelect; /* Select ADC sample channel. */
+ adc_etc_interrupt_enable_t InterruptEnable; /* Enable/disable Interrupt. */
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ bool enableIrq; /* Enable IRQ for selected interrupt enable choice in "InterruptEnable" */
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+} adc_etc_trigger_chain_config_t;
+
+/*!
+ * @brief ADC_ETC trigger configuration.
+ */
+typedef struct _adc_etc_trigger_config
+{
+ bool enableSyncMode; /* Enable the sync Mode, In SyncMode ADC1 and ADC2 are controlled by the same trigger source.
+ In AsyncMode ADC1 and ADC2 are controlled by separate trigger source. */
+ bool enableSWTriggerMode; /* Enable the sofware trigger mode. */
+ uint32_t triggerChainLength; /* TRIG chain length to the ADC. 0: Trig length is 1. ... 7: Trig length is 8. */
+ uint32_t triggerPriority; /* External trigger priority, 7 is highest, 0 is lowest. */
+ uint32_t sampleIntervalDelay; /* Set sampling interval delay. */
+ uint32_t initialDelay; /* Set trigger initial delay. */
+} adc_etc_trigger_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize the ADC_ETC module.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_Init(ADC_ETC_Type *base, const adc_etc_config_t *config);
+
+/*!
+ * @brief De-Initialize the ADC_ETC module.
+ *
+ * @param base ADC_ETC peripheral base address.
+ */
+void ADC_ETC_Deinit(ADC_ETC_Type *base);
+
+/*!
+ * @brief Gets an available pre-defined settings for the ADC_ETC's configuration.
+ * This function initializes the ADC_ETC's configuration structure with available settings. The default values are:
+ * @code
+ * config->enableTSCBypass = true;
+ * config->enableTSC0Trigger = false;
+ * config->enableTSC1Trigger = false;
+ * config->TSC0triggerPriority = 0U;
+ * config->TSC1triggerPriority = 0U;
+ * config->clockPreDivider = 0U;
+ * config->XBARtriggerMask = 0U;
+ * @endcode
+ *
+ * @param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_GetDefaultConfig(adc_etc_config_t *config);
+
+/*!
+ * @brief Set the external XBAR trigger configuration.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index.
+ * @param config Pointer to "adc_etc_trigger_config_t" structure.
+ */
+void ADC_ETC_SetTriggerConfig(ADC_ETC_Type *base, uint32_t triggerGroup, const adc_etc_trigger_config_t *config);
+
+/*!
+ * @brief Set the external XBAR trigger chain configuration.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means Trigger0 source's chain1 would be
+ * configurated.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index. Available number is 0~7.
+ * @param chainGroup Trigger chain group index. Available number is 0~7.
+ * @param config Pointer to "adc_etc_trigger_chain_config_t" structure.
+ */
+void ADC_ETC_SetTriggerChainConfig(ADC_ETC_Type *base,
+ uint32_t triggerGroup,
+ uint32_t chainGroup,
+ const adc_etc_trigger_chain_config_t *config);
+
+/*!
+ * @brief Gets the interrupt status flags of external XBAR and TSC triggers.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param sourceIndex trigger source index.
+ *
+ * @return Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+uint32_t ADC_ETC_GetInterruptStatusFlags(ADC_ETC_Type *base, adc_etc_external_trigger_source_t sourceIndex);
+
+/*!
+ * @brief Clears the ADC_ETC's interrupt status falgs.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param sourceIndex trigger source index.
+ * @param mask Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+void ADC_ETC_ClearInterruptStatusFlags(ADC_ETC_Type *base,
+ adc_etc_external_trigger_source_t sourceIndex,
+ uint32_t mask);
+
+/*!
+ * @brief Enable the DMA corresponding to each trigger source.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index. Available number is 0~7.
+ */
+static inline void ADC_ETC_EnableDMA(ADC_ETC_Type *base, uint32_t triggerGroup)
+{
+ /* Avoid clearing status flags at the same time. */
+ base->DMA_CTRL = (base->DMA_CTRL | ((uint32_t)ADC_ETC_DMA_CTRL_TRIG0_ENABLE_MASK << (uint32_t)triggerGroup)) &
+ ~ADC_ETC_DMA_CTRL_TRGn_REQ_MASK;
+}
+
+/*!
+ * @brief Disable the DMA corresponding to each trigger sources.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index. Available number is 0~7.
+ */
+static inline void ADC_ETC_DisableDMA(ADC_ETC_Type *base, uint32_t triggerGroup)
+{
+ /* Avoid clearing status flags at the same time. */
+ base->DMA_CTRL = (base->DMA_CTRL & ~((uint32_t)ADC_ETC_DMA_CTRL_TRIG0_ENABLE_MASK << (uint32_t)triggerGroup)) &
+ ~ADC_ETC_DMA_CTRL_TRGn_REQ_MASK;
+}
+
+/*!
+ * @brief Get the DMA request status falgs. Only external XBAR sources support DMA request.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @return Mask of external XBAR tirgger's DMA request asserted flags. Available range is trigger0:0x01 to
+ * trigger7:0x80.
+ */
+static inline uint32_t ADC_ETC_GetDMAStatusFlags(ADC_ETC_Type *base)
+{
+ return (((base->DMA_CTRL) & ADC_ETC_DMA_CTRL_TRGn_REQ_MASK) >> ADC_ETC_DMA_CTRL_TRIG0_REQ_SHIFT);
+}
+
+/*!
+ * @brief Clear the DMA request status falgs. Only external XBAR sources support DMA request.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param mask Mask of external XBAR tirgger's DMA request asserted flags. Available range is trigger0:0x01 to
+ * trigger7:0x80.
+ */
+static inline void ADC_ETC_ClearDMAStatusFlags(ADC_ETC_Type *base, uint32_t mask)
+{
+ base->DMA_CTRL = ((base->DMA_CTRL) & ~ADC_ETC_DMA_CTRL_TRGn_REQ_MASK) | (mask << ADC_ETC_DMA_CTRL_TRIG0_REQ_SHIFT);
+}
+
+/*!
+ * @brief When enable, all logical will be reset.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param enable Enable/Disable the software reset.
+ */
+static inline void ADC_ETC_DoSoftwareReset(ADC_ETC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= ADC_ETC_CTRL_SOFTRST_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~ADC_ETC_CTRL_SOFTRST_MASK;
+ }
+}
+
+/*!
+ * @brief Do software trigger corresponding to each XBAR trigger sources.
+ * Each XBAR trigger sources can be configured as HW or SW trigger mode. In hardware trigger mode,
+ * trigger source is from XBAR. In software mode, trigger source is from software tigger. TSC trigger sources
+ * can only work in hardware trigger mode.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index. Available number is 0~7.
+ */
+static inline void ADC_ETC_DoSoftwareTrigger(ADC_ETC_Type *base, uint32_t triggerGroup)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_CTRL_COUNT);
+
+ base->TRIG[triggerGroup].TRIGn_CTRL |= ADC_ETC_TRIGn_CTRL_SW_TRIG_MASK;
+}
+
+/*!
+ * @brief Get ADC conversion result from external XBAR sources.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means the API would
+ * return Trigger0 source's chain1 conversion result.
+ *
+ * @param base ADC_ETC peripheral base address.
+ * @param triggerGroup Trigger group index. Available number is 0~7.
+ * @param chainGroup Trigger chain group index. Available number is 0~7.
+ * @return ADC conversion result value.
+ */
+uint32_t ADC_ETC_GetADCConversionValue(ADC_ETC_Type *base, uint32_t triggerGroup, uint32_t chainGroup);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* @} */
+
+#endif /* _FSL_ADC_ETC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.c b/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.c
new file mode 100644
index 0000000000..a8f1f29ddb
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "fsl_aoi.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.aoi"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to aoi bases for each instance. */
+static AOI_Type *const s_aoiBases[] = AOI_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to aoi clocks for each instance. */
+static const clock_ip_name_t s_aoiClocks[] = AOI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for AOI module.
+ *
+ * @param base AOI peripheral base address
+ *
+ * @return The AOI instance
+ */
+static uint32_t AOI_GetInstance(AOI_Type *base);
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t AOI_GetInstance(AOI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_aoiBases); instance++)
+ {
+ if (s_aoiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_aoiBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes an AOI instance for operation.
+ *
+ * This function un-gates the AOI clock.
+ *
+ * param base AOI peripheral address.
+ */
+void AOI_Init(AOI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock gate from clock manager. */
+ CLOCK_EnableClock(s_aoiClocks[AOI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitializes an AOI instance for operation.
+ *
+ * This function shutdowns AOI module.
+ *
+ * param base AOI peripheral address.
+ */
+void AOI_Deinit(AOI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock gate from clock manager */
+ CLOCK_DisableClock(s_aoiClocks[AOI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the Boolean evaluation associated.
+ *
+ * This function returns the Boolean evaluation associated.
+ *
+ * Example:
+ code
+ aoi_event_config_t demoEventLogicStruct;
+
+ AOI_GetEventLogicConfig(AOI, kAOI_Event0, &demoEventLogicStruct);
+ endcode
+ *
+ * param base AOI peripheral address.
+ * param event Index of the event which will be set of type aoi_event_t.
+ * param config Selected input configuration .
+ */
+void AOI_GetEventLogicConfig(AOI_Type *base, aoi_event_t event, aoi_event_config_t *config)
+{
+ assert((uint32_t)event < (uint32_t)FSL_FEATURE_AOI_EVENT_COUNT);
+ assert(config != NULL);
+
+ uint16_t value;
+ uint16_t temp;
+ /* Read BFCRT01 register at event index. */
+ value = base->BFCRT[event].BFCRT01;
+
+ temp = (value & AOI_BFCRT01_PT0_AC_MASK) >> AOI_BFCRT01_PT0_AC_SHIFT;
+ config->PT0AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_BC_MASK) >> AOI_BFCRT01_PT0_BC_SHIFT;
+ config->PT0BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_CC_MASK) >> AOI_BFCRT01_PT0_CC_SHIFT;
+ config->PT0CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_DC_MASK) >> AOI_BFCRT01_PT0_DC_SHIFT;
+ config->PT0DC = (aoi_input_config_t)temp;
+
+ temp = (value & AOI_BFCRT01_PT1_AC_MASK) >> AOI_BFCRT01_PT1_AC_SHIFT;
+ config->PT1AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_BC_MASK) >> AOI_BFCRT01_PT1_BC_SHIFT;
+ config->PT1BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_CC_MASK) >> AOI_BFCRT01_PT1_CC_SHIFT;
+ config->PT1CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_DC_MASK) >> AOI_BFCRT01_PT1_DC_SHIFT;
+ config->PT1DC = (aoi_input_config_t)temp;
+
+ /* Read BFCRT23 register at event index. */
+ value = base->BFCRT[event].BFCRT23;
+
+ temp = (value & AOI_BFCRT23_PT2_AC_MASK) >> AOI_BFCRT23_PT2_AC_SHIFT;
+ config->PT2AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_BC_MASK) >> AOI_BFCRT23_PT2_BC_SHIFT;
+ config->PT2BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_CC_MASK) >> AOI_BFCRT23_PT2_CC_SHIFT;
+ config->PT2CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_DC_MASK) >> AOI_BFCRT23_PT2_DC_SHIFT;
+ config->PT2DC = (aoi_input_config_t)temp;
+
+ temp = (value & AOI_BFCRT23_PT3_AC_MASK) >> AOI_BFCRT23_PT3_AC_SHIFT;
+ config->PT3AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_BC_MASK) >> AOI_BFCRT23_PT3_BC_SHIFT;
+ config->PT3BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_CC_MASK) >> AOI_BFCRT23_PT3_CC_SHIFT;
+ config->PT3CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_DC_MASK) >> AOI_BFCRT23_PT3_DC_SHIFT;
+ config->PT3DC = (aoi_input_config_t)temp;
+}
+
+/*!
+ * brief Configures an AOI event.
+ *
+ * This function configures an AOI event according
+ * to the aoiEventConfig structure. This function configures all inputs (A, B, C, and D)
+ * of all product terms (0, 1, 2, and 3) of a desired event.
+ *
+ * Example:
+ code
+ aoi_event_config_t demoEventLogicStruct;
+
+ demoEventLogicStruct.PT0AC = kAOI_InvInputSignal;
+ demoEventLogicStruct.PT0BC = kAOI_InputSignal;
+ demoEventLogicStruct.PT0CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT0DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT1AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT1BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT2AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT2BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT3AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT3BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3DC = kAOI_LogicOne;
+
+ AOI_SetEventLogicConfig(AOI, kAOI_Event0, demoEventLogicStruct);
+ endcode
+ *
+ * param base AOI peripheral address.
+ * param event Event which will be configured of type aoi_event_t.
+ * param eventConfig Pointer to type aoi_event_config_t structure. The user is responsible for
+ * filling out the members of this structure and passing the pointer to this function.
+ */
+void AOI_SetEventLogicConfig(AOI_Type *base, aoi_event_t event, const aoi_event_config_t *eventConfig)
+{
+ assert(eventConfig != NULL);
+ assert((uint32_t)event < (uint32_t)FSL_FEATURE_AOI_EVENT_COUNT);
+
+ uint16_t value;
+ /* Calculate value to configure product term 0, 1 */
+ value = AOI_BFCRT01_PT0_AC(eventConfig->PT0AC) | AOI_BFCRT01_PT0_BC(eventConfig->PT0BC) |
+ AOI_BFCRT01_PT0_CC(eventConfig->PT0CC) | AOI_BFCRT01_PT0_DC(eventConfig->PT0DC) |
+ AOI_BFCRT01_PT1_AC(eventConfig->PT1AC) | AOI_BFCRT01_PT1_BC(eventConfig->PT1BC) |
+ AOI_BFCRT01_PT1_CC(eventConfig->PT1CC) | AOI_BFCRT01_PT1_DC(eventConfig->PT1DC);
+ /* Write value to register */
+ base->BFCRT[event].BFCRT01 = value;
+
+ /* Reset and calculate value to configure product term 2, 3 */
+ value = AOI_BFCRT23_PT2_AC(eventConfig->PT2AC) | AOI_BFCRT23_PT2_BC(eventConfig->PT2BC) |
+ AOI_BFCRT23_PT2_CC(eventConfig->PT2CC) | AOI_BFCRT23_PT2_DC(eventConfig->PT2DC) |
+ AOI_BFCRT23_PT3_AC(eventConfig->PT3AC) | AOI_BFCRT23_PT3_BC(eventConfig->PT3BC) |
+ AOI_BFCRT23_PT3_CC(eventConfig->PT3CC) | AOI_BFCRT23_PT3_DC(eventConfig->PT3DC);
+ /* Write value to register */
+ base->BFCRT[event].BFCRT23 = value;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.h b/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.h
new file mode 100644
index 0000000000..6d905b9d64
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/aoi/fsl_aoi.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_AOI_H_
+#define _FSL_AOI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup aoi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#ifndef AOI
+#define AOI AOI0 /*!< AOI peripheral address */
+#endif
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_AOI_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) /*!< Version 2.0.1. */
+/*@}*/
+
+/*!
+ * @brief AOI input configurations.
+ *
+ * The selection item represents the Boolean evaluations.
+ */
+typedef enum _aoi_input_config
+{
+ kAOI_LogicZero = 0x0U, /*!< Forces the input to logical zero. */
+ kAOI_InputSignal = 0x1U, /*!< Passes the input signal. */
+ kAOI_InvInputSignal = 0x2U, /*!< Inverts the input signal. */
+ kAOI_LogicOne = 0x3U /*!< Forces the input to logical one. */
+} aoi_input_config_t;
+
+/*!
+ * @brief AOI event indexes, where an event is the collection of the four product
+ * terms (0, 1, 2, and 3) and the four signal inputs (A, B, C, and D).
+ */
+typedef enum _aoi_event
+{
+ kAOI_Event0 = 0x0U, /*!< Event 0 index */
+ kAOI_Event1 = 0x1U, /*!< Event 1 index */
+ kAOI_Event2 = 0x2U, /*!< Event 2 index */
+ kAOI_Event3 = 0x3U /*!< Event 3 index */
+} aoi_event_t;
+
+/*!
+ * @brief AOI event configuration structure
+ *
+ * Defines structure _aoi_event_config and use the AOI_SetEventLogicConfig() function to make
+ * whole event configuration.
+ */
+typedef struct _aoi_event_config
+{
+ aoi_input_config_t PT0AC; /*!< Product term 0 input A */
+ aoi_input_config_t PT0BC; /*!< Product term 0 input B */
+ aoi_input_config_t PT0CC; /*!< Product term 0 input C */
+ aoi_input_config_t PT0DC; /*!< Product term 0 input D */
+ aoi_input_config_t PT1AC; /*!< Product term 1 input A */
+ aoi_input_config_t PT1BC; /*!< Product term 1 input B */
+ aoi_input_config_t PT1CC; /*!< Product term 1 input C */
+ aoi_input_config_t PT1DC; /*!< Product term 1 input D */
+ aoi_input_config_t PT2AC; /*!< Product term 2 input A */
+ aoi_input_config_t PT2BC; /*!< Product term 2 input B */
+ aoi_input_config_t PT2CC; /*!< Product term 2 input C */
+ aoi_input_config_t PT2DC; /*!< Product term 2 input D */
+ aoi_input_config_t PT3AC; /*!< Product term 3 input A */
+ aoi_input_config_t PT3BC; /*!< Product term 3 input B */
+ aoi_input_config_t PT3CC; /*!< Product term 3 input C */
+ aoi_input_config_t PT3DC; /*!< Product term 3 input D */
+} aoi_event_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @name AOI Initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes an AOI instance for operation.
+ *
+ * This function un-gates the AOI clock.
+ *
+ * @param base AOI peripheral address.
+ */
+void AOI_Init(AOI_Type *base);
+
+/*!
+ * @brief Deinitializes an AOI instance for operation.
+ *
+ * This function shutdowns AOI module.
+ *
+ * @param base AOI peripheral address.
+ */
+void AOI_Deinit(AOI_Type *base);
+
+/*@}*/
+
+/*!
+ * @name AOI Get Set Operation
+ * @{
+ */
+
+/*!
+ * @brief Gets the Boolean evaluation associated.
+ *
+ * This function returns the Boolean evaluation associated.
+ *
+ * Example:
+ @code
+ aoi_event_config_t demoEventLogicStruct;
+
+ AOI_GetEventLogicConfig(AOI, kAOI_Event0, &demoEventLogicStruct);
+ @endcode
+ *
+ * @param base AOI peripheral address.
+ * @param event Index of the event which will be set of type aoi_event_t.
+ * @param config Selected input configuration .
+ */
+void AOI_GetEventLogicConfig(AOI_Type *base, aoi_event_t event, aoi_event_config_t *config);
+
+/*!
+ * @brief Configures an AOI event.
+ *
+ * This function configures an AOI event according
+ * to the aoiEventConfig structure. This function configures all inputs (A, B, C, and D)
+ * of all product terms (0, 1, 2, and 3) of a desired event.
+ *
+ * Example:
+ @code
+ aoi_event_config_t demoEventLogicStruct;
+
+ demoEventLogicStruct.PT0AC = kAOI_InvInputSignal;
+ demoEventLogicStruct.PT0BC = kAOI_InputSignal;
+ demoEventLogicStruct.PT0CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT0DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT1AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT1BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT2AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT2BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT3AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT3BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3DC = kAOI_LogicOne;
+
+ AOI_SetEventLogicConfig(AOI, kAOI_Event0, demoEventLogicStruct);
+ @endcode
+ *
+ * @param base AOI peripheral address.
+ * @param event Event which will be configured of type aoi_event_t.
+ * @param eventConfig Pointer to type aoi_event_config_t structure. The user is responsible for
+ * filling out the members of this structure and passing the pointer to this function.
+ */
+void AOI_SetEventLogicConfig(AOI_Type *base, aoi_event_t event, const aoi_event_config_t *eventConfig);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*@}*/
+
+/*!* @} */
+
+#endif /* _FSL_AOI_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c
new file mode 100644
index 0000000000..be4f6c1b4d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 2019-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_asrc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.asrc"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief Typedef for asrc tx interrupt handler. */
+typedef void (*asrc_isr_t)(ASRC_Type *base, asrc_handle_t *asrcHandle);
+/*! @brief ASRC support maximum channel number */
+#define ASRC_SUPPORT_MAXIMUM_CHANNEL_NUMER (10U)
+#define ASRC_SAMPLE_RATIO_DECIMAL_DEPTH (26U)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief ASRC read non blocking.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ * @param destAddress dest buffer address.
+ * @param samples number of samples to read.
+ * @param sampleWidth the width that one sample takes.
+ */
+static void ASRC_ReadNonBlocking(
+ ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *destAddress, uint32_t samples, uint32_t sampleWidth);
+
+/*!
+ * @brief ASRC write non blocking.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ * @param srcAddress source buffer address.
+ * @param samples number of samples to read.
+ * @param sampleMask the mask of sample data.
+ * @param sampleWidth the width that one sample takes.
+ */
+static void ASRC_WriteNonBlocking(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ const uint32_t *srcAddress,
+ uint32_t samples,
+ uint32_t sampleMask,
+ uint32_t sampleWidth);
+
+/*!
+ * @brief ASRC calculate divider and prescaler.
+ *
+ * @param sampleRate_Hz sample rate.
+ * @param sourceClock_Hz source clock.
+ */
+static uint32_t ASRC_CalculateClockDivider(uint32_t sampleRate_Hz, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief ASRC pre/post processing selection.
+ *
+ * @param inSampleRate in audio data sample rate.
+ * @param outSampleRate out audio data sample rate.
+ * @param preProc pre processing selection.
+ * @param postProc post precessing selection.
+ */
+static status_t ASRC_ProcessSelection(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t *preProc,
+ uint32_t *postProc);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static ASRC_Type *const s_asrcBases[] = ASRC_BASE_PTRS;
+/*!@brief asrc handle pointer */
+static asrc_handle_t *s_asrcHandle[ARRAY_SIZE(s_asrcBases)][FSL_ASRC_CHANNEL_PAIR_COUNT];
+/* IRQ number array */
+static const IRQn_Type s_asrcIRQ[] = ASRC_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_asrcClock[] = ASRC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to IRQ handler for each instance. */
+static asrc_isr_t s_asrcIsr;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t ASRC_GetInstance(ASRC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_asrcBases); instance++)
+ {
+ if (s_asrcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_asrcBases));
+
+ return instance;
+}
+
+static void ASRC_ReadNonBlocking(
+ ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *destAddress, uint32_t samples, uint32_t sampleWidth)
+{
+ uint32_t i = 0U;
+ uint32_t *destAddr = destAddress;
+ volatile uint32_t *srcAddr = ASRC_ASRDO_ADDR(base, channelPair);
+
+ for (i = 0U; i < samples; i++)
+ {
+ *destAddr = *srcAddr;
+ destAddr = (uint32_t *)((uint32_t)destAddr + sampleWidth);
+ }
+}
+
+static void ASRC_WriteNonBlocking(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ const uint32_t *srcAddress,
+ uint32_t samples,
+ uint32_t sampleMask,
+ uint32_t sampleWidth)
+{
+ uint32_t i = 0U;
+ const uint32_t *srcAddr = srcAddress;
+ volatile uint32_t *destAddr = ASRC_ASRDI_ADDR(base, channelPair);
+
+ for (i = 0U; i < samples; i++)
+ {
+ *destAddr = *srcAddr & sampleMask;
+ srcAddr = (uint32_t *)((uint32_t)srcAddr + sampleWidth);
+ }
+}
+
+static uint32_t ASRC_CalculateClockDivider(uint32_t sampleRate_Hz, uint32_t sourceClock_Hz)
+{
+ assert(sourceClock_Hz >= sampleRate_Hz);
+
+ uint32_t divider = sourceClock_Hz / sampleRate_Hz;
+ uint32_t prescaler = 0U;
+
+ /* sourceClock_Hz = sampleRate_Hz * divider * (2 ^ prescaler) */
+ while (divider > 8U)
+ {
+ divider >>= 1U;
+ prescaler++;
+ }
+ /* Hardware limitation:
+ * If the prescaler is set to 1, the clock divider can only be set to 1 and the clock source must have a 50% duty
+ * cycle
+ */
+ if ((prescaler == 1U) && (divider != 1U))
+ {
+ divider >>= 1U;
+ prescaler++;
+ }
+ /* fine tuning */
+ if (sourceClock_Hz / ((1UL << prescaler) * divider) > sampleRate_Hz)
+ {
+ divider++;
+ }
+
+ return ((divider - 1U) << 3U) | (prescaler & 0x7U);
+}
+
+static status_t ASRC_ProcessSelection(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t *preProc,
+ uint32_t *postProc)
+{
+ bool op2Cond = false;
+ bool op0Cond = false;
+
+ op2Cond = (((inSampleRate * 15U > outSampleRate * 16U) && (outSampleRate < 56000U)) ||
+ ((inSampleRate > 56000U) && (outSampleRate < 56000U)));
+ op0Cond = (inSampleRate * 23U < outSampleRate * 8U);
+
+ /* preProc == 4 or preProc == 5 is not support now */
+ if ((inSampleRate * 8U > 129U * outSampleRate) || ((inSampleRate * 8U > 65U * outSampleRate)))
+ {
+ return kStatus_ASRCNotSupport;
+ }
+
+ if (inSampleRate * 8U > 33U * outSampleRate)
+ {
+ *preProc = 2U;
+ }
+ else if (inSampleRate * 8U > 15U * outSampleRate)
+ {
+ if (inSampleRate > 152000U)
+ {
+ *preProc = 2U;
+ }
+ else
+ {
+ *preProc = 1U;
+ }
+ }
+ else if (inSampleRate < 76000U)
+ {
+ *preProc = 0;
+ }
+ else if (inSampleRate > 152000U)
+ {
+ *preProc = 2;
+ }
+ else
+ {
+ *preProc = 1;
+ }
+
+ if (op2Cond)
+ {
+ *postProc = 2;
+ }
+ else if (op0Cond)
+ {
+ *postProc = 0;
+ }
+ else
+ {
+ *postProc = 1;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Map register sample width to real sample width.
+ *
+ * note This API is depends on the ASRC configuration, should be called after the ASRC_SetChannelPairConfig.
+ * param base asrc base pointer.
+ * param channelPair asrc channel pair index.
+ * param inWidth ASRC channel pair number.
+ * param outWidth input sample rate.
+ * retval input sample mask value.
+ */
+uint32_t ASRC_MapSamplesWidth(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *inWidth, uint32_t *outWidth)
+{
+ uint32_t sampleMask = 0U,
+ inRegWidth = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_IWD_MASK) >> ASRC_ASRMCR1_IWD_SHIFT,
+ outRegWidth = ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_OW16_MASK,
+ inDataAlign = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_IMSB_MASK) >> ASRC_ASRMCR1_IMSB_SHIFT,
+ outDataAlign = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_OMSB_MASK) >> ASRC_ASRMCR1_OMSB_SHIFT;
+ /* get in sample width */
+ if (inRegWidth == (uint32_t)kASRC_DataWidth8Bit)
+ {
+ *inWidth = 1U;
+ sampleMask = 0xFFU;
+ if (inDataAlign == (uint32_t)kASRC_DataAlignMSB)
+ {
+ *inWidth = 2U;
+ sampleMask = 0xFF00U;
+ }
+ }
+ else if (inRegWidth == (uint32_t)kASRC_DataWidth16Bit)
+ {
+ *inWidth = 2U;
+ sampleMask = 0xFFFFU;
+ if (inDataAlign == (uint32_t)kASRC_DataAlignMSB)
+ {
+ *inWidth = 4U;
+ sampleMask = 0xFFFF0000U;
+ }
+ }
+ else
+ {
+ *inWidth = 3U;
+ sampleMask = 0xFFFFFFU;
+
+ if (inDataAlign == (uint32_t)kASRC_DataAlignMSB)
+ {
+ sampleMask = 0xFFFFFF00U;
+ *inWidth = 4U;
+ }
+ }
+ /* get out sample width */
+ if (outRegWidth == (uint32_t)kASRC_DataWidth16Bit)
+ {
+ *outWidth = 2U;
+ if (outDataAlign == (uint32_t)kASRC_DataAlignMSB)
+ {
+ *outWidth = 4U;
+ }
+ }
+ else
+ {
+ *outWidth = 4U;
+ }
+
+ return sampleMask;
+}
+
+/*!
+ * brief ASRC configure ideal ratio.
+ * The ideal ratio should be used when input clock source is not avalible.
+ *
+ * param base ASRC base pointer.
+ * param channelPair ASRC channel pair.
+ * param inputSampleRate input audio data sample rate.
+ * param outputSampleRate output audio data sample rate.
+ */
+status_t ASRC_SetIdealRatioConfig(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate)
+{
+ uint32_t ratio = 0U, i = 0U;
+ uint32_t preProc = 0U, postProc = 0U;
+ uint32_t asrcfg = base->ASRCFG;
+ /* caculate integer part */
+ ratio = (inputSampleRate / outputSampleRate) << ASRC_SAMPLE_RATIO_DECIMAL_DEPTH;
+
+ inputSampleRate %= outputSampleRate;
+ /* get decimal part */
+ for (i = 1U; i <= ASRC_SAMPLE_RATIO_DECIMAL_DEPTH; i++)
+ {
+ inputSampleRate <<= 1;
+
+ if (inputSampleRate < outputSampleRate)
+ {
+ continue;
+ }
+
+ ratio |= 1UL << (ASRC_SAMPLE_RATIO_DECIMAL_DEPTH - i);
+ inputSampleRate -= outputSampleRate;
+
+ if (0U == inputSampleRate)
+ {
+ break;
+ }
+ }
+ /* select pre/post precessing option */
+ if (ASRC_ProcessSelection(inputSampleRate, outputSampleRate, &preProc, &postProc) != kStatus_Success)
+ {
+ return kStatus_ASRCNotSupport;
+ }
+
+ ASRC_IDEAL_RATIO_HIGH(base, channelPair) = ASRC_ASRIDRHA_IDRATIOA_H(ratio >> 24U);
+ ASRC_IDEAL_RATIO_LOW(base, channelPair) = ASRC_ASRIDRLA_IDRATIOA_L(ratio);
+ base->ASRCTR &= ~ASRC_ASRCTR_AT_MASK(channelPair);
+ asrcfg &= ~(ASRC_ASRCFG_PRE_MODE_MASK(channelPair) | ASRC_ASRCFG_POST_MODE_MASK(channelPair));
+ asrcfg |= ASRC_ASRCFG_PRE_MODE(preProc, channelPair) | ASRC_ASRCFG_POST_MODE(postProc, channelPair);
+ base->ASRCFG = asrcfg;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the asrc peripheral.
+ *
+ * This API gates the asrc clock. The asrc module can't operate unless ASRC_Init is called to enable the clock.
+ *
+ * param base asrc base pointer.
+ * param asrcPeripheralClock_Hz peripheral clock of ASRC.
+ */
+void ASRC_Init(ASRC_Type *base, uint32_t asrcPeripheralClock_Hz)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the asrc clock */
+ CLOCK_EnableClock(s_asrcClock[ASRC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* disable ASRC channel pair, enable ASRC */
+ base->ASRCTR = 1U;
+
+ /* disable all the interrupt */
+ base->ASRIER = 0U;
+
+#if (defined FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM) && FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM
+ /* set paramter register to default configurations per recommand value in reference manual */
+ base->ASRPM[0] = 0x7fffffU;
+ base->ASRPM[1] = 0x255555U;
+ base->ASRPM[2] = 0xff7280U;
+ base->ASRPM[3] = 0xff7280U;
+ base->ASRPM[4] = 0xff7280U;
+#else
+ /* set paramter register to default configurations per recommand value in reference manual */
+ base->ASRPMn[0] = 0x7fffffU;
+ base->ASRPMn[1] = 0x255555U;
+ base->ASRPMn[2] = 0xff7280U;
+ base->ASRPMn[3] = 0xff7280U;
+ base->ASRPMn[4] = 0xff7280U;
+#endif /*FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM*/
+ /* set task queue fifo */
+ base->ASRTFR1 = ASRC_ASRTFR1_TF_BASE(0x7C);
+ /* 76K/56K divider */
+ base->ASR76K = ASRC_ASR76K_ASR76K(asrcPeripheralClock_Hz / 76000U);
+ base->ASR56K = ASRC_ASR56K_ASR56K(asrcPeripheralClock_Hz / 56000U);
+}
+
+/*!
+ * brief De-initializes the ASRC peripheral.
+ *
+ * This API gates the ASRC clock and disable ASRC module. The ASRC module can't operate unless ASRC_Init
+ *
+ * param base ASRC base pointer.
+ */
+void ASRC_Deinit(ASRC_Type *base)
+{
+ /* disable ASRC module */
+ ASRC_ModuleEnable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_asrcClock[ASRC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Do software reset .
+ *
+ * This software reset bit is self-clear bit, it will generate a software reset signal inside ASRC.
+ * After 9 cycles of the ASRC processing clock, this reset process will stop and this bit will cleared
+ * automatically.
+ *
+ * param base ASRC base pointer
+ */
+void ASRC_SoftwareReset(ASRC_Type *base)
+{
+ base->ASRCTR |= ASRC_ASRCTR_SRST_MASK;
+ /* polling reset clear automatically */
+ while ((base->ASRCTR & ASRC_ASRCTR_SRST_MASK) != 0U)
+ {
+ }
+}
+
+/*!
+ * brief ASRC configure channel pair.
+ *
+ * param base ASRC base pointer.
+ * param channelPair index of channel pair, reference _asrc_channel_pair.
+ * param config ASRC channel pair configuration pointer.
+ * param inputSampleRate in audio data sample rate.
+ * param outSampleRate out audio data sample rate.
+ */
+status_t ASRC_SetChannelPairConfig(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ asrc_channel_pair_config_t *config,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate)
+{
+ assert(config != NULL);
+
+ if (config->outDataWidth == kASRC_DataWidth8Bit)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (((inputSampleRate < (uint32_t)kASRC_SampleRate_8000HZ) ||
+ (inputSampleRate > (uint32_t)kASRC_SampleRate_192000HZ)) ||
+ ((outputSampleRate < (uint32_t)kASRC_SampleRate_8000HZ) ||
+ (outputSampleRate > (uint32_t)kASRC_SampleRate_192000HZ)) ||
+ (((outputSampleRate > (uint32_t)kASRC_SampleRate_8000HZ) &&
+ (outputSampleRate < (uint32_t)kASRC_SampleRate_30000HZ)) &&
+ (inputSampleRate / outputSampleRate > 8U || outputSampleRate / inputSampleRate > 24U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t i = 0U;
+ /* channel pair processing selection and ratio configuration */
+ uint32_t asrctr = base->ASRCTR & (~(ASRC_ASRCTR_AT_MASK(channelPair) | ASRC_ASRCTR_RATIO_MASK(channelPair)));
+ /* use automatic selection for processing option by default */
+ asrctr |= ASRC_ASRCTR_AT_MASK(channelPair);
+ /* ratio configuration */
+ asrctr |= ASRC_ASRCTR_RATIO(config->sampleRateRatio, channelPair);
+ base->ASRCTR = asrctr;
+
+ /* audio data channel counter configurations */
+ uint32_t asrcncr = base->ASRCNCR & (~ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(channelPair));
+ base->ASRCNCR = asrcncr | ASRC_ASRCNCR_CHANNEL_COUNTER(config->audioDataChannels, channelPair);
+
+ /* in clock source and out clock source configurations */
+ uint32_t asrcsr =
+ base->ASRCSR &
+ (~(ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(channelPair) | ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(channelPair)));
+ asrcsr |= ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE(config->outClockSource, channelPair);
+ if (config->inClockSource != kASRC_ClockSourceNotAvalible)
+ {
+ asrcsr |= ASRC_ASRCSR_INPUT_CLOCK_SOURCE(config->inClockSource, channelPair);
+ }
+ base->ASRCSR = asrcsr;
+
+ /* clock divider configuration */
+ uint32_t asrcdr =
+ base->ASRCDR1 &
+ (~(ASRC_ASRCDR_INPUT_PRESCALER_MASK(channelPair) | ASRC_ASRCDR_INPUT_DIVIDER_MASK(channelPair) |
+ ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(channelPair) | ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(channelPair)));
+
+ asrcdr |= ASCR_ASRCDR_OUTPUT_CLOCK_DIVIDER_PRESCALER(
+ ASRC_CalculateClockDivider(outputSampleRate, config->outSourceClock_Hz), channelPair);
+ if (config->inClockSource != kASRC_ClockSourceNotAvalible)
+ {
+ asrcdr |= ASCR_ASRCDR_INPUT_CLOCK_DIVIDER_PRESCALER(
+ ASRC_CalculateClockDivider(inputSampleRate, config->inSourceClock_Hz), channelPair);
+ }
+
+ if (channelPair == kASRC_ChannelPairC)
+ {
+ base->ASRCDR2 = asrcdr;
+ }
+ else
+ {
+ base->ASRCDR1 = asrcdr;
+ }
+
+ /* data width/sign extension/data align configuration */
+ ASRC_ASRMCR1(base, channelPair) = ASRC_ASRMCR1_OW16(config->outDataWidth) | ASRC_ASRMCR1_IWD(config->inDataWidth) |
+ ASRC_ASRMCR1_OSGN(config->outSignExtension) |
+ ASRC_ASRMCR1_OMSB(config->outDataAlign) | ASRC_ASRMCR1_IMSB(config->inDataAlign);
+ /* data configurations, MISC */
+ uint32_t asrmcra = ASRC_ASRMCR(base, channelPair) &
+ (~(ASRC_ASRMCRA_BUFSTALLA_MASK | ASRC_ASRMCRA_EXTTHRSHA_MASK |
+ ASRC_ASRMCRA_INFIFO_THRESHOLDA_MASK | ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_MASK));
+ /* buffer stall */
+ asrmcra |= ASRC_ASRMCRA_BUFSTALLA(config->bufStallWhenFifoEmptyFull);
+ /* in fifo and out fifo threshold */
+ asrmcra |= ASRC_ASRMCRA_EXTTHRSHA_MASK | ASRC_ASRMCRA_INFIFO_THRESHOLDA(config->inFifoThreshold - 1UL) |
+ ASRC_ASRMCRA_OUTFIFO_THRESHOLDA(config->outFifoThreshold - 1UL);
+ ASRC_ASRMCR(base, channelPair) = asrmcra;
+
+ if (config->sampleRateRatio == kASRC_RatioUseIdealRatio)
+ {
+ if (ASRC_SetIdealRatioConfig(base, channelPair, inputSampleRate, outputSampleRate) != kStatus_Success)
+ {
+ return kStatus_ASRCChannelPairConfigureFailed;
+ }
+ }
+
+ /* channel pair enable */
+ ASRC_ChannelPairEnable(base, channelPair, true);
+
+ /* wait channel initial served */
+ while (!ASRC_GetChannelPairInitialStatus(base, channelPair))
+ {
+ }
+
+ for (i = 0U; i < (uint32_t)config->audioDataChannels * 4U; i++)
+ {
+ ASRC_ChannelPairWriteData(base, channelPair, 0U);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get output sample buffer size.
+ *
+ * note This API is depends on the ASRC output configuration, should be called after the ASRC_SetChannelPairConfig.
+ *
+ * param base asrc base pointer.
+ * param channelPair ASRC channel pair number.
+ * param inSampleRate input sample rate.
+ * param outSampleRate output sample rate.
+ * param inSamples input sampleS size.
+ * retval output buffer size in byte.
+ */
+uint32_t ASRC_GetOutSamplesSize(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t inSamplesize)
+{
+ uint32_t inSamples = 0U;
+ uint32_t outSamples = 0U;
+ uint32_t outSamplesBufSize = 0U, audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair);
+ ;
+ asrc_data_width_t outWdith = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OW16_MASK) == ASRC_ASRMCR1_OW16_MASK ?
+ kASRC_DataWidth16Bit :
+ kASRC_DataWidth24Bit;
+ asrc_data_align_t outAlign = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OMSB_MASK) == ASRC_ASRMCR1_OMSB_MASK ?
+ kASRC_DataAlignMSB :
+ kASRC_DataAlignLSB;
+ uint32_t inWdith = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_IWD_MASK) >> ASRC_ASRMCR1_IWD_SHIFT;
+ asrc_data_align_t inAlign = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_IMSB_MASK) == ASRC_ASRMCR1_IMSB_MASK ?
+ kASRC_DataAlignMSB :
+ kASRC_DataAlignLSB;
+
+ bool signExtend = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OSGN_MASK) == ASRC_ASRMCR1_OSGN_MASK ? true : false;
+
+ /* 24bit input data */
+ if (inWdith == 0U)
+ {
+ inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 4U : 3U);
+ }
+ /* 16bit input data */
+ else if (inWdith == 1U)
+ {
+ inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 4U : 2U);
+ }
+ /* 8bit input data */
+ else
+ {
+ inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 2U : 1U);
+ }
+
+ outSamples = (uint32_t)((uint64_t)inSamples * outSampleRate / inSampleRate);
+ /* make sure output samples is in group */
+ outSamples = outSamples - outSamples % audioChannels;
+
+ if (outWdith == kASRC_DataWidth16Bit)
+ {
+ if ((outAlign == kASRC_DataAlignMSB) || signExtend)
+ {
+ outSamplesBufSize = outSamples * 4U;
+ }
+ else
+ {
+ outSamplesBufSize = outSamples * 2U;
+ }
+ }
+
+ if (outWdith == kASRC_DataWidth24Bit)
+ {
+ outSamplesBufSize = outSamples * 4U;
+ }
+
+ return outSamplesBufSize;
+}
+
+/*!
+ * brief Performs an blocking convert on asrc.
+ *
+ * note This API returns immediately after the convert finished.
+ *
+ * param base asrc base pointer.
+ * param channelPair channel pair index.
+ * param xfer Pointer to the ASRC_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ */
+status_t ASRC_TransferBlocking(ASRC_Type *base, asrc_channel_pair_t channelPair, asrc_transfer_t *xfer)
+{
+ assert(xfer != NULL);
+
+ uint32_t inWaterMark = ASRC_ASRMCR(base, channelPair) & ASRC_ASRMCRA_INFIFO_THRESHOLDA_MASK,
+ outWaterMark = (ASRC_ASRMCR(base, channelPair) & ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_MASK) >>
+ ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_SHIFT,
+ audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair);
+ uint8_t *inAddr = (uint8_t *)xfer->inData, *outAddr = (uint8_t *)xfer->outData;
+ uint32_t onceWriteSamples = 0U;
+ uint32_t status = 0U, inSampleMask = 0U, inSamples = 0U, outSamples = 0U, inWidth = 0U, outWidth = 0U;
+
+ inSampleMask = ASRC_MapSamplesWidth(base, channelPair, &inWidth, &outWidth);
+ inSamples = xfer->inDataSize / inWidth;
+ outSamples = xfer->outDataSize / outWidth;
+ inWaterMark *= audioChannels;
+ outWaterMark *= audioChannels;
+
+ while (outSamples != 0U)
+ {
+ status = ASRC_GetStatus(base);
+
+ if ((status & ((uint32_t)kASRC_StatusPairCInputReady | (uint32_t)kASRC_StatusPairBInputReady |
+ (uint32_t)kASRC_StatusPairAInputReady)) != 0U)
+ {
+ onceWriteSamples =
+ MIN(inSamples, (size_t)((FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH * audioChannels - inWaterMark)));
+ ASRC_WriteNonBlocking(base, channelPair, (uint32_t *)(uint32_t)inAddr, onceWriteSamples, inSampleMask,
+ inWidth);
+ inAddr = (uint8_t *)((uint32_t)inAddr + onceWriteSamples * inWidth);
+ inSamples -= onceWriteSamples;
+ }
+
+ if (outSamples > outWaterMark)
+ {
+ if ((status & ((uint32_t)kASRC_StatusPairCOutputReady | (uint32_t)kASRC_StatusPairAOutputReady |
+ (uint32_t)kASRC_StatusPairBOutputReady)) != 0U)
+ {
+ ASRC_ReadNonBlocking(base, channelPair, (uint32_t *)(uint32_t)outAddr, outWaterMark, outWidth);
+ outAddr = (uint8_t *)((uint32_t)outAddr + outWaterMark * outWidth);
+ outSamples -= outWaterMark;
+ }
+ }
+ else
+ {
+ outSamples -=
+ ASRC_GetRemainFifoSamples(base, channelPair, (uint32_t *)(uint32_t)outAddr, outWidth, outSamples);
+ continue;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief ASRC configure channel pair.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC transactional handle pointer.
+ * param config ASRC channel pair configuration pointer.
+ * param inputSampleRate in audio data sample rate.
+ * param outputSampleRate out audio data sample rate.
+ */
+status_t ASRC_TransferSetChannelPairConfig(ASRC_Type *base,
+ asrc_handle_t *handle,
+ asrc_channel_pair_config_t *config,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate)
+{
+ assert(handle != NULL);
+
+ handle->in.fifoThreshold = config->inFifoThreshold * (uint32_t)config->audioDataChannels;
+ handle->out.fifoThreshold = config->outFifoThreshold * (uint32_t)config->audioDataChannels;
+ handle->audioDataChannels = config->audioDataChannels;
+
+ if (ASRC_SetChannelPairConfig(base, handle->channelPair, config, inputSampleRate, outputSampleRate) !=
+ kStatus_Success)
+ {
+ return kStatus_ASRCChannelPairConfigureFailed;
+ }
+
+ handle->in.sampleMask =
+ ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get left samples in fifo.
+ *
+ * param base asrc base pointer.
+ * param channelPair ASRC channel pair number.
+ * param buffer input sample numbers.
+ * param outSampleWidth output sample width.
+ * param remainSamples output sample rate.
+ * retval remain samples number.
+ */
+uint32_t ASRC_GetRemainFifoSamples(
+ ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *buffer, uint32_t outSampleWidth, uint32_t remainSamples)
+{
+ uint32_t remainSamplesInFifo = 0U;
+ uint32_t audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair);
+ remainSamplesInFifo =
+ ((ASRC_ASRFST_ADDR(base, channelPair) & ASRC_ASRFSTA_OUTFIFO_FILLA_MASK) >> ASRC_ASRFSTA_OUTFIFO_FILLA_SHIFT) *
+ audioChannels;
+
+ if (remainSamples < remainSamplesInFifo)
+ {
+ remainSamplesInFifo = remainSamples;
+ }
+
+ ASRC_ReadNonBlocking(base, channelPair, (uint32_t *)buffer, remainSamplesInFifo, outSampleWidth);
+
+ return remainSamplesInFifo;
+}
+
+/*!
+ * brief Initializes the ASRC handle.
+ *
+ * This function initializes the handle for the ASRC transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base ASRC base pointer
+ * param handle ASRC handle pointer.
+ * param inCallback Pointer to the user callback function.
+ * param outCallback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void ASRC_TransferCreateHandle(ASRC_Type *base,
+ asrc_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_transfer_callback_t inCallback,
+ asrc_transfer_callback_t outCallback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ uint32_t instance = ASRC_GetInstance(base);
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_asrcHandle[instance][channelPair] = handle;
+
+ handle->in.callback = inCallback;
+ handle->out.callback = outCallback;
+ handle->userData = userData;
+ handle->channelPair = channelPair;
+ /* Set the isr pointer */
+ s_asrcIsr = ASRC_TransferHandleIRQ;
+
+ (void)EnableIRQ(s_asrcIRQ[instance]);
+}
+
+/*!
+ * brief Performs an interrupt non-blocking convert on asrc.
+ *
+ * note This API returns immediately after the transfer initiates, application should check the wait and check the
+ * callback status.
+ *
+ * param base asrc base pointer.
+ * param handle Pointer to the asrc_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the ASRC_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_ASRCBusy Previous receive still not finished.
+ */
+status_t ASRC_TransferNonBlocking(ASRC_Type *base, asrc_handle_t *handle, asrc_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ /* Check if the queue is full */
+ if ((handle->in.asrcQueue[handle->in.queueUser] != NULL) || (handle->out.asrcQueue[handle->out.queueUser] != NULL))
+ {
+ return kStatus_ASRCBusy;
+ }
+
+ /* Add into queue */
+ handle->in.transferSamples[handle->in.queueUser] = xfer->inDataSize / handle->in.sampleWidth;
+ handle->in.asrcQueue[handle->in.queueUser] = xfer->inData;
+ handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_QUEUE_SIZE;
+
+ handle->out.asrcQueue[handle->out.queueUser] = xfer->outData;
+ handle->out.transferSamples[handle->out.queueUser] = xfer->outDataSize / handle->out.sampleWidth;
+ handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_QUEUE_SIZE;
+
+ if (handle->state != (uint32_t)kStatus_ASRCBusy)
+ {
+ /* enable channel pair interrupt */
+ ASRC_EnableInterrupt(base, ASRC_ASRIER_INPUT_INTERRUPT_MASK(handle->channelPair) |
+ (uint32_t)kASRC_OverLoadInterruptMask |
+ ASRC_ASRIER_OUTPUTPUT_INTERRUPT_MASK(handle->channelPair));
+ }
+
+ /* Set the state to busy */
+ handle->state = kStatus_ASRCBusy;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base asrc base pointer.
+ * param handle Pointer to the ASRC_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t ASRC_TransferGetConvertedCount(ASRC_Type *base, asrc_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kStatus_ASRCBusy)
+ {
+ status = kStatus_ASRCIdle;
+ }
+ else
+ {
+ *count = handle->out.transferSamples[handle->out.queueDriver];
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current convert.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base asrc base pointer.
+ * param handle Pointer to the ASRC_handle_t structure which stores the transfer state.
+ */
+void ASRC_TransferAbortConvert(ASRC_Type *base, asrc_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* enable ASRC module */
+ ASRC_ModuleEnable(base, false);
+
+ handle->state = kStatus_ASRCIdle;
+
+ handle->in.queueDriver = 0;
+ handle->in.queueUser = 0;
+ handle->out.queueDriver = 0;
+ handle->out.queueUser = 0;
+}
+
+/*!
+ * brief Terminate all asrc convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortSend.
+ *
+ * param base asrc base pointer.
+ * param handle asrc eDMA handle pointer.
+ */
+void ASRC_TransferTerminateConvert(ASRC_Type *base, asrc_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ ASRC_TransferAbortConvert(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue));
+ (void)memset(handle->in.transferSamples, 0, sizeof(handle->in.transferSamples));
+ (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue));
+ (void)memset(handle->out.transferSamples, 0, sizeof(handle->out.transferSamples));
+}
+
+/*!
+ * brief ASRC convert interrupt handler.
+ *
+ * param base asrc base pointer.
+ * param handle Pointer to the asrc_handle_t structure.
+ */
+void ASRC_TransferHandleIRQ(ASRC_Type *base, asrc_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t status = base->ASRSTR;
+
+ /* Handle Error */
+ if ((status & (uint32_t)kASRC_StatusInputError) != 0U)
+ {
+ /* Call the callback */
+ if (handle->in.callback != NULL)
+ {
+ (handle->in.callback)(base, handle, kStatus_ASRCConvertError, handle->userData);
+ }
+ }
+
+ if ((status & (uint32_t)kASRC_StatusOutputError) != 0U)
+ {
+ /* Call the callback */
+ if (handle->out.callback != NULL)
+ {
+ (handle->out.callback)(base, handle, kStatus_ASRCConvertError, handle->userData);
+ }
+ }
+
+ /* Handle transfer */
+ if ((status & ((uint32_t)kASRC_StatusPairCOutputReady | (uint32_t)kASRC_StatusPairAOutputReady |
+ (uint32_t)kASRC_StatusPairBOutputReady)) != 0U)
+ {
+ if (handle->out.transferSamples[handle->out.queueDriver] != 0U)
+ {
+ ASRC_ReadNonBlocking(base, handle->channelPair,
+ (uint32_t *)(uint32_t)handle->out.asrcQueue[handle->out.queueDriver],
+ handle->out.fifoThreshold, handle->out.sampleWidth);
+ handle->out.transferSamples[handle->out.queueDriver] -= handle->out.fifoThreshold;
+ handle->out.asrcQueue[handle->out.queueDriver] =
+ (uint8_t *)((uint32_t)handle->out.asrcQueue[handle->out.queueDriver] +
+ handle->out.fifoThreshold * handle->out.sampleWidth);
+ }
+ }
+
+ if ((status & ((uint32_t)kASRC_StatusPairCInputReady | (uint32_t)kASRC_StatusPairBInputReady |
+ (uint32_t)kASRC_StatusPairAInputReady)) != 0U)
+ {
+ /* Judge if the data need to transmit is less than space */
+ uint32_t size = MIN((handle->in.transferSamples[handle->in.queueDriver]),
+ (size_t)((FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH * (uint32_t)handle->audioDataChannels -
+ handle->in.fifoThreshold)));
+ ASRC_WriteNonBlocking(base, handle->channelPair,
+ (uint32_t *)(uint32_t)handle->in.asrcQueue[handle->in.queueDriver], size,
+ handle->in.sampleMask, handle->in.sampleWidth);
+ handle->in.transferSamples[handle->in.queueDriver] -= size;
+ handle->in.asrcQueue[handle->in.queueDriver] =
+ (uint8_t *)((uint32_t)handle->in.asrcQueue[handle->in.queueDriver] + size * handle->in.sampleWidth);
+ }
+
+ /* If finished a block, call the callback function */
+ if (handle->in.transferSamples[handle->in.queueDriver] == 0U)
+ {
+ handle->in.asrcQueue[handle->in.queueDriver] = NULL;
+ handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
+ if (handle->in.callback != NULL)
+ {
+ (handle->in.callback)(base, handle, kStatus_ASRCIdle, handle->userData);
+ }
+ }
+
+ if (handle->out.transferSamples[handle->out.queueDriver] < (handle->out.fifoThreshold + 1U))
+ {
+ handle->out.transferSamples[handle->out.queueDriver] -= ASRC_GetRemainFifoSamples(
+ base, handle->channelPair, (uint32_t *)(uint32_t)handle->out.asrcQueue[handle->out.queueDriver],
+ handle->out.sampleWidth, handle->out.transferSamples[handle->out.queueDriver]);
+ }
+
+ if (handle->out.transferSamples[handle->out.queueDriver] == 0U)
+ {
+ handle->out.asrcQueue[handle->out.queueDriver] = NULL;
+ handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
+ if (handle->out.callback != NULL)
+ {
+ (handle->out.callback)(base, handle, kStatus_ASRCIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->out.asrcQueue[handle->out.queueDriver] == NULL)
+ {
+ ASRC_TransferAbortConvert(base, handle);
+ }
+}
+
+#if defined ASRC
+void ASRC_DriverIRQHandler(void);
+void ASRC_DriverIRQHandler(void)
+{
+ /* channel PAIR A interrupt handling*/
+ if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairAInterrupt) != 0U)
+ {
+ s_asrcIsr(ASRC, s_asrcHandle[0][0U]);
+ }
+ /* channel PAIR B interrupt handling*/
+ if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairBInterrupt) != 0U)
+ {
+ s_asrcIsr(ASRC, s_asrcHandle[0][1U]);
+ }
+ /* channel PAIR C interrupt handling*/
+ if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairCInterrupt) != 0U)
+ {
+ s_asrcIsr(ASRC, s_asrcHandle[0][2U]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ASRC */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h
new file mode 100644
index 0000000000..e4f8ce384a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h
@@ -0,0 +1,761 @@
+/*
+ * Copyright 2019-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ASRC_H_
+#define _FSL_ASRC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup asrc_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_ASRC_DRIVER_VERSION (MAKE_VERSION(2, 1, 2)) /*!< Version 2.1.2 */
+/*@}*/
+
+#ifndef ASRC_XFER_QUEUE_SIZE
+/*!@brief ASRC transfer queue size, user can refine it according to use case. */
+#define ASRC_XFER_QUEUE_SIZE (4U)
+#endif
+/*!@brief ASRC channel pair count */
+#define FSL_ASRC_CHANNEL_PAIR_COUNT (4U)
+/*! @brief ASRC FIFO depth */
+#define FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH (64U)
+
+/*! @brief ASRC register access macro */
+#define ASRC_ASRCTR_AT_MASK(index) ((uint32_t)1U << (ASRC_ASRCTR_ATSA_SHIFT + (uint32_t)(index)))
+#define ASRC_ASRCTR_RATIO_MASK(index) ((uint32_t)3U << (ASRC_ASRCTR_IDRA_SHIFT + (uint32_t)(index)*2U))
+#define ASRC_ASRCTR_RATIO(ratio, index) \
+ (((uint32_t)((uint32_t)(ratio) << (ASRC_ASRCTR_IDRA_SHIFT + (uint32_t)(index)*2U))) & ASRC_ASRCTR_RATIO_MASK(index))
+#define ASRC_ASRIER_INPUT_INTERRUPT_MASK(index) ((uint32_t)1U << (ASRC_ASRIER_ADIEA_SHIFT + (uint32_t)(index)))
+#define ASRC_ASRIER_OUTPUTPUT_INTERRUPT_MASK(index) ((uint32_t)1U << (ASRC_ASRIER_ADOEA_SHIFT + (uint32_t)(index)))
+#define ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCNCR_ANCA_SHIFT + (uint32_t)(index)*4U))
+#define ASRC_ASRCNCR_CHANNEL_COUNTER(counter, index) \
+ ((uint32_t)((uint32_t)(counter) << (ASRC_ASRCNCR_ANCA_SHIFT + (uint32_t)(index)*4U)) & \
+ ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(index))
+#define ASRC_ASRCFG_PRE_MODE_MASK(index) ((uint32_t)3U << (ASRC_ASRCFG_PREMODA_SHIFT + (uint32_t)(index)*4U))
+#define ASRC_ASRCFG_PRE_MODE(mode, index) \
+ ((uint32_t)((uint32_t)(mode) << (ASRC_ASRCFG_PREMODA_SHIFT + (uint32_t)(index)*4U)) & \
+ ASRC_ASRCFG_PRE_MODE_MASK(index))
+#define ASRC_ASRCFG_POST_MODE_MASK(index) ((uint32_t)3U << (ASRC_ASRCFG_POSTMODA_SHIFT + (uint32_t)(index)*4U))
+#define ASRC_ASRCFG_POST_MODE(mode, index) \
+ ((uint32_t)((uint32_t)(mode) << (ASRC_ASRCFG_POSTMODA_SHIFT + (uint32_t)(index)*4U)) & \
+ ASRC_ASRCFG_POST_MODE_MASK(index))
+#define ASRC_ASRCFG_INIT_DONE_MASK(index) ((uint32_t)1U << (ASRC_ASRCFG_INIRQA_SHIFT + (uint32_t)(index)))
+#define ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCSR_AICSA_SHIFT + (uint32_t)(index)*4U))
+#define ASRC_ASRCSR_INPUT_CLOCK_SOURCE(source, index) \
+ ((uint32_t)((uint32_t)(source) << (ASRC_ASRCSR_AICSA_SHIFT + (uint32_t)(index)*4U)) & \
+ ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(index))
+#define ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCSR_AOCSA_SHIFT + (uint32_t)(index)*4U))
+#define ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE(source, index) \
+ ((uint32_t)((uint32_t)(source) << (ASRC_ASRCSR_AOCSA_SHIFT + (uint32_t)(index)*4U)) & \
+ ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(index))
+
+#define ASRC_ASRCDR_INPUT_PRESCALER_MASK(index) \
+ ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AICPA_SHIFT + (uint32_t)(index)*6U)) : 7U)
+#define ASRC_ASRCDR_INPUT_PRESCALER(prescaler, index) \
+ (((index) < 2U ? ((uint32_t)(prescaler) << (ASRC_ASRCDR1_AICPA_SHIFT + (uint32_t)(index)*6U)) : (prescaler)) & \
+ ASRC_ASRCDR1_INPUT_PRESCALER_MASK(index))
+#define ASRC_ASRCDR_INPUT_DIVIDER_MASK(index) \
+ ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AICDA_SHIFT + (uint32_t)(index)*6U)) : \
+ (7U << ASRC_ASRCDR1_AICDA_SHIFT))
+#define ASRC_ASRCDR_INPUT_DIVIDER(divider, index) \
+ (((uint32_t)(index) < 2U ? ((uint32_t)(divider) << (ASRC_ASRCDR1_AICDA_SHIFT + (uint32_t)(index)*6U)) : \
+ ((uint32_t)(divider) << ASRC_ASRCDR1_AICDA_SHIFT)) & \
+ ASRC_ASRCDR_INPUT_DIVIDER_MASK(index))
+#define ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(index) \
+ ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : (7U << 6U))
+#define ASRC_ASRCDR_OUTPUT_PRESCALER(prescaler, index) \
+ (((uint32_t)(index) < 2U ? ((uint32_t)(prescaler) << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : \
+ ((uint32_t)(prescaler) << 6U)) & \
+ ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(index))
+#define ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(index) \
+ ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AOCDA_SHIFT + (uint32_t)(index)*6U)) : (7UL << 9U))
+#define ASRC_ASRCDR_OUTPUT_DIVIDER(divider, index) \
+ (((uint32_t)(index) < 2U ? ((uint32_t)(divider) << (ASRC_ASRCDR1_AOCDA_SHIFT + (uint32_t)(index)*6U)) : \
+ ((uint32_t)(divider) << 9U)) & \
+ ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(index))
+
+#define ASCR_ASRCDR_OUTPUT_CLOCK_DIVIDER_PRESCALER(value, index) \
+ (((uint32_t)(index) < 2U ? ((uint32_t)(value) << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : \
+ ((uint32_t)(value) << 6U)))
+#define ASCR_ASRCDR_INPUT_CLOCK_DIVIDER_PRESCALER(value, index) \
+ (((uint32_t)(index) < 2U ? ((uint32_t)(value) << ((uint32_t)(index)*6U)) : ((uint32_t)(value))))
+
+#define ASRC_IDEAL_RATIO_HIGH(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRIDRHA) + (uint32_t)(index)*8U)
+#define ASRC_IDEAL_RATIO_LOW(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRIDRLA) + (uint32_t)(index)*8U)
+#define ASRC_ASRMCR(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRMCRA) + (uint32_t)(index)*8U)
+#define ASRC_ASRMCR1(base, index) *(volatile uint32_t *)((uint32_t)(&((base)->ASRMCR1[(index)])))
+#define ASRC_ASRDI(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRDIA) + (uint32_t)(index)*8U)
+#define ASRC_ASRDO(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRDOA) + (uint32_t)(index)*8U)
+#define ASRC_ASRDI_ADDR(base, index) (volatile uint32_t *)((uint32_t)(&(base)->ASRDIA) + (uint32_t)(index)*8U)
+#define ASRC_ASRDO_ADDR(base, index) (volatile uint32_t *)((uint32_t)(&(base)->ASRDOA) + (uint32_t)(index)*8U)
+#define ASRC_ASRFST_ADDR(base, index) (*(volatile uint32_t *)((uint32_t)(&(base)->ASRFSTA) + (uint32_t)(index)*8U))
+#define ASRC_GET_CHANNEL_COUNTER(base, index) (((base)->ASRCNCR >> ((uint32_t)(index)*4U)) & 0xFU)
+
+/*! @brief ASRC return status
+ * @anchor _asrc_status_t
+ */
+enum
+{
+ kStatus_ASRCIdle = MAKE_STATUS(kStatusGroup_ASRC, 0), /*!< ASRC is idle. */
+ kStatus_ASRCInIdle = MAKE_STATUS(kStatusGroup_ASRC, 1), /*!< ASRC in is idle. */
+ kStatus_ASRCOutIdle = MAKE_STATUS(kStatusGroup_ASRC, 2), /*!< ASRC out is idle. */
+ kStatus_ASRCBusy = MAKE_STATUS(kStatusGroup_ASRC, 3), /*!< ASRC is busy. */
+ kStatus_ASRCInvalidArgument = MAKE_STATUS(kStatusGroup_ASRC, 4), /*!< ASRC invalid argument. */
+ kStatus_ASRCClockConfigureFailed = MAKE_STATUS(kStatusGroup_ASRC, 5), /*!< ASRC clock configure failed */
+ kStatus_ASRCChannelPairConfigureFailed = MAKE_STATUS(kStatusGroup_ASRC, 6), /*!< ASRC clock configure failed */
+ kStatus_ASRCConvertError = MAKE_STATUS(kStatusGroup_ASRC, 7), /*!< ASRC clock configure failed */
+ kStatus_ASRCNotSupport = MAKE_STATUS(kStatusGroup_ASRC, 8), /*!< ASRC not support */
+ kStatus_ASRCQueueFull = MAKE_STATUS(kStatusGroup_ASRC, 9), /*!< ASRC queue is full */
+ kStatus_ASRCOutQueueIdle = MAKE_STATUS(kStatusGroup_ASRC, 10), /*!< ASRC out queue is idle */
+ kStatus_ASRCInQueueIdle = MAKE_STATUS(kStatusGroup_ASRC, 11), /*!< ASRC in queue is idle */
+};
+
+/*! @brief ASRC channel pair mask */
+typedef enum _asrc_channel_pair
+{
+ kASRC_ChannelPairA = 0, /*!< channel pair A value */
+ kASRC_ChannelPairB = 1, /*!< channel pair B value */
+ kASRC_ChannelPairC = 2, /*!< channel pair C value */
+} asrc_channel_pair_t;
+
+/*! @brief ASRC support sample rate
+ * @anchor _asrc_sample_rate
+ */
+enum
+{
+ kASRC_SampleRate_8000HZ = 8000U, /*!< asrc sample rate 8KHZ */
+ kASRC_SampleRate_11025HZ = 11025U, /*!< asrc sample rate 11.025KHZ */
+ kASRC_SampleRate_12000HZ = 12000U, /*!< asrc sample rate 12KHZ */
+ kASRC_SampleRate_16000HZ = 16000U, /*!< asrc sample rate 16KHZ */
+ kASRC_SampleRate_22050HZ = 22050U, /*!< asrc sample rate 22.05KHZ */
+ kASRC_SampleRate_24000HZ = 24000U, /*!< asrc sample rate 24KHZ */
+ kASRC_SampleRate_30000HZ = 30000U, /*!< asrc sample rate 30KHZ */
+ kASRC_SampleRate_32000HZ = 32000U, /*!< asrc sample rate 32KHZ */
+ kASRC_SampleRate_44100HZ = 44100U, /*!< asrc sample rate 44.1KHZ */
+ kASRC_SampleRate_48000HZ = 48000U, /*!< asrc sample rate 48KHZ */
+ kASRC_SampleRate_64000HZ = 64000U, /*!< asrc sample rate 64KHZ */
+ kASRC_SampleRate_88200HZ = 88200U, /*!< asrc sample rate 88.2KHZ */
+ kASRC_SampleRate_96000HZ = 96000U, /*!< asrc sample rate 96KHZ */
+ kASRC_SampleRate_128000HZ = 128000U, /*!< asrc sample rate 128KHZ */
+ kASRC_SampleRate_176400HZ = 176400U, /*!< asrc sample rate 176.4KHZ */
+ kASRC_SampleRate_192000HZ = 192000U, /*!< asrc sample rate 192KHZ */
+};
+
+/*! @brief The ASRC interrupt enable flag
+ * @anchor _asrc_interrupt_mask
+ */
+enum
+{
+ kASRC_FPInWaitStateInterruptEnable = ASRC_ASRIER_AFPWE_MASK, /*!< FP in wait state mask */
+ kASRC_OverLoadInterruptMask = ASRC_ASRIER_AOLIE_MASK, /*!< overload interrupt mask */
+ kASRC_DataOutputCInterruptMask = ASRC_ASRIER_ADOEC_MASK, /*!< data output c interrupt mask */
+ kASRC_DataOutputBInterruptMask = ASRC_ASRIER_ADOEB_MASK, /*!< data output b interrupt mask */
+ kASRC_DataOutputAInterruptMask = ASRC_ASRIER_ADOEA_MASK, /*!< data output a interrupt mask */
+ kASRC_DataInputCInterruptMask = ASRC_ASRIER_ADIEC_MASK, /*!< data input c interrupt mask */
+ kASRC_DataInputBInterruptMask = ASRC_ASRIER_ADIEB_MASK, /*!< data input b interrupt mask */
+ kASRC_DataInputAInterruptMask = ASRC_ASRIER_ADIEA_MASK, /*!< data input a interrupt mask */
+};
+
+/*! @brief The ASRC interrupt status
+ * @anchor _asrc_interrupt_status
+ */
+enum
+{
+ kASRC_StatusDSLCounterReady = ASRC_ASRSTR_DSLCNT_MASK, /*!< DSL counter */
+ kASRC_StatusTaskQueueOverLoad = ASRC_ASRSTR_ATQOL_MASK, /*!< task queue overload */
+ kASRC_StatusPairCOutputOverLoad = ASRC_ASRSTR_AOOLC_MASK, /*!< pair c output overload */
+ kASRC_StatusPairBOutputOverLoad = ASRC_ASRSTR_AOOLB_MASK, /*!< pair b output overload */
+ kASRC_StatusPairAOutputOverLoad = ASRC_ASRSTR_AOOLA_MASK, /*!< pair a output overload */
+ kASRC_StatusPairCInputOverLoad = ASRC_ASRSTR_AIOLC_MASK, /*!< pair c input overload */
+ kASRC_StatusPairBInputOverLoad = ASRC_ASRSTR_AIOLB_MASK, /*!<pair b input overload */
+ kASRC_StatusPairAInputOverLoad = ASRC_ASRSTR_AIOLA_MASK, /*!< pair a input overload */
+ kASRC_StatusPairCOutputOverflow = ASRC_ASRSTR_AODOC_MASK, /*!< pair c output overflow */
+ kASRC_StatusPairBOutputOverflow = ASRC_ASRSTR_AODOB_MASK, /*!< pair b output overflow */
+ kASRC_StatusPairAOutputOverflow = ASRC_ASRSTR_AODOA_MASK, /*!< pair a output overflow */
+ kASRC_StatusPairCInputUnderflow = ASRC_ASRSTR_AIDUC_MASK, /*!< pair c input underflow*/
+ kASRC_StatusPairBInputUnderflow = ASRC_ASRSTR_AIDUB_MASK, /*!< pair b input under flow */
+ kASRC_StatusPairAInputUnderflow = ASRC_ASRSTR_AIDUA_MASK, /*!< pair a input underflow*/
+ kASRC_StatusFPInWaitState = ASRC_ASRSTR_FPWT_MASK, /*!< FP in wait state */
+ kASRC_StatusOverloadError = ASRC_ASRSTR_AOLE_MASK, /*!< overload error */
+
+ kASRC_StatusInputError = kASRC_StatusPairCInputOverLoad | kASRC_StatusPairBInputOverLoad |
+ kASRC_StatusPairAInputOverLoad | kASRC_StatusPairCInputUnderflow |
+ kASRC_StatusPairBInputUnderflow |
+ kASRC_StatusPairAInputUnderflow, /*!< input error status */
+
+ kASRC_StatusOutputError = kASRC_StatusPairCOutputOverLoad | kASRC_StatusPairBOutputOverLoad |
+ kASRC_StatusPairAOutputOverLoad | kASRC_StatusPairCOutputOverflow |
+ kASRC_StatusPairBOutputOverflow |
+ kASRC_StatusPairAOutputOverflow, /*!< output error status */
+
+ kASRC_StatusPairCOutputReady = ASRC_ASRSTR_AODFC_MASK, /*!< pair c output ready */
+ kASRC_StatusPairBOutputReady = ASRC_ASRSTR_AODFB_MASK, /*!< pair b output ready */
+ kASRC_StatusPairAOutputReady = ASRC_ASRSTR_AODFA_MASK, /*!< pair a output ready */
+ kASRC_StatusPairCInputReady = ASRC_ASRSTR_AIDEC_MASK, /*!< pair c input ready */
+ kASRC_StatusPairBInputReady = ASRC_ASRSTR_AIDEB_MASK, /*!< pair b input ready */
+ kASRC_StatusPairAInputReady = ASRC_ASRSTR_AIDEA_MASK, /*!< pair a input ready */
+ kASRC_StatusPairAInterrupt = kASRC_StatusPairAInputReady | kASRC_StatusPairAOutputReady, /*!< pair A interrupt */
+ kASRC_StatusPairBInterrupt = kASRC_StatusPairBInputReady | kASRC_StatusPairBOutputReady, /*!< pair B interrupt */
+ kASRC_StatusPairCInterrupt = kASRC_StatusPairCInputReady | kASRC_StatusPairCOutputReady, /*!< pair C interrupt */
+
+};
+
+/*! @brief ASRC channel pair status
+ * @anchor _asrc_channel_pair_status
+ */
+enum
+{
+ kASRC_OutputFifoNearFull = ASRC_ASRFSTA_OAFA_MASK, /*!< channel pair output fifo near full */
+ kASRC_InputFifoNearEmpty = ASRC_ASRFSTA_IAEA_MASK, /*!< channel pair input fifo near empty */
+};
+
+/*! @brief ASRC ideal ratio */
+typedef enum _asrc_ratio
+{
+ kASRC_RatioNotUsed = 0U, /*!< ideal ratio not used */
+ kASRC_RatioUseInternalMeasured =
+ 2U, /*!< ideal ratio use internal measure ratio, can be used for real time streaming audio */
+ kASRC_RatioUseIdealRatio =
+ 3U, /*!< ideal ratio use manual configure ratio, can be used for the non-real time streaming audio */
+} asrc_ratio_t;
+
+/*! @brief Number of channels in audio data */
+typedef enum _asrc_audio_channel
+{
+ kASRC_ChannelsNumber1 = 1U, /*!< channel number is 1 */
+ kASRC_ChannelsNumber2 = 2U, /*!< channel number is 2 */
+ kASRC_ChannelsNumber3 = 3U, /*!< channel number is 3 */
+ kASRC_ChannelsNumber4 = 4U, /*!< channel number is 4 */
+ kASRC_ChannelsNumber5 = 5U, /*!< channel number is 5 */
+ kASRC_ChannelsNumber6 = 6U, /*!< channel number is 6 */
+ kASRC_ChannelsNumber7 = 7U, /*!< channel number is 7 */
+ kASRC_ChannelsNumber8 = 8U, /*!< channel number is 8 */
+ kASRC_ChannelsNumber9 = 9U, /*!< channel number is 9 */
+ kASRC_ChannelsNumber10 = 10U, /*!< channel number is 10 */
+} asrc_audio_channel_t;
+
+/*! @brief data width */
+typedef enum _asrc_data_width
+{
+ kASRC_DataWidth24Bit = 0U, /*!< data width 24bit */
+ kASRC_DataWidth16Bit = 1U, /*!< data width 16bit */
+ kASRC_DataWidth8Bit = 2U, /*!< data width 8bit */
+} asrc_data_width_t;
+
+/*! @brief data alignment */
+typedef enum _asrc_data_align
+{
+ kASRC_DataAlignMSB = 1U, /*!< data alignment MSB */
+ kASRC_DataAlignLSB = 0U, /*!< data alignment LSB */
+} asrc_data_align_t;
+
+/*! @brief sign extension */
+typedef enum _asrc_sign_extension
+{
+ kASRC_NoSignExtension = 0U, /*!< no sign extension */
+ kASRC_SignExtension = 1U, /*!< sign extension */
+} asrc_sign_extension_t;
+
+/*! @brief asrc channel pair configuation */
+typedef struct _asrc_channel_pair_config
+{
+ asrc_audio_channel_t audioDataChannels; /*!< audio data channel numbers */
+ asrc_clock_source_t
+ inClockSource; /*!< input clock source, reference the clock source definition in SOC header file */
+ uint32_t inSourceClock_Hz; /*!< input source clock frequency */
+
+ asrc_clock_source_t
+ outClockSource; /*!< output clock source, reference the clock source definition in SOC header file */
+ uint32_t outSourceClock_Hz; /*!< output source clock frequency */
+
+ asrc_ratio_t sampleRateRatio; /*!< sample rate ratio type */
+
+ asrc_data_width_t inDataWidth; /*!< input data width */
+ asrc_data_align_t inDataAlign; /*!< input data alignment */
+
+ asrc_data_width_t outDataWidth; /*!< output data width */
+ asrc_data_align_t outDataAlign; /*!< output data alignment */
+ asrc_sign_extension_t outSignExtension; /*!< output extension */
+
+ uint8_t outFifoThreshold; /*!< output fifo threshold */
+ uint8_t inFifoThreshold; /*!< input fifo threshold */
+
+ bool bufStallWhenFifoEmptyFull; /*!< stall Pair A conversion in case of Buffer near empty full condition */
+
+} asrc_channel_pair_config_t;
+
+/*! @brief SAI transfer structure */
+typedef struct _asrc_transfer
+{
+ void *inData; /*!< Data address to convert.*/
+ size_t inDataSize; /*!< input data size. */
+ void *outData; /*!< Data address to store converted data */
+ size_t outDataSize; /*!< output data size. */
+} asrc_transfer_t;
+
+/*! @brief asrc handler */
+typedef struct _asrc_handle asrc_handle_t;
+
+/*! @brief ASRC transfer callback prototype */
+typedef void (*asrc_transfer_callback_t)(ASRC_Type *base, asrc_handle_t *handle, status_t status, void *userData);
+
+/*! @brief asrc in handler */
+typedef struct _asrc_in_handle
+{
+ asrc_transfer_callback_t callback; /*!< Callback function called at convert complete */
+ uint32_t sampleWidth; /*!< data width */
+ uint32_t sampleMask; /*!< data mask */
+ uint32_t fifoThreshold; /*!< fifo threshold */
+ uint8_t *asrcQueue[ASRC_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSamples[ASRC_XFER_QUEUE_SIZE]; /*!< Data bytes need to convert */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+} asrc_in_handle_t;
+
+/*! @brief output handler */
+typedef struct _asrc_out_handle
+{
+ asrc_transfer_callback_t callback; /*!< Callback function called at convert complete */
+ uint32_t sampleWidth; /*!< data width */
+ uint32_t fifoThreshold; /*!< fifo threshold */
+ uint8_t *asrcQueue[ASRC_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSamples[ASRC_XFER_QUEUE_SIZE]; /*!< Data bytes need to convert */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+} asrc_out_handle_t;
+
+/*! @brief ASRC handle structure */
+struct _asrc_handle
+{
+ ASRC_Type *base; /*!< base address */
+
+ uint32_t state; /*!< Transfer status */
+ void *userData; /*!< Callback parameter passed to callback function*/
+
+ asrc_audio_channel_t audioDataChannels; /*!< audio channel number */
+ asrc_channel_pair_t channelPair; /*!< channel pair mask */
+
+ asrc_in_handle_t in; /*!< asrc input handler */
+ asrc_out_handle_t out; /*!< asrc output handler */
+};
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Get instance number of the ASRC peripheral.
+ *
+ * @param base ASRC base pointer.
+ */
+uint32_t ASRC_GetInstance(ASRC_Type *base);
+
+/*!
+ * brief Initializes the asrc peripheral.
+ *
+ * This API gates the asrc clock. The asrc module can't operate unless ASRC_Init is called to enable the clock.
+ *
+ * param base asrc base pointer.
+ * param asrcPeripheralClock_Hz peripheral clock of ASRC.
+ */
+void ASRC_Init(ASRC_Type *base, uint32_t asrcPeripheralClock_Hz);
+
+/*!
+ * @brief De-initializes the ASRC peripheral.
+ *
+ * This API gates the ASRC clock and disable ASRC module. The ASRC module can't operate unless ASRC_Init
+ *
+ * @param base ASRC base pointer.
+ */
+void ASRC_Deinit(ASRC_Type *base);
+
+/*!
+ * @brief Do software reset .
+ *
+ * This software reset bit is self-clear bit, it will generate a software reset signal inside ASRC.
+ * After 9 cycles of the ASRC processing clock, this reset process will stop and this bit will cleared
+ * automatically.
+ *
+ * @param base ASRC base pointer
+ */
+void ASRC_SoftwareReset(ASRC_Type *base);
+
+/*!
+ * @brief ASRC configure channel pair.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair index of channel pair, reference _asrc_channel_pair.
+ * @param config ASRC channel pair configuration pointer.
+ * @param inputSampleRate input audio data sample rate.
+ * @param outputSampleRate output audio data sample rate.
+ */
+status_t ASRC_SetChannelPairConfig(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ asrc_channel_pair_config_t *config,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate);
+
+/*!
+ * @brief Get output sample buffer size.
+ *
+ * @note This API is depends on the ASRC output configuration, should be called after the ASRC_SetChannelPairConfig.
+ *
+ * @param base asrc base pointer.
+ * @param channelPair ASRC channel pair number.
+ * @param inSampleRate input sample rate.
+ * @param outSampleRate output sample rate.
+ * @param inSamplesize input sampleS size.
+ * @retval output buffer size in byte.
+ */
+uint32_t ASRC_GetOutSamplesSize(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t inSamplesize);
+
+/*!
+ * @brief Map register sample width to real sample width.
+ *
+ * @note This API is depends on the ASRC configuration, should be called after the ASRC_SetChannelPairConfig.
+ * @param base asrc base pointer.
+ * @param channelPair asrc channel pair index.
+ * @param inWidth ASRC channel pair number.
+ * @param outWidth input sample rate.
+ * @retval input sample mask value.
+ */
+uint32_t ASRC_MapSamplesWidth(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *inWidth, uint32_t *outWidth);
+
+/*!
+ * @brief Get left samples in fifo.
+ *
+ * @param base asrc base pointer.
+ * @param channelPair ASRC channel pair number.
+ * @param buffer input sample numbers.
+ * @param outSampleWidth output sample width.
+ * @param remainSamples output sample rate.
+ * @retval remain samples number.
+ */
+uint32_t ASRC_GetRemainFifoSamples(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ uint32_t *buffer,
+ uint32_t outSampleWidth,
+ uint32_t remainSamples);
+
+/*!
+ * @brief ASRC module enable.
+ *
+ * @param base ASRC base pointer.
+ * @param enable true is enable, false is disable
+ */
+static inline void ASRC_ModuleEnable(ASRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->ASRCTR |= ASRC_ASRCTR_ASRCEN_MASK;
+ }
+ else
+ {
+ base->ASRCTR &= ~ASRC_ASRCTR_ASRCEN_MASK;
+ }
+}
+
+/*!
+ * @brief ASRC enable channel pair.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair channel pair mask value, reference _asrc_channel_pair_mask.
+ * @param enable true is enable, false is disable.
+ */
+static inline void ASRC_ChannelPairEnable(ASRC_Type *base, asrc_channel_pair_t channelPair, bool enable)
+{
+ if (enable)
+ {
+ base->ASRCTR |= 1UL << ((uint32_t)channelPair + 1U);
+ }
+ else
+ {
+ base->ASRCTR &= ~(1UL << ((uint32_t)channelPair + 1U));
+ }
+}
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief ASRC interrupt enable
+ * This function enable the ASRC interrupt with the provided mask.
+ *
+ * @param base ASRC peripheral base address.
+ * @param mask The interrupts to enable. Logical OR of @ref _asrc_interrupt_mask.
+ */
+static inline void ASRC_EnableInterrupt(ASRC_Type *base, uint32_t mask)
+{
+ base->ASRIER |= mask;
+}
+
+/*!
+ * @brief ASRC interrupt disable
+ * This function disable the ASRC interrupt with the provided mask.
+ *
+ * @param base ASRC peripheral base address.
+ * @param mask The interrupts to disable. Logical OR of @ref _asrc_interrupt_mask.
+ */
+static inline void ASRC_DisableInterrupt(ASRC_Type *base, uint32_t mask)
+{
+ base->ASRIER &= ~mask;
+}
+
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the ASRC status flag state.
+ *
+ * @param base ASRC base pointer
+ * @return ASRC Tx status flag value. Use the Status Mask to get the status value needed.
+ */
+static inline uint32_t ASRC_GetStatus(ASRC_Type *base)
+{
+ return base->ASRSTR;
+}
+
+/*!
+ * @brief Gets the ASRC channel pair initialization state.
+ *
+ * @param base ASRC base pointer
+ * @param channel ASRC channel pair.
+ * @return ASRC Tx status flag value. Use the Status Mask to get the status value needed.
+ */
+static inline bool ASRC_GetChannelPairInitialStatus(ASRC_Type *base, asrc_channel_pair_t channel)
+{
+ return ((base->ASRCFG >> ASRC_ASRCFG_INIRQA_SHIFT) & (1U << (uint32_t)channel)) == 0U ? false : true;
+}
+
+/*!
+ * @brief Gets the ASRC channel A fifo a status flag state.
+ *
+ * @param base ASRC base pointer
+ * @param channelPair ASRC channel pair.
+ * @return ASRC channel pair a fifo status flag value. Use the Status Mask to get the status value needed.
+ */
+static inline uint32_t ASRC_GetChannelPairFifoStatus(ASRC_Type *base, asrc_channel_pair_t channelPair)
+{
+ return ASRC_ASRMCR(base, channelPair) & ((uint32_t)kASRC_OutputFifoNearFull | (uint32_t)kASRC_InputFifoNearEmpty);
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Writes data into ASRC channel pair FIFO.
+ * Note: ASRC fifo width is 24bit.
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ * @param data Data needs to be written.
+ */
+static inline void ASRC_ChannelPairWriteData(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t data)
+{
+ ASRC_ASRDI(base, channelPair) = data;
+}
+
+/*!
+ * @brief Read data from ASRC channel pair FIFO.
+ * Note: ASRC fifo width is 24bit.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ * @retval value read from fifo.
+ */
+static inline uint32_t ASRC_ChannelPairReadData(ASRC_Type *base, asrc_channel_pair_t channelPair)
+{
+ return ASRC_ASRDO(base, channelPair);
+}
+
+/*!
+ * @brief Get input data fifo address.
+ * Note: ASRC fifo width is 24bit.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ */
+static inline uint32_t ASRC_GetInputDataRegisterAddress(ASRC_Type *base, asrc_channel_pair_t channelPair)
+{
+ return (uint32_t)ASRC_ASRDI_ADDR(base, channelPair);
+}
+
+/*!
+ * @brief Get output data fifo address.
+ * Note: ASRC fifo width is 24bit.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ */
+static inline uint32_t ASRC_GetOutputDataRegisterAddress(ASRC_Type *base, asrc_channel_pair_t channelPair)
+{
+ return (uint32_t)ASRC_ASRDO_ADDR(base, channelPair);
+}
+
+/*!
+ * @brief ASRC configure ideal ratio.
+ * The ideal ratio should be used when input clock source is not avalible.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair.
+ * @param inputSampleRate input audio data sample rate.
+ * @param outputSampleRate output audio data sample rate.
+ */
+status_t ASRC_SetIdealRatioConfig(ASRC_Type *base,
+ asrc_channel_pair_t channelPair,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate);
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief ASRC configure channel pair.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC transactional handle pointer.
+ * @param config ASRC channel pair configuration pointer.
+ * @param inputSampleRate input audio data sample rate.
+ * @param outputSampleRate output audio data sample rate.
+ */
+status_t ASRC_TransferSetChannelPairConfig(ASRC_Type *base,
+ asrc_handle_t *handle,
+ asrc_channel_pair_config_t *config,
+ uint32_t inputSampleRate,
+ uint32_t outputSampleRate);
+
+/*!
+ * @brief Initializes the ASRC handle.
+ *
+ * This function initializes the handle for the ASRC transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base ASRC base pointer
+ * @param handle ASRC handle pointer.
+ * @param channelPair ASRC channel pair.
+ * @param inCallback Pointer to the user callback function.
+ * @param outCallback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function
+ */
+void ASRC_TransferCreateHandle(ASRC_Type *base,
+ asrc_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_transfer_callback_t inCallback,
+ asrc_transfer_callback_t outCallback,
+ void *userData);
+
+/*!
+ * @brief Performs an interrupt non-blocking convert on asrc.
+ *
+ * @note This API returns immediately after the transfer initiates, application should check the wait and check the
+ * callback status.
+ *
+ * @param base asrc base pointer.
+ * @param handle Pointer to the asrc_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the ASRC_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_ASRCBusy Previous receive still not finished.
+ */
+status_t ASRC_TransferNonBlocking(ASRC_Type *base, asrc_handle_t *handle, asrc_transfer_t *xfer);
+
+/*!
+ * @brief Performs an blocking convert on asrc.
+ *
+ * @note This API returns immediately after the convert finished.
+ *
+ * @param base asrc base pointer.
+ * @param channelPair channel pair index.
+ * @param xfer Pointer to the ASRC_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ */
+status_t ASRC_TransferBlocking(ASRC_Type *base, asrc_channel_pair_t channelPair, asrc_transfer_t *xfer);
+
+/*!
+ * @brief Get converted byte count.
+ *
+ * @param base ASRC base pointer.
+ * @param handle Pointer to the asrc_handle_t structure which stores the transfer state.
+ * @param count Bytes count sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_ASRCIdle There is not a non-blocking transaction currently in progress.
+ */
+status_t ASRC_TransferGetConvertedCount(ASRC_Type *base, asrc_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the current convert.
+ *
+ * @note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base ASRC base pointer.
+ * @param handle Pointer to the asrc_handle_t structure which stores the transfer state.
+ */
+void ASRC_TransferAbortConvert(ASRC_Type *base, asrc_handle_t *handle);
+
+/*!
+ * @brief Terminate all ASRC convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortConvert.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferTerminateConvert(ASRC_Type *base, asrc_handle_t *handle);
+
+/*!
+ * @brief ASRC convert interrupt handler.
+ *
+ * @param base ASRC base pointer.
+ * @param handle Pointer to the asrc_handle_t structure.
+ */
+void ASRC_TransferHandleIRQ(ASRC_Type *base, asrc_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_ASRC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c
new file mode 100644
index 0000000000..8731a8e8fe
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_asrc_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.asrc_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _asrc_edma_private_handle
+{
+ ASRC_Type *base;
+ asrc_edma_handle_t *handle;
+} asrc_edma_private_handle_t;
+
+/*<! Private handle only used for internally. */
+static asrc_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_ASRC_COUNT][FSL_ASRC_CHANNEL_PAIR_COUNT];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief ASRC EDMA callback for input.
+ *
+ * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief ASRC EDMA callback for output.
+ *
+ * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
+ asrc_edma_handle_t *asrcHandle = privHandle->handle;
+ asrc_in_edma_handle_t *asrcInHandle = &(privHandle->handle->in);
+ status_t inStatus = kStatus_ASRCInIdle;
+ /* If finished a block, call the callback function */
+ asrcInHandle->asrcQueue[asrcInHandle->queueDriver] = NULL;
+ asrcInHandle->queueDriver = (asrcInHandle->queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
+
+ /* If all data finished, just stop the transfer */
+ if (asrcInHandle->asrcQueue[asrcInHandle->queueDriver] == NULL)
+ {
+ EDMA_AbortTransfer(asrcInHandle->inDmaHandle);
+ inStatus = kStatus_ASRCInQueueIdle;
+ }
+
+ if (asrcHandle->callback != NULL)
+ {
+ (asrcHandle->callback)(privHandle->base, asrcHandle, inStatus, asrcHandle->userData);
+ }
+}
+
+static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData;
+ asrc_edma_handle_t *asrcHandle = privHandle->handle;
+ asrc_out_edma_handle_t *asrcOutHandle = &(privHandle->handle->out);
+ uint32_t queueDriverIndex = asrcOutHandle->queueDriver;
+ status_t callbackStatus = kStatus_ASRCOutIdle;
+
+ /* If finished a block, call the callback function */
+ asrcOutHandle->asrcQueue[queueDriverIndex] = NULL;
+ asrcOutHandle->queueDriver = (uint8_t)((queueDriverIndex + 1U) % ASRC_XFER_OUT_QUEUE_SIZE);
+
+ /* If all data finished, just stop the transfer */
+ if (asrcOutHandle->asrcQueue[asrcOutHandle->queueDriver] == NULL)
+ {
+ EDMA_AbortTransfer(asrcOutHandle->outDmaHandle);
+ callbackStatus = kStatus_ASRCOutQueueIdle;
+ }
+
+ if (asrcHandle->callback != NULL)
+ {
+ (asrcHandle->callback)(privHandle->base, asrcHandle, callbackStatus, asrcHandle->userData);
+ }
+}
+/*!
+ * brief Initializes the ASRC IN eDMA handle.
+ *
+ * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
+ * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
+ *
+ * param base ASRC base pointer.
+ * param channelPair ASRC channel pair
+ * param handle ASRC eDMA handle pointer.
+ * param callback Pointer to user callback function.
+ * param txDmaHandle ASRC send edma handle pointer.
+ * param periphConfig peripheral configuration.
+ * param userData User parameter passed to the callback function.
+ */
+void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_edma_callback_t callback,
+ edma_handle_t *inDmaHandle,
+ const asrc_p2p_edma_config_t *periphConfig,
+ void *userData)
+{
+ assert((handle != NULL) && (inDmaHandle != NULL));
+
+ uint32_t instance = ASRC_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(&handle->in, 0, sizeof(asrc_in_edma_handle_t));
+
+ handle->in.inDmaHandle = inDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set ASRC state to idle */
+ handle->in.state = kStatus_ASRCIdle;
+ handle->channelPair = channelPair;
+ handle->in.peripheralConfig = periphConfig;
+
+ s_edmaPrivateHandle[instance][channelPair].base = base;
+ s_edmaPrivateHandle[instance][channelPair].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(inDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->in.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(inDmaHandle, ASRC_InEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
+}
+
+/*!
+ * brief Initializes the ASRC OUT eDMA handle.
+ *
+ * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
+ * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
+ *
+ * param base ASRC base pointer.
+ * param channelPair ASRC channel pair
+ * param handle ASRC eDMA handle pointer.
+ * param callback Pointer to user callback function.
+ * param txDmaHandle ASRC send edma handle pointer.
+ * param periphConfig peripheral configuration.
+ * param userData User parameter passed to the callback function.
+ */
+void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_edma_callback_t callback,
+ edma_handle_t *outDmaHandle,
+ const asrc_p2p_edma_config_t *periphConfig,
+ void *userData)
+{
+ assert((handle != NULL) && (NULL != outDmaHandle));
+
+ uint32_t instance = ASRC_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(&handle->out, 0, sizeof(asrc_out_edma_handle_t));
+
+ handle->out.outDmaHandle = outDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set ASRC state to idle */
+ handle->out.state = kStatus_ASRCIdle;
+ handle->channelPair = channelPair;
+ handle->out.peripheralConfig = periphConfig;
+
+ s_edmaPrivateHandle[instance][channelPair].base = base;
+ s_edmaPrivateHandle[instance][channelPair].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(outDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->out.tcd)), ASRC_XFER_OUT_QUEUE_SIZE);
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(outDmaHandle, ASRC_OutEDMACallback, &s_edmaPrivateHandle[instance][channelPair]);
+}
+
+/*!
+ * brief Configures the ASRC channel pair.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ * param asrcConfig asrc configurations.
+ * param periphConfig peripheral configuration.
+ * param inputSampleRate ASRC input sample rate.
+ * param outputSampleRate ASRC output sample rate.
+ */
+status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_config_t *asrcConfig,
+ uint32_t inSampleRate,
+ uint32_t outSampleRate)
+{
+ assert((handle != NULL) && (NULL != asrcConfig));
+
+ /* Configure the audio format to ASRC registers */
+ if (ASRC_SetChannelPairConfig(base, handle->channelPair, asrcConfig, inSampleRate, outSampleRate) !=
+ kStatus_Success)
+ {
+ return kStatus_ASRCChannelPairConfigureFailed;
+ }
+ handle->in.fifoThreshold = (asrcConfig->inFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
+ handle->out.fifoThreshold = (asrcConfig->outFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels;
+ (void)ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get output sample buffer size can be transferred by edma.
+ *
+ * note This API is depends on the ASRC output configuration, should be called after the
+ * ASRC_TransferSetChannelPairConfigEDMA.
+ *
+ * param base asrc base pointer.
+ * param handle ASRC channel pair edma handle.
+ * param inSampleRate input sample rate.
+ * param outSampleRate output sample rate.
+ * param inSamples input sampleS size.
+ * retval output buffer size in byte.
+ */
+uint32_t ASRC_GetOutSamplesSizeEDMA(
+ ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize)
+{
+ uint32_t outputSize = ASRC_GetOutSamplesSize(base, handle->channelPair, inSampleRate, outSampleRate, inSamplesize);
+
+ return outputSize - outputSize % handle->out.fifoThreshold;
+}
+
+static status_t ASRC_TransferOutSubmitEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ uint32_t *outDataAddr,
+ uint32_t outDataSize)
+{
+ assert(outDataAddr != NULL);
+ assert(outDataSize != 0U);
+
+ uint32_t outAddr = ASRC_GetOutputDataRegisterAddress(base, handle->channelPair);
+ edma_transfer_config_t config = {0};
+ edma_transfer_type_t type = kEDMA_PeripheralToMemory;
+
+ if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
+ {
+ return kStatus_ASRCQueueFull;
+ }
+
+ if (handle->out.peripheralConfig != NULL)
+ {
+ type = kEDMA_PeripheralToPeripheral;
+ }
+
+ if (handle->out.asrcQueue[handle->out.queueUser] != NULL)
+ {
+ return kStatus_ASRCQueueFull;
+ }
+
+ handle->out.asrcQueue[handle->out.queueUser] = outDataAddr;
+ handle->out.transferSize[handle->out.queueUser] = outDataSize;
+ handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE;
+ /* Prepare ASRC output edma configuration */
+ EDMA_PrepareTransfer(&config, (uint32_t *)outAddr, handle->out.sampleWidth, outDataAddr, handle->out.sampleWidth,
+ handle->out.fifoThreshold * handle->out.sampleWidth, outDataSize, type);
+
+ if (handle->out.state != (uint32_t)kStatus_ASRCBusy)
+ {
+ (void)EDMA_SubmitTransfer(handle->out.outDmaHandle, &config);
+
+ EDMA_StartTransfer(handle->out.outDmaHandle);
+
+ if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
+ {
+ handle->out.peripheralConfig->startPeripheral(true);
+ }
+ }
+
+ return kStatus_Success;
+}
+
+static status_t ASRC_TransferInSubmitEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ uint32_t *inDataAddr,
+ uint32_t inDataSize)
+{
+ assert(inDataAddr != NULL);
+ assert(inDataSize != 0U);
+
+ uint32_t inAddr = ASRC_GetInputDataRegisterAddress(base, handle->channelPair);
+ edma_transfer_config_t config = {0};
+
+ if (handle->in.asrcQueue[handle->in.queueUser] != NULL)
+ {
+ return kStatus_ASRCQueueFull;
+ }
+
+ /* Add into queue */
+ handle->in.asrcQueue[handle->in.queueUser] = inDataAddr;
+ handle->in.transferSize[handle->in.queueUser] = inDataSize;
+ handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_IN_QUEUE_SIZE;
+
+ /* Prepare ASRC input edma configuration */
+ EDMA_PrepareTransfer(&config, (uint32_t *)inDataAddr, handle->in.sampleWidth, (uint32_t *)inAddr,
+ handle->in.sampleWidth, handle->in.fifoThreshold * handle->in.sampleWidth, inDataSize,
+ handle->in.peripheralConfig == NULL ? kEDMA_MemoryToPeripheral : kEDMA_PeripheralToPeripheral);
+
+ if (handle->in.state != (uint32_t)kStatus_ASRCBusy)
+ {
+ (void)EDMA_SubmitTransfer(handle->in.inDmaHandle, &config);
+ EDMA_StartTransfer(handle->in.inDmaHandle);
+ /* start peripheral */
+ if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
+ {
+ handle->in.peripheralConfig->startPeripheral(true);
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking ASRC convert using EDMA.
+ *
+ * note This interface returns immediately after the transfer initiates.
+
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a ASRC eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full.
+ */
+status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ if (ASRC_TransferOutSubmitEDMA(base, handle, xfer->outData, xfer->outDataSize) != kStatus_Success)
+ {
+ return kStatus_ASRCQueueFull;
+ }
+
+ if (ASRC_TransferInSubmitEDMA(base, handle, xfer->inData, xfer->inDataSize) != kStatus_Success)
+ {
+ return kStatus_ASRCQueueFull;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a ASRC IN transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->in.inDmaHandle);
+
+ /* Handle the queue index */
+ handle->in.asrcQueue[handle->in.queueDriver] = NULL;
+ handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->in.state = kStatus_ASRCIdle;
+}
+
+/*!
+ * brief Aborts a ASRC OUT transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->out.outDmaHandle);
+
+ /* Handle the queue index */
+ handle->out.asrcQueue[handle->out.queueDriver] = NULL;
+ handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->out.state = kStatus_ASRCIdle;
+}
+
+/*!
+ * brief Terminate In ASRC Convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ ASRC_TransferInAbortEDMA(base, handle);
+ /* stop peripheral */
+ if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL))
+ {
+ handle->in.peripheralConfig->startPeripheral(false);
+ }
+
+ /* Clear all the internal information */
+ (void)memset(handle->in.tcd, 0, sizeof(handle->in.tcd));
+ (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue));
+ (void)memset(handle->in.transferSize, 0, sizeof(handle->in.transferSize));
+ handle->in.queueUser = 0U;
+ handle->in.queueDriver = 0U;
+}
+
+/*!
+ * brief Terminate Out ASRC Convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
+ *
+ * param base ASRC base pointer.
+ * param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ ASRC_TransferOutAbortEDMA(base, handle);
+
+ if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL))
+ {
+ handle->out.peripheralConfig->startPeripheral(false);
+ }
+
+ (void)memset(handle->out.tcd, 0, sizeof(handle->out.tcd));
+ (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue));
+ (void)memset(handle->out.transferSize, 0, sizeof(handle->out.transferSize));
+ handle->out.queueUser = 0U;
+ handle->out.queueDriver = 0U;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h
new file mode 100644
index 0000000000..89053232c8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_ASRC_P2P_EDMA_H_
+#define _FSL_ASRC_P2P_EDMA_H_
+
+#include "fsl_edma.h"
+#include "fsl_asrc.h"
+
+/*!
+ * @addtogroup asrc_edma_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_ASRC_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 1, 0)) /*!< Version 2.1.0 */
+/*@}*/
+/*!< @brief ASRC IN edma QUEUE size */
+#define ASRC_XFER_IN_QUEUE_SIZE 4U
+#define ASRC_XFER_OUT_QUEUE_SIZE (ASRC_XFER_QUEUE_SIZE * 2U)
+
+typedef struct _asrc_edma_handle asrc_edma_handle_t;
+
+/*! @brief ASRC eDMA transfer callback function for finish and error */
+typedef void (*asrc_edma_callback_t)(ASRC_Type *base, asrc_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief ASRC trigger peripheral function pointer */
+typedef void (*asrc_start_peripheral_t)(bool start);
+/*! @brief destination peripheral configuration */
+typedef struct _asrc_p2p_edma_config
+{
+ uint8_t watermark; /*!< peripheral watermark */
+ uint8_t channel; /*!< peripheral channel number */
+ asrc_start_peripheral_t startPeripheral; /*!< trigger peripheral start */
+} asrc_p2p_edma_config_t;
+
+/*!@ brief asrc in edma handler */
+typedef struct _asrc_in_edma_handle
+{
+ edma_handle_t *inDmaHandle; /*!< DMA handler for ASRC in */
+
+ uint8_t tcd[(ASRC_XFER_IN_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA send. */
+
+ uint32_t sampleWidth; /*!< input data width */
+ uint32_t fifoThreshold; /*!< ASRC input fifo threshold */
+ uint32_t *asrcQueue[ASRC_XFER_IN_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[ASRC_XFER_IN_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+ uint32_t state; /*!< Internal state for ASRC eDMA transfer */
+
+ const asrc_p2p_edma_config_t *peripheralConfig; /*!< peripheral configuration pointer */
+} asrc_in_edma_handle_t;
+
+/*!@ brief asrc out edma handler */
+typedef struct _asrc_out_edma_handle
+{
+ edma_handle_t *outDmaHandle; /*!< DMA handler for ASRC out */
+
+ uint8_t tcd[(ASRC_XFER_OUT_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA send. */
+
+ uint32_t sampleWidth; /*!< output data width */
+ uint32_t fifoThreshold; /*!< ASRC output fifo threshold */
+ uint32_t *asrcQueue[ASRC_XFER_OUT_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[ASRC_XFER_OUT_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+ uint32_t state; /*!< Internal state for ASRC eDMA transfer */
+ const asrc_p2p_edma_config_t *peripheralConfig; /*!< peripheral configuration pointer */
+} asrc_out_edma_handle_t;
+
+/*! @brief ASRC DMA transfer handle.*/
+struct _asrc_edma_handle
+{
+ asrc_in_edma_handle_t in; /*!< asrc in handler */
+ asrc_out_edma_handle_t out; /*!< asrc out handler */
+ asrc_channel_pair_t channelPair; /*!< channel pair */
+ void *userData; /*!< User callback parameter */
+ asrc_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the ASRC IN eDMA handle.
+ *
+ * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
+ * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair
+ * @param handle ASRC eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param inDmaHandle DMA handler for ASRC in.
+ * @param periphConfig peripheral configuration.
+ * @param userData User parameter passed to the callback function.
+ */
+void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_edma_callback_t callback,
+ edma_handle_t *inDmaHandle,
+ const asrc_p2p_edma_config_t *periphConfig,
+ void *userData);
+
+/*!
+ * @brief Initializes the ASRC OUT eDMA handle.
+ *
+ * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs.
+ * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle.
+ *
+ * @param base ASRC base pointer.
+ * @param channelPair ASRC channel pair
+ * @param handle ASRC eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param outDmaHandle DMA handler for ASRC out.
+ * @param periphConfig peripheral configuration.
+ * @param userData User parameter passed to the callback function.
+ */
+void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_t channelPair,
+ asrc_edma_callback_t callback,
+ edma_handle_t *outDmaHandle,
+ const asrc_p2p_edma_config_t *periphConfig,
+ void *userData);
+
+/*!
+ * @brief Configures the ASRC P2P channel pair.
+ *
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ * @param asrcConfig asrc configurations.
+ * @param inSampleRate ASRC input sample rate.
+ * @param outSampleRate ASRC output sample rate.
+ */
+status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base,
+ asrc_edma_handle_t *handle,
+ asrc_channel_pair_config_t *asrcConfig,
+ uint32_t inSampleRate,
+ uint32_t outSampleRate);
+
+/*!
+ * @brief Get output sample buffer size can be transferred by edma.
+ *
+ * @note This API is depends on the ASRC output configuration, should be called after the
+ * ASRC_TransferSetChannelPairConfigEDMA.
+ *
+ * @param base asrc base pointer.
+ * @param handle ASRC channel pair edma handle.
+ * @param inSampleRate input sample rate.
+ * @param outSampleRate output sample rate.
+ * @param inSamplesize input sampleS size.
+ * @retval output buffer size in byte.
+ */
+uint32_t ASRC_GetOutSamplesSizeEDMA(
+ ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize);
+
+/*!
+ * @brief Performs a non-blocking ASRC m2m convert using EDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates.
+
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a ASRC eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full.
+ */
+status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a ASRC IN transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a ASRC OUT transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle);
+
+/*!
+ * @brief Terminate In ASRC Convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle);
+
+/*!
+ * @brief Terminate Out ASRC Convert.
+ *
+ * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the
+ * current transfer slot, please call ASRC_TransferAbortPP2PEDMA.
+ *
+ * @param base ASRC base pointer.
+ * @param handle ASRC eDMA handle pointer.
+ */
+void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.c b/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.c
new file mode 100644
index 0000000000..d4ffdacfb9
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_bee.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.bee"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void aligned_memcpy(void *dst, const void *src, size_t size)
+{
+ register uint32_t *to32 = (uint32_t *)(uint32_t *)dst;
+ register const uint32_t *from32 = (const uint32_t *)(const uint32_t *)src;
+
+ while (size >= sizeof(uint32_t))
+ {
+ *to32 = *from32;
+ size -= sizeof(uint32_t);
+ to32++;
+ from32++;
+ }
+}
+
+/*!
+ * brief Resets BEE module to factory default values.
+ *
+ * This function performs hardware reset of BEE module. Attributes and keys from software for both regions are cleared.
+ *
+ * param base BEE peripheral address.
+ */
+void BEE_Init(BEE_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Bee);
+#endif
+
+ base->CTRL = BEE_CTRL_CTRL_SFTRST_N_MASK | BEE_CTRL_CTRL_CLK_EN_MASK;
+}
+
+/*!
+ * brief Resets BEE module, clears keys for both regions and disables clock to the BEE.
+ *
+ * This function performs hardware reset of BEE module and disables clocks. Attributes and keys from software for both
+ * regions are cleared.
+ *
+ * param base BEE peripheral address.
+ */
+void BEE_Deinit(BEE_Type *base)
+{
+ base->CTRL &=
+ ~(BEE_CTRL_BEE_ENABLE_MASK | BEE_CTRL_CTRL_SFTRST_N_MASK | BEE_CTRL_CTRL_CLK_EN_MASK | BEE_CTRL_KEY_VALID_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Bee);
+#endif
+}
+
+/*!
+ * brief Loads default values to the BEE region configuration structure.
+ *
+ * Loads default values to the BEE region configuration structure. The default values are as follows:
+ * code
+ * config->region0Mode = kBEE_AesCtrMode;
+ * config->region1Mode = kBEE_AesCtrMode;
+ * config->region0AddrOffset = 0U;
+ * config->region1AddrOffset = 0U;
+ * config->region0SecLevel = kBEE_SecurityLevel3;
+ * config->region1SecLevel = kBEE_SecurityLevel3;
+ * config->region1Bot = 0U;
+ * config->region1Top = 0U;
+ * config->accessPermission = kBEE_AccessProtDisabled;
+ * config->endianSwapEn = kBEE_EndianSwapEnabled;
+ * endcode
+ *
+ * param config Configuration structure for BEE peripheral.
+ */
+void BEE_GetDefaultConfig(bee_region_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->region0Mode = kBEE_AesCtrMode;
+ config->region1Mode = kBEE_AesCtrMode;
+ config->region0AddrOffset = 0U;
+ config->region1AddrOffset = 0U;
+ config->region0SecLevel = kBEE_SecurityLevel3;
+ config->region1SecLevel = kBEE_SecurityLevel3;
+ config->region1Bot = 0U;
+ config->region1Top = 0U;
+ config->accessPermission = kBEE_AccessProtDisabled;
+ config->endianSwapEn = kBEE_EndianSwapEnabled;
+}
+
+/*!
+ * brief Sets BEE configuration.
+ *
+ * This function sets BEE peripheral and BEE region settings accorging to given configuration structure.
+ *
+ * param base BEE peripheral address.
+ * param config Configuration structure for BEE.
+ */
+void BEE_SetConfig(BEE_Type *base, const bee_region_config_t *config)
+{
+ uint32_t beeCtrlVal;
+ bool reenable = false;
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Disable BEE before region configuration in case it is enabled. */
+ if ((base->CTRL & BEE_CTRL_BEE_ENABLE_MASK) != 0U)
+ {
+ BEE_Disable(base);
+ reenable = true;
+ }
+
+ /* Preserve CTRL bit values that are not set by this function */
+ beeCtrlVal = base->CTRL & 0xFFFF0037U;
+
+ /* Set variable according to configuration */
+ beeCtrlVal |= BEE_CTRL_AC_PROT_EN(config->accessPermission) | BEE_CTRL_LITTLE_ENDIAN(config->endianSwapEn) |
+ BEE_CTRL_SECURITY_LEVEL_R0(config->region0SecLevel) | BEE_CTRL_CTRL_AES_MODE_R0(config->region0Mode) |
+ BEE_CTRL_SECURITY_LEVEL_R1(config->region1SecLevel) | BEE_CTRL_CTRL_AES_MODE_R1(config->region1Mode);
+
+ /* Load values to registers */
+ base->CTRL = beeCtrlVal;
+ base->ADDR_OFFSET0 = config->region0AddrOffset;
+ base->ADDR_OFFSET1 = config->region1AddrOffset;
+ base->REGION1_BOT = config->region1Bot;
+ base->REGION1_TOP = config->region1Top;
+
+ /* Reenable BEE if it was enabled before. */
+ if (reenable)
+ {
+ BEE_Enable(base);
+ }
+}
+
+/*!
+ * brief Loads the AES key for selected region into BEE key registers.
+ *
+ * This function loads given AES key to BEE register for the given region.
+ * The key must be 32-bit aligned and stored in little-endian format.
+ *
+ * Please note, that eFuse BEE_KEYx_SEL must be set accordingly to be able to load and use key loaded in BEE registers.
+ * Otherwise, key cannot loaded and BEE will use key from OTPMK or SW_GP2.
+ *
+ * param base BEE peripheral address.
+ * param region Selection of the BEE region to be configured.
+ * param key AES key (in little-endian format).
+ * param keySize Size of AES key.
+ */
+status_t BEE_SetRegionKey(BEE_Type *base, bee_region_t region, const uint8_t *key, size_t keySize)
+{
+ bool redisable = false;
+
+ /* Key must be 32-bit aligned */
+ if ((0U != ((uintptr_t)key & 0x3u)) || (keySize != 16U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Clear KEY_VALID bit before new key is loaded */
+ base->CTRL &= ~BEE_CTRL_KEY_VALID_MASK;
+
+ /* Write key registers, key is stored in little-endian format in memory */
+ aligned_memcpy((uint32_t *)(uint32_t)&base->AES_KEY0_W0, key, keySize);
+
+ /* Enable BEE before key configuration. */
+ if (0U == (base->CTRL & BEE_CTRL_BEE_ENABLE_MASK))
+ {
+ BEE_Enable(base);
+ redisable = true;
+ }
+
+ if (region == kBEE_Region0)
+ {
+ base->CTRL &= ~BEE_CTRL_KEY_REGION_SEL_MASK;
+ }
+
+ else if (region == kBEE_Region1)
+ {
+ base->CTRL |= BEE_CTRL_KEY_REGION_SEL_MASK;
+ }
+
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set KEY_VALID bit to trigger key loading */
+ base->CTRL |= BEE_CTRL_KEY_VALID_MASK;
+ /* Wait until key is ready */
+ while (0U == (base->CTRL & BEE_CTRL_KEY_VALID_MASK))
+ {
+ }
+
+ /* Redisable BEE if it was disabled before this function call. */
+ if (redisable)
+ {
+ BEE_Disable(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Loads the nonce for selected region into BEE nonce registers.
+ *
+ * This function loads given nonce(only AES CTR mode) to BEE register for the given region.
+ * The nonce must be 32-bit aligned and stored in little-endian format.
+ *
+ * param base BEE peripheral address.
+ * param region Selection of the BEE region to be configured.
+ * param nonce AES nonce (in little-endian format).
+ * param nonceSize Size of AES nonce.
+ */
+status_t BEE_SetRegionNonce(BEE_Type *base, bee_region_t region, const uint8_t *nonce, size_t nonceSize)
+{
+ /* Nonce must be 32-bit aligned */
+ if ((0U != ((uintptr_t)nonce & 0x3u)) || (nonceSize != 16U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Write nonce registers, nonce is stored in little-endian format in memory */
+ if (region == kBEE_Region0)
+ {
+ aligned_memcpy((uint32_t *)(uint32_t)&base->CTR_NONCE0_W0, nonce, nonceSize);
+ }
+
+ else if (region == kBEE_Region1)
+ {
+ aligned_memcpy((uint32_t *)(uint32_t)&base->CTR_NONCE1_W0, nonce, nonceSize);
+ }
+
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the BEE status flags.
+ *
+ * This function returns status of BEE peripheral.
+ *
+ * param base BEE peripheral address.
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+uint32_t BEE_GetStatusFlags(BEE_Type *base)
+{
+ return base->STATUS;
+}
+
+/*!
+ * brief Clears the BEE status flags.
+ *
+ * param base BEE peripheral base address.
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+void BEE_ClearStatusFlags(BEE_Type *base, uint32_t mask)
+{
+ /* w1c */
+ base->STATUS |= mask;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.h b/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.h
new file mode 100644
index 0000000000..201177a41f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/bee/fsl_bee.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_BEE_H_
+#define _FSL_BEE_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup bee
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief BEE driver version. Version 2.0.2.
+ *
+ * Current version: 2.0.2
+ *
+ * Change log:
+ *
+ * - 2.0.2
+ * - Bug Fixes
+ * - Fixed MISRA issue.
+ *
+ * - 2.0.1
+ * - Bug Fixes
+ * - Fixed bug in key user key loading sequence. BEE must be enabled during loading of user key.
+ * - Fixed typos in comments.
+ * - New Features
+ * - Added configuration setting for endian swap, access permission and region security level.
+ * - Improvements
+ * - Setting of AES nonce was moved from BEE_SetRegionKey() into separate BEE_SetRegionNonce() function.
+ * - Changed handling of region settings. Both regions are configured simultaneously by BEE_SetConfig() function.
+ * Configuration of FAC start and end address using IOMUXC_GPRs was moved to application.
+ * - Default value for region address offset was changed to 0.
+ *
+ * - 2.0.0
+ * - Initial version
+ */
+#define FSL_BEE_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+/*@}*/
+
+/*! @brief BEE aes mode. */
+typedef enum _bee_aes_mode
+{
+ kBEE_AesEcbMode = 0U, /*!< AES ECB Mode */
+ kBEE_AesCtrMode = 1U /*!< AES CTR Mode */
+} bee_aes_mode_t;
+
+/*! @brief BEE region. */
+typedef enum _bee_region
+{
+ kBEE_Region0 = 0U, /*!< BEE region 0 */
+ kBEE_Region1 = 1U /*!< BEE region 1 */
+} bee_region_t;
+
+/*! @brief BEE ac prot enable. */
+typedef enum _bee_ac_prot_enable
+{
+ kBEE_AccessProtDisabled = 0U, /*!< BEE access permission control disabled */
+ kBEE_AccessProtEnabled = 1U /*!< BEE access permission control enabled */
+} bee_ac_prot_enable;
+
+/*! @brief BEE endian swap enable. */
+typedef enum _bee_endian_swap_enable
+{
+ kBEE_EndianSwapDisabled = 1U, /*!< BEE endian swap disabled */
+ kBEE_EndianSwapEnabled = 0U /*!< BEE endian swap enabled */
+} bee_endian_swap_enable;
+
+/*! @brief BEE security level. */
+typedef enum _bee_security_level
+{
+ kBEE_SecurityLevel0 = 0U, /*!< BEE security level 0 */
+ kBEE_SecurityLevel1 = 1U, /*!< BEE security level 1 */
+ kBEE_SecurityLevel2 = 2U, /*!< BEE security level 2 */
+ kBEE_SecurityLevel3 = 3U /*!< BEE security level 3 */
+} bee_security_level;
+
+/*! @brief BEE status flags. */
+typedef enum _bee_status_flags
+{
+ kBEE_DisableAbortFlag = 1U, /*!< Disable abort flag. */
+ kBEE_Reg0ReadSecViolation = 2U, /*!< Region-0 read channel security violation */
+ kBEE_ReadIllegalAccess = 4U, /*!< Read channel illegal access detected */
+ kBEE_Reg1ReadSecViolation = 8U, /*!< Region-1 read channel security violation */
+ kBEE_Reg0AccessViolation = 16U, /*!< Protected region-0 access violation */
+ kBEE_Reg1AccessViolation = 32U, /*!< Protected region-1 access violation */
+ kBEE_IdleFlag = BEE_STATUS_BEE_IDLE_MASK /*!< Idle flag */
+} bee_status_flags_t;
+
+/*! @brief BEE region configuration structure. */
+typedef struct _bee_region_config
+{
+ bee_aes_mode_t region0Mode; /*!< AES mode used for encryption/decryption for region 0 */
+ bee_aes_mode_t region1Mode; /*!< AES mode used for encryption/decryption for region 1 */
+ uint32_t region0AddrOffset; /*!< Region 0 address offset */
+ uint32_t region1AddrOffset; /*!< Region 1 address offset */
+ bee_security_level region0SecLevel; /*!< Region 0 security level */
+ bee_security_level region1SecLevel; /*!< Region 1 security level */
+ uint32_t region1Bot; /*!< Region 1 bottom address */
+ uint32_t region1Top; /*!< Region 1 top address */
+ bee_ac_prot_enable accessPermission; /*!< Access permission control enable/disable */
+ bee_endian_swap_enable endianSwapEn; /*!< Endian swap enable/disable */
+} bee_region_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Resets BEE module to factory default values.
+ *
+ * This function performs hardware reset of BEE module. Attributes and keys from software for both regions are cleared.
+ *
+ * @param base BEE peripheral address.
+ */
+void BEE_Init(BEE_Type *base);
+
+/*!
+ * @brief Resets BEE module, clears keys for both regions and disables clock to the BEE.
+ *
+ * This function performs hardware reset of BEE module and disables clocks. Attributes and keys from software for both
+ * regions are cleared.
+ *
+ * @param base BEE peripheral address.
+ */
+void BEE_Deinit(BEE_Type *base);
+
+/*!
+ * @brief Enables BEE decryption.
+ *
+ * This function enables decryption using BEE.
+ *
+ * @param base BEE peripheral address.
+ */
+static inline void BEE_Enable(BEE_Type *base)
+{
+ base->CTRL |= BEE_CTRL_BEE_ENABLE_MASK;
+}
+
+/*!
+ * @brief Disables BEE decryption.
+ *
+ * This function disables decryption using BEE.
+ *
+ * @param base BEE peripheral address.
+ */
+static inline void BEE_Disable(BEE_Type *base)
+{
+ base->CTRL &= ~BEE_CTRL_BEE_ENABLE_MASK;
+}
+
+/*!
+ * @brief Loads default values to the BEE region configuration structure.
+ *
+ * Loads default values to the BEE region configuration structure. The default values are as follows:
+ * @code
+ * config->region0Mode = kBEE_AesCtrMode;
+ * config->region1Mode = kBEE_AesCtrMode;
+ * config->region0AddrOffset = 0U;
+ * config->region1AddrOffset = 0U;
+ * config->region0SecLevel = kBEE_SecurityLevel3;
+ * config->region1SecLevel = kBEE_SecurityLevel3;
+ * config->region1Bot = 0U;
+ * config->region1Top = 0U;
+ * config->accessPermission = kBEE_AccessProtDisabled;
+ * config->endianSwapEn = kBEE_EndianSwapEnabled;
+ * @endcode
+ *
+ * @param config Configuration structure for BEE peripheral.
+ */
+void BEE_GetDefaultConfig(bee_region_config_t *config);
+
+/*!
+ * @brief Sets BEE configuration.
+ *
+ * This function sets BEE peripheral and BEE region settings accorging to given configuration structure.
+ *
+ * @param base BEE peripheral address.
+ * @param config Configuration structure for BEE.
+ */
+void BEE_SetConfig(BEE_Type *base, const bee_region_config_t *config);
+
+/*!
+ * @brief Loads the AES key for selected region into BEE key registers.
+ *
+ * This function loads given AES key to BEE register for the given region.
+ * The key must be 32-bit aligned and stored in little-endian format.
+ *
+ * Please note, that eFuse BEE_KEYx_SEL must be set accordingly to be able to load and use key loaded in BEE registers.
+ * Otherwise, key cannot loaded and BEE will use key from OTPMK or SW_GP2.
+ *
+ * @param base BEE peripheral address.
+ * @param region Selection of the BEE region to be configured.
+ * @param key AES key (in little-endian format).
+ * @param keySize Size of AES key.
+ */
+status_t BEE_SetRegionKey(BEE_Type *base, bee_region_t region, const uint8_t *key, size_t keySize);
+
+/*!
+ * @brief Loads the nonce for selected region into BEE nonce registers.
+ *
+ * This function loads given nonce(only AES CTR mode) to BEE register for the given region.
+ * The nonce must be 32-bit aligned and stored in little-endian format.
+ *
+ * @param base BEE peripheral address.
+ * @param region Selection of the BEE region to be configured.
+ * @param nonce AES nonce (in little-endian format).
+ * @param nonceSize Size of AES nonce.
+ */
+status_t BEE_SetRegionNonce(BEE_Type *base, bee_region_t region, const uint8_t *nonce, size_t nonceSize);
+
+/*!
+ * @brief Gets the BEE status flags.
+ *
+ * This function returns status of BEE peripheral.
+ *
+ * @param base BEE peripheral address.
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+uint32_t BEE_GetStatusFlags(BEE_Type *base);
+
+/*!
+ * @brief Clears the BEE status flags.
+ *
+ * @param base BEE peripheral base address.
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+void BEE_ClearStatusFlags(BEE_Type *base, uint32_t mask);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*@}*/
+
+#endif /* _FSL_BEE_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.c b/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.c
new file mode 100644
index 0000000000..721a3fb04e
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_cache.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.cache_armv7_m7"
+#endif
+
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#define L2CACHE_OPERATION_TIMEOUT 0xFFFFFU
+#define L2CACHE_8WAYS_MASK 0xFFU
+#define L2CACHE_16WAYS_MASK 0xFFFFU
+#define L2CACHE_SMALLWAYS_NUM 8U
+#define L2CACHE_1KBCOVERTOB 1024U
+#define L2CACHE_SAMLLWAYS_SIZE 16U
+#define L2CACHE_LOCKDOWN_REGNUM 8 /*!< Lock down register numbers.*/
+ /*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Set for all ways and waiting for the operation finished.
+ * This is provided for all the background operations.
+ *
+ * @param auxCtlReg The auxiliary control register.
+ * @param regAddr The register address to be operated.
+ */
+static void L2CACHE_SetAndWaitBackGroundOperate(uint32_t auxCtlReg, uint32_t regAddr);
+
+/*!
+ * @brief Invalidates the Level 2 cache line by physical address.
+ * This function invalidates a cache line by physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_InvalidateLineByAddr(uint32_t address);
+
+/*!
+ * @brief Cleans the Level 2 cache line based on the physical address.
+ * This function cleans a cache line based on a physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_CleanLineByAddr(uint32_t address);
+
+/*!
+ * @brief Cleans and invalidates the Level 2 cache line based on the physical address.
+ * This function cleans and invalidates a cache line based on a physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_CleanInvalidateLineByAddr(uint32_t address);
+
+/*!
+ * @brief Gets the number of the Level 2 cache and the way size.
+ * This function cleans and invalidates a cache line based on a physcial address.
+ *
+ * @param num_ways The number of the cache way.
+ * @param size_way The way size.
+ */
+static void L2CACHE_GetWayNumSize(uint32_t *num_ways, uint32_t *size_way);
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void L2CACHE_SetAndWaitBackGroundOperate(uint32_t auxCtlReg, uint32_t regAddr)
+{
+ uint16_t mask = L2CACHE_8WAYS_MASK;
+ uint32_t timeout = L2CACHE_OPERATION_TIMEOUT;
+
+ /* Check the ways used at first. */
+ if (auxCtlReg & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK)
+ {
+ mask = L2CACHE_16WAYS_MASK;
+ }
+
+ /* Set the opeartion for all ways/entries of the cache. */
+ *(uint32_t *)regAddr = mask;
+ /* Waiting for until the operation is complete. */
+ while ((*(volatile uint32_t *)regAddr & mask) && timeout)
+ {
+ __ASM("nop");
+ timeout--;
+ }
+}
+
+static uint32_t L2CACHE_InvalidateLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Invalidate the cache line by physical address. */
+ L2CACHEC->REG7_INV_PA = address;
+
+ return address;
+}
+
+static uint32_t L2CACHE_CleanLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Invalidate the cache line by physical address. */
+ L2CACHEC->REG7_CLEAN_PA = address;
+
+ return address;
+}
+
+static uint32_t L2CACHE_CleanInvalidateLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Clean and invalidate the cache line by physical address. */
+ L2CACHEC->REG7_CLEAN_INV_PA = address;
+
+ return address;
+}
+
+static void L2CACHE_GetWayNumSize(uint32_t *num_ways, uint32_t *size_way)
+{
+ assert(num_ways);
+ assert(size_way);
+
+ uint32_t number = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ uint32_t size = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_SHIFT;
+
+ *num_ways = (number + 1) * L2CACHE_SMALLWAYS_NUM;
+ if (!size)
+ {
+ /* 0 internally mapped to the same size as 1 - 16KB.*/
+ size += 1;
+ }
+ *size_way = (1 << (size - 1)) * L2CACHE_SAMLLWAYS_SIZE * L2CACHE_1KBCOVERTOB;
+}
+
+/*!
+ * brief Initializes the level 2 cache controller module.
+ *
+ * param config Pointer to configuration structure. See "l2cache_config_t".
+ */
+void L2CACHE_Init(l2cache_config_t *config)
+{
+ assert(config);
+
+ uint16_t waysNum = 0xFFU; /* Default use the 8-way mask. */
+ uint8_t count;
+ uint32_t auxReg = 0;
+
+ /*The aux register must be configured when the cachec is disabled
+ * So disable first if the cache controller is enabled.
+ */
+ if (L2CACHEC->REG1_CONTROL & L2CACHEC_REG1_CONTROL_CE_MASK)
+ {
+ L2CACHE_Disable();
+ }
+
+ /* Unlock all entries. */
+ if (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK)
+ {
+ waysNum = 0xFFFFU;
+ }
+
+ for (count = 0; count < L2CACHE_LOCKDOWN_REGNUM; count++)
+ {
+ L2CACHE_LockdownByWayEnable(count, waysNum, false);
+ }
+
+ /* Set the ways and way-size etc. */
+ auxReg = L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY(config->wayNum) |
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE(config->waySize) | L2CACHEC_REG1_AUX_CONTROL_CRP(config->repacePolicy) |
+ L2CACHEC_REG1_AUX_CONTROL_IPE(config->istrPrefetchEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_DPE(config->dataPrefetchEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_NLE(config->nsLockdownEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_FWA(config->writeAlloc) | L2CACHEC_REG1_AUX_CONTROL_HPSDRE(config->writeAlloc);
+ L2CACHEC->REG1_AUX_CONTROL = auxReg;
+
+ /* Set the tag/data ram latency. */
+ if (config->lateConfig)
+ {
+ uint32_t data = 0;
+ /* Tag latency. */
+ data = L2CACHEC_REG1_TAG_RAM_CONTROL_SL(config->lateConfig->tagSetupLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_SL(config->lateConfig->tagSetupLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_RAL(config->lateConfig->tagReadLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_WAL(config->lateConfig->dataWriteLate);
+ L2CACHEC->REG1_TAG_RAM_CONTROL = data;
+ /* Data latency. */
+ data = L2CACHEC_REG1_DATA_RAM_CONTROL_SL(config->lateConfig->dataSetupLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_SL(config->lateConfig->dataSetupLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_RAL(config->lateConfig->dataReadLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_WAL(config->lateConfig->dataWriteLate);
+ L2CACHEC->REG1_DATA_RAM_CONTROL = data;
+ }
+}
+
+/*!
+ * brief Gets an available default settings for the cache controller.
+ *
+ * This function initializes the cache controller configuration structure with default settings.
+ * The default values are:
+ * code
+ * config->waysNum = kL2CACHE_8ways;
+ * config->waySize = kL2CACHE_32KbSize;
+ * config->repacePolicy = kL2CACHE_Roundrobin;
+ * config->lateConfig = NULL;
+ * config->istrPrefetchEnable = false;
+ * config->dataPrefetchEnable = false;
+ * config->nsLockdownEnable = false;
+ * config->writeAlloc = kL2CACHE_UseAwcache;
+ * endcode
+ * param config Pointer to the configuration structure.
+ */
+void L2CACHE_GetDefaultConfig(l2cache_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ memset(config, 0, sizeof(*config));
+
+ uint32_t number = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ uint32_t size = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_SHIFT;
+
+ /* Get the default value */
+ config->wayNum = (l2cache_way_num_t)number;
+ config->waySize = (l2cache_way_size)size;
+ config->repacePolicy = kL2CACHE_Roundrobin;
+ config->lateConfig = NULL;
+ config->istrPrefetchEnable = false;
+ config->dataPrefetchEnable = false;
+ config->nsLockdownEnable = false;
+ config->writeAlloc = kL2CACHE_UseAwcache;
+}
+
+/*!
+ * brief Enables the level 2 cache controller.
+ * This function enables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Enable(void)
+{
+ /* Invalidate first. */
+ L2CACHE_Invalidate();
+ /* Enable the level 2 cache controller. */
+ L2CACHEC->REG1_CONTROL = L2CACHEC_REG1_CONTROL_CE_MASK;
+}
+
+/*!
+ * brief Disables the level 2 cache controller.
+ * This function disables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Disable(void)
+{
+ /* First CleanInvalidate all enties in the cache. */
+ L2CACHE_CleanInvalidate();
+ /* Disable the level 2 cache controller. */
+ L2CACHEC->REG1_CONTROL &= ~L2CACHEC_REG1_CONTROL_CE_MASK;
+ /* DSB - data sync barrier.*/
+ __DSB();
+}
+
+/*!
+ * brief Invalidates the Level 2 cache.
+ * This function invalidates all entries in cache.
+ *
+ */
+void L2CACHE_Invalidate(void)
+{
+ /* Invalidate all entries in cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_INV_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans the level 2 cache controller.
+ * This function cleans all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_Clean(void)
+{
+ /* Clean all entries of the cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_CLEAN_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans and invalidates the level 2 cache controller.
+ * This function cleans and invalidates all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_CleanInvalidate(void)
+{
+ /* Clean all entries of the cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_CLEAN_INV_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function invalidates all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t endAddr = address + size_byte;
+
+ /* Invalidate addresses in the range. */
+ while (address < endAddr)
+ {
+ address = L2CACHE_InvalidateLineByAddr(address);
+ /* Update the size. */
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be cleaned.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t num_ways = 0;
+ uint32_t size_way = 0;
+ uint32_t endAddr = address + size_byte;
+
+ /* Get the number and size of the cache way. */
+ L2CACHE_GetWayNumSize(&num_ways, &size_way);
+
+ /* Check if the clean size is over the cache size. */
+ if ((endAddr - address) > num_ways * size_way)
+ {
+ L2CACHE_Clean();
+ return;
+ }
+
+ /* Clean addresses in the range. */
+ while ((address & ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1)) < endAddr)
+ {
+ /* Clean the address in the range. */
+ address = L2CACHE_CleanLineByAddr(address);
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans and invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans and invalidates all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be cleaned and invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t num_ways = 0;
+ uint32_t size_way = 0;
+ uint32_t endAddr = address + size_byte;
+
+ /* Get the number and size of the cache way. */
+ L2CACHE_GetWayNumSize(&num_ways, &size_way);
+
+ /* Check if the clean size is over the cache size. */
+ if ((endAddr - address) > num_ways * size_way)
+ {
+ L2CACHE_CleanInvalidate();
+ return;
+ }
+
+ /* Clean addresses in the range. */
+ while ((address & ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1)) < endAddr)
+ {
+ /* Clean the address in the range. */
+ address = L2CACHE_CleanInvalidateLineByAddr(address);
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Enables or disables to lock down the data and instruction by way.
+ * This function locks down the cached instruction/data by way and prevent the adresses from
+ * being allocated and prevent dara from being evicted out of the level 2 cache.
+ * But the normal cache maintenance operations that invalidate, clean or clean
+ * and validate cache contents affect the locked-down cache lines as normal.
+ *
+ * param masterId The master id, range from 0 ~ 7.
+ * param mask The ways to be enabled or disabled to lockdown.
+ * each bit in value is related to each way of the cache. for example:
+ * value: bit 0 ------ way 0.
+ * value: bit 1 ------ way 1.
+ * --------------------------
+ * value: bit 15 ------ way 15.
+ * Note: please make sure the value setting is align with your supported ways.
+ * param enable True enable the lockdown, false to disable the lockdown.
+ */
+void L2CACHE_LockdownByWayEnable(uint32_t masterId, uint32_t mask, bool enable)
+{
+ uint8_t num_ways = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ num_ways = (num_ways + 1) * L2CACHE_SMALLWAYS_NUM;
+
+ assert(mask < (1U << num_ways));
+ assert(masterId < L2CACHE_LOCKDOWN_REGNUM);
+
+ uint32_t dataReg = L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN;
+ uint32_t istrReg = L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN;
+
+ if (enable)
+ {
+ /* Data lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN = dataReg | mask;
+ /* Instruction lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN = istrReg | mask;
+ }
+ else
+ {
+ /* Data lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN = dataReg & ~mask;
+ /* Instruction lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN = istrReg & ~mask;
+ }
+}
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+
+/*!
+ * brief Invalidate cortex-m7 L1 instruction cache by range.
+ *
+ * param address The start address of the memory to be invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 I-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L1CACHE_InvalidateICacheByRange(uint32_t address, uint32_t size_byte)
+{
+#if (__DCACHE_PRESENT == 1U)
+ uint32_t addr = address & ~((uint32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE - 1U);
+ uint32_t align_len = address - addr;
+ int32_t size = (int32_t)size_byte + (int32_t)align_len;
+
+ __DSB();
+ while (size > 0)
+ {
+ SCB->ICIMVAU = addr;
+ addr += (uint32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE;
+ size -= (int32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE;
+ }
+ __DSB();
+ __ISB();
+#endif
+}
+
+/*!
+ * brief Invalidates all instruction caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void ICACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_InvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+
+ L1CACHE_InvalidateICacheByRange(address, size_byte);
+}
+
+/*!
+ * brief Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_InvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+ L1CACHE_InvalidateDCacheByRange(address, size_byte);
+}
+
+/*!
+ * brief Cleans all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be cleaned.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanByRange(uint32_t address, uint32_t size_byte)
+{
+ L1CACHE_CleanDCacheByRange(address, size_byte);
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_CleanByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+}
+
+/*!
+ * brief Cleans and Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be cleaned and invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ L1CACHE_CleanInvalidateDCacheByRange(address, size_byte);
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_CleanInvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.h b/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.h
new file mode 100644
index 0000000000..1ed0597c0c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cache/armv7-m7/fsl_cache.h
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_CACHE_H_
+#define _FSL_CACHE_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup cache_armv7_m7
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief cache driver version 2.0.4. */
+#define FSL_CACHE_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#ifndef FSL_SDK_DISBLE_L2CACHE_PRESENT
+#define FSL_SDK_DISBLE_L2CACHE_PRESENT 0
+#endif
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+
+/*! @brief Number of level 2 cache controller ways. */
+typedef enum _l2cache_way_num
+{
+ kL2CACHE_8ways = 0, /*!< 8 ways. */
+#if defined(FSL_FEATURE_L2CACHE_SUPPORT_16_WAY_ASSOCIATIVITY) && FSL_FEATURE_L2CACHE_SUPPORT_16_WAY_ASSOCIATIVITY
+ kL2CACHE_16ways /*!< 16 ways. */
+#endif /* FSL_FEATURE_L2CACHE_SUPPORT_16_WAY_ASSOCIATIVITY */
+} l2cache_way_num_t;
+
+/*! @brief Level 2 cache controller way size. */
+typedef enum _l2cache_way_size
+{
+ kL2CACHE_16KBSize = 1, /*!< 16 KB way size. */
+ kL2CACHE_32KBSize = 2, /*!< 32 KB way size. */
+ kL2CACHE_64KBSize = 3, /*!< 64 KB way size. */
+ kL2CACHE_128KBSize = 4, /*!< 128 KB way size. */
+ kL2CACHE_256KBSize = 5, /*!< 256 KB way size. */
+ kL2CACHE_512KBSize = 6 /*!< 512 KB way size. */
+} l2cache_way_size;
+
+/*! @brief Level 2 cache controller replacement policy. */
+typedef enum _l2cache_replacement
+{
+ kL2CACHE_Pseudorandom = 0U, /*!< Peseudo-random replacement policy using an lfsr. */
+ kL2CACHE_Roundrobin /*!< Round-robin replacemnt policy. */
+} l2cache_replacement_t;
+
+/*! @brief Level 2 cache controller force write allocate options. */
+typedef enum _l2cache_writealloc
+{
+ kL2CACHE_UseAwcache = 0, /*!< Use AWCAHE attribute for the write allocate. */
+ kL2CACHE_NoWriteallocate, /*!< Force no write allocate. */
+ kL2CACHE_forceWriteallocate /*!< Force write allocate when write misses. */
+} l2cache_writealloc_t;
+
+/*! @brief Level 2 cache controller tag/data ram latency. */
+typedef enum _l2cache_latency
+{
+ kL2CACHE_1CycleLate = 0, /*!< 1 cycle of latency. */
+ kL2CACHE_2CycleLate, /*!< 2 cycle of latency. */
+ kL2CACHE_3CycleLate, /*!< 3 cycle of latency. */
+ kL2CACHE_4CycleLate, /*!< 4 cycle of latency. */
+ kL2CACHE_5CycleLate, /*!< 5 cycle of latency. */
+ kL2CACHE_6CycleLate, /*!< 6 cycle of latency. */
+ kL2CACHE_7CycleLate, /*!< 7 cycle of latency. */
+ kL2CACHE_8CycleLate /*!< 8 cycle of latency. */
+} l2cache_latency_t;
+
+/*! @brief Level 2 cache controller tag/data ram latency configure structure. */
+typedef struct _l2cache_latency_config
+{
+ l2cache_latency_t tagWriteLate; /*!< Tag write latency. */
+ l2cache_latency_t tagReadLate; /*!< Tag Read latency. */
+ l2cache_latency_t tagSetupLate; /*!< Tag setup latency. */
+ l2cache_latency_t dataWriteLate; /*!< Data write latency. */
+ l2cache_latency_t dataReadLate; /*!< Data Read latency. */
+ l2cache_latency_t dataSetupLate; /*!< Data setup latency. */
+} L2cache_latency_config_t;
+
+/*! @brief Level 2 cache controller configure structure. */
+typedef struct _l2cache_config
+{
+ /* ------------------------ l2 cachec basic settings ---------------------------- */
+ l2cache_way_num_t wayNum; /*!< The number of ways. */
+ l2cache_way_size waySize; /*!< The way size = Cache Ram size / wayNum. */
+ l2cache_replacement_t repacePolicy; /*!< Replacemnet policy. */
+ /* ------------------------ tag/data ram latency settings ----------------------- */
+ L2cache_latency_config_t *lateConfig; /*!< Tag/data latency configure. Set NUll if not required. */
+ /* ------------------------ Prefetch enable settings ---------------------------- */
+ bool istrPrefetchEnable; /*!< Instruction prefetch enable. */
+ bool dataPrefetchEnable; /*!< Data prefetch enable. */
+ /* ------------------------ Non-secure access settings -------------------------- */
+ bool nsLockdownEnable; /*!< None-secure lockdown enable. */
+ /* ------------------------ other settings -------------------------------------- */
+ l2cache_writealloc_t writeAlloc; /*!< Write allcoate force option. */
+} l2cache_config_t;
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Control for cortex-m7 L1 cache
+ *@{
+ */
+
+/*!
+ * @brief Enables cortex-m7 L1 instruction cache.
+ *
+ */
+static inline void L1CACHE_EnableICache(void)
+{
+ SCB_EnableICache();
+}
+
+/*!
+ * @brief Disables cortex-m7 L1 instruction cache.
+ *
+ */
+static inline void L1CACHE_DisableICache(void)
+{
+ if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR))
+ {
+ SCB_DisableICache();
+ }
+}
+
+/*!
+ * @brief Invalidate cortex-m7 L1 instruction cache.
+ *
+ */
+static inline void L1CACHE_InvalidateICache(void)
+{
+ SCB_InvalidateICache();
+}
+
+/*!
+ * @brief Invalidate cortex-m7 L1 instruction cache by range.
+ *
+ * @param address The start address of the memory to be invalidated.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 I-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L1CACHE_InvalidateICacheByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Enables cortex-m7 L1 data cache.
+ *
+ */
+static inline void L1CACHE_EnableDCache(void)
+{
+ SCB_EnableDCache();
+}
+
+/*!
+ * @brief Disables cortex-m7 L1 data cache.
+ *
+ */
+static inline void L1CACHE_DisableDCache(void)
+{
+ if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR))
+ {
+ SCB_DisableDCache();
+ }
+}
+
+/*!
+ * @brief Invalidates cortex-m7 L1 data cache.
+ *
+ */
+static inline void L1CACHE_InvalidateDCache(void)
+{
+ SCB_InvalidateDCache();
+}
+
+/*!
+ * @brief Cleans cortex-m7 L1 data cache.
+ *
+ */
+static inline void L1CACHE_CleanDCache(void)
+{
+ SCB_CleanDCache();
+}
+
+/*!
+ * @brief Cleans and Invalidates cortex-m7 L1 data cache.
+ *
+ */
+static inline void L1CACHE_CleanInvalidateDCache(void)
+{
+ SCB_CleanInvalidateDCache();
+}
+
+/*!
+ * @brief Invalidates cortex-m7 L1 data cache by range.
+ *
+ * @param address The start address of the memory to be invalidated.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 D-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+static inline void L1CACHE_InvalidateDCacheByRange(uint32_t address, uint32_t size_byte)
+{
+ SCB_InvalidateDCache_by_Addr((uint32_t *)address, (int32_t)size_byte);
+}
+
+/*!
+ * @brief Cleans cortex-m7 L1 data cache by range.
+ *
+ * @param address The start address of the memory to be cleaned.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 D-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+static inline void L1CACHE_CleanDCacheByRange(uint32_t address, uint32_t size_byte)
+{
+ SCB_CleanDCache_by_Addr((uint32_t *)address, (int32_t)size_byte);
+}
+
+/*!
+ * @brief Cleans and Invalidates cortex-m7 L1 data cache by range.
+ *
+ * @param address The start address of the memory to be clean and invalidated.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 D-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+static inline void L1CACHE_CleanInvalidateDCacheByRange(uint32_t address, uint32_t size_byte)
+{
+ SCB_CleanInvalidateDCache_by_Addr((uint32_t *)address, (int32_t)size_byte);
+}
+/*@}*/
+
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+/*!
+ * @name Control for L2 pl310 cache
+ *@{
+ */
+
+/*!
+ * @brief Initializes the level 2 cache controller module.
+ *
+ * @param config Pointer to configuration structure. See "l2cache_config_t".
+ */
+void L2CACHE_Init(l2cache_config_t *config);
+
+/*!
+ * @brief Gets an available default settings for the cache controller.
+ *
+ * This function initializes the cache controller configuration structure with default settings.
+ * The default values are:
+ * @code
+ * config->waysNum = kL2CACHE_8ways;
+ * config->waySize = kL2CACHE_32KbSize;
+ * config->repacePolicy = kL2CACHE_Roundrobin;
+ * config->lateConfig = NULL;
+ * config->istrPrefetchEnable = false;
+ * config->dataPrefetchEnable = false;
+ * config->nsLockdownEnable = false;
+ * config->writeAlloc = kL2CACHE_UseAwcache;
+ * @endcode
+ * @param config Pointer to the configuration structure.
+ */
+void L2CACHE_GetDefaultConfig(l2cache_config_t *config);
+
+/*!
+ * @brief Enables the level 2 cache controller.
+ * This function enables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Enable(void);
+
+/*!
+ * @brief Disables the level 2 cache controller.
+ * This function disables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Disable(void);
+
+/*!
+ * @brief Invalidates the Level 2 cache.
+ * This function invalidates all entries in cache.
+ *
+ */
+void L2CACHE_Invalidate(void);
+
+/*!
+ * @brief Invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function invalidates all cache lines between two physical addresses.
+ *
+ * @param address The start address of the memory to be invalidated.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_InvalidateByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Cleans the level 2 cache controller.
+ * This function cleans all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_Clean(void);
+
+/*!
+ * @brief Cleans the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans all cache lines between two physical addresses.
+ *
+ * @param address The start address of the memory to be cleaned.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Cleans and invalidates the level 2 cache controller.
+ * This function cleans and invalidates all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_CleanInvalidate(void);
+
+/*!
+ * @brief Cleans and invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans and invalidates all cache lines between two physical addresses.
+ *
+ * @param address The start address of the memory to be cleaned and invalidated.
+ * @param size_byte The memory size.
+ * @note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Enables or disables to lock down the data and instruction by way.
+ * This function locks down the cached instruction/data by way and prevent the adresses from
+ * being allocated and prevent dara from being evicted out of the level 2 cache.
+ * But the normal cache maintenance operations that invalidate, clean or clean
+ * and validate cache contents affect the locked-down cache lines as normal.
+ *
+ * @param masterId The master id, range from 0 ~ 7.
+ * @param mask The ways to be enabled or disabled to lockdown.
+ * each bit in value is related to each way of the cache. for example:
+ * value: bit 0 ------ way 0.
+ * value: bit 1 ------ way 1.
+ * --------------------------
+ * value: bit 15 ------ way 15.
+ * Note: please make sure the value setting is align with your supported ways.
+ * @param enable True enable the lockdown, false to disable the lockdown.
+ */
+void L2CACHE_LockdownByWayEnable(uint32_t masterId, uint32_t mask, bool enable);
+
+/*@}*/
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+
+/*!
+ * @name Unified Cache Control for all caches (cortex-m7 L1 cache + l2 pl310)
+ * Mainly used for many drivers for easy cache operation.
+ *@{
+ */
+
+/*!
+ * @brief Invalidates all instruction caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * @param address The physical address.
+ * @param size_byte size of the memory to be invalidated.
+ * @note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void ICACHE_InvalidateByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * @param address The physical address.
+ * @param size_byte size of the memory to be invalidated.
+ * @note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_InvalidateByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Cleans all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * @param address The physical address.
+ * @param size_byte size of the memory to be cleaned.
+ * @note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanByRange(uint32_t address, uint32_t size_byte);
+
+/*!
+ * @brief Cleans and Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * @param address The physical address.
+ * @param size_byte size of the memory to be cleaned and invalidated.
+ * @note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_CACHE_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.c b/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.c
new file mode 100644
index 0000000000..9b985e1cbd
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_cdog.h"
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.cdog"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Sets the default configuration of CDOG
+ *
+ * This function initialize CDOG config structure to default values.
+ *
+ * param conf CDOG configuration structure
+ */
+void CDOG_GetDefaultConfig(cdog_config_t *conf)
+{
+ /* Default configuration after reset */
+ conf->lock = (uint8_t)kCDOG_LockCtrl_Unlock; /* Lock control */
+ conf->timeout = (uint8_t)kCDOG_FaultCtrl_NoAction; /* Timeout control */
+ conf->miscompare = (uint8_t)kCDOG_FaultCtrl_NoAction; /* Miscompare control */
+ conf->sequence = (uint8_t)kCDOG_FaultCtrl_NoAction; /* Sequence control */
+ conf->state = (uint8_t)kCDOG_FaultCtrl_NoAction; /* State control */
+ conf->address = (uint8_t)kCDOG_FaultCtrl_NoAction; /* Address control */
+ conf->irq_pause = (uint8_t)kCDOG_IrqPauseCtrl_Run; /* IRQ pause control */
+ conf->debug_halt = (uint8_t)kCDOG_DebugHaltCtrl_Run; /* Debug halt control */
+ return;
+}
+
+/*!
+ * brief Sets secure counter and instruction timer values
+ *
+ * This function sets value in RELOAD and START registers for instruction timer.
+ *
+ * param base CDOG peripheral base address
+ * param reload reload value
+ * param start start value
+ */
+void CDOG_Start(CDOG_Type *base, uint32_t reload, uint32_t start)
+{
+ base->RELOAD = reload;
+ base->START = start;
+}
+
+/*!
+ * brief Stops secure counter and instruction timer
+ *
+ * This function stops instruction timer and secure counter.
+ * This also change state of CDOG to IDLE.
+ *
+ * param base CDOG peripheral base address
+ * param stop expected value which will be compared with value of secure counter
+ */
+void CDOG_Stop(CDOG_Type *base, uint32_t stop)
+{
+ base->STOP = stop;
+}
+
+/*!
+ * brief Sets secure counter and instruction timer values
+ *
+ * This function sets value in STOP, RELOAD and START registers
+ * for instruction timer and secure counter.
+ *
+ * param base CDOG peripheral base address
+ * param stop expected value which will be compared with value of secure counter
+ * param reload reload value for instruction timer
+ * param start start value for secure timer
+ */
+void CDOG_Set(CDOG_Type *base, uint32_t stop, uint32_t reload, uint32_t start)
+{
+ base->STOP = stop;
+ base->RELOAD = reload;
+ base->START = start;
+}
+
+/*!
+ * brief Add value to secure counter
+ *
+ * This function add specified value to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param add Value to be added.
+ */
+void CDOG_Add(CDOG_Type *base, uint32_t add)
+{
+ base->ADD = (secure_counter_t)add;
+}
+
+/*!
+ * brief Add 1 to secure counter
+ *
+ * This function add 1 to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param add Value to be added.
+ */
+void CDOG_Add1(CDOG_Type *base)
+{
+ base->ADD1 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Add 16 to secure counter
+ *
+ * This function add 16 to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param add Value to be added.
+ */
+void CDOG_Add16(CDOG_Type *base)
+{
+ base->ADD16 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Add 256 to secure counter
+ *
+ * This function add 256 to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param add Value to be added.
+ */
+void CDOG_Add256(CDOG_Type *base)
+{
+ base->ADD256 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Substract value to secure counter
+ *
+ * This function substract specified value to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param sub Value to be substracted.
+ */
+void CDOG_Sub(CDOG_Type *base, uint32_t sub)
+{
+ base->SUB = (secure_counter_t)sub;
+}
+
+/*!
+ * brief Substract 1 from secure counter
+ *
+ * This function substract specified 1 from secure counter.
+ *
+ * param base CDOG peripheral base address.
+ */
+void CDOG_Sub1(CDOG_Type *base)
+{
+ base->SUB1 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Substract 16 from secure counter
+ *
+ * This function substract specified 16 from secure counter.
+ *
+ * param base CDOG peripheral base address.
+ */
+void CDOG_Sub16(CDOG_Type *base)
+{
+ base->SUB16 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Substract 256 from secure counter
+ *
+ * This function substract specified 256 from secure counter.
+ *
+ * param base CDOG peripheral base address.
+ */
+void CDOG_Sub256(CDOG_Type *base)
+{
+ base->SUB256 = (secure_counter_t)0x1U;
+}
+
+/*!
+ * brief Checks secure counter.
+ *
+ * This function compares stop value with secure counter value
+ * by writting to RELOAD refister.
+ *
+ * param base CDOG peripheral base address
+ * param check expected (stop) value.
+ */
+void CDOG_Check(CDOG_Type *base, uint32_t check)
+{
+ base->RESTART = check;
+}
+
+/*!
+ * brief Set the CDOG persistent word.
+ *
+ * param base CDOG peripheral base address.
+ * param value The value to be written.
+ */
+void CDOG_WritePersistent(CDOG_Type *base, uint32_t value)
+{
+ base->PERSISTENT = value;
+}
+
+/*!
+ * brief Get the CDOG persistent word.
+ *
+ * param base CDOG peripheral base address.
+ * return The persistent word.
+ */
+uint32_t CDOG_ReadPersistent(CDOG_Type *base)
+{
+ return base->PERSISTENT;
+}
+
+/*!
+ * brief Initialize CDOG
+ *
+ * This function initializes CDOG block and setting.
+ *
+ * param base CDOG peripheral base address
+ * param conf CDOG configuration structure
+ * return Status of the init operation
+ */
+status_t CDOG_Init(CDOG_Type *base, cdog_config_t *conf)
+{
+ /* Ungate clock to CDOG engine and reset it */
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#ifdef CDOG_CLOCKS
+ CLOCK_EnableClock(kCLOCK_Cdog);
+#endif /* CDOG_CLOCKS */
+#endif /* !FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if !(defined(FSL_FEATURE_CDOG_HAS_NO_RESET) && FSL_FEATURE_CDOG_HAS_NO_RESET)
+ RESET_PeripheralReset(kCDOG_RST_SHIFT_RSTn);
+#endif /* !FSL_FEATURE_CDOG_HAS_NO_RESET */
+
+ if (base->CONTROL == 0x0U)
+ {
+ /* CDOG is not in IDLE mode, which may be cause after SW reset. */
+ /* Writing to CONTROL register will trigger fault. */
+ return kStatus_Fail;
+ }
+
+ /* Clear pending errors, otherwise the device will reset */
+ /* itself immediately after enable Code Watchdog */
+ if ((uint32_t)kCDOG_LockCtrl_Lock ==
+ ((base->CONTROL & CDOG_CONTROL_LOCK_CTRL_MASK) >> CDOG_CONTROL_LOCK_CTRL_SHIFT))
+
+ {
+ CDOG->FLAGS = CDOG_FLAGS_TO_FLAG(1U) | CDOG_FLAGS_MISCOM_FLAG(1U) | CDOG_FLAGS_SEQ_FLAG(1U) |
+ CDOG_FLAGS_CNT_FLAG(1U) | CDOG_FLAGS_STATE_FLAG(1U) | CDOG_FLAGS_ADDR_FLAG(1U) |
+ CDOG_FLAGS_POR_FLAG(1U);
+ }
+ else
+ {
+ CDOG->FLAGS = CDOG_FLAGS_TO_FLAG(0U) | CDOG_FLAGS_MISCOM_FLAG(0U) | CDOG_FLAGS_SEQ_FLAG(0U) |
+ CDOG_FLAGS_CNT_FLAG(0U) | CDOG_FLAGS_STATE_FLAG(0U) | CDOG_FLAGS_ADDR_FLAG(0U) |
+ CDOG_FLAGS_POR_FLAG(0U);
+ }
+
+ base->CONTROL =
+ CDOG_CONTROL_TIMEOUT_CTRL(conf->timeout) | /* Action if the timeout event is triggered */
+ CDOG_CONTROL_MISCOMPARE_CTRL(conf->miscompare) | /* Action if the miscompare error event is triggered */
+ CDOG_CONTROL_SEQUENCE_CTRL(conf->sequence) | /* Action if the sequence error event is triggered */
+ CDOG_CONTROL_STATE_CTRL(conf->state) | /* Action if the state error event is triggered */
+ CDOG_CONTROL_ADDRESS_CTRL(conf->address) | /* Action if the address error event is triggered */
+ CDOG_CONTROL_IRQ_PAUSE(conf->irq_pause) | /* Pause running during interrupts setup */
+ CDOG_CONTROL_DEBUG_HALT_CTRL(
+ conf->debug_halt) | /* Halt CDOG timer during debug so we have chance to debug code */
+ CDOG_CONTROL_LOCK_CTRL(conf->lock); /* Lock control register */
+
+ NVIC_EnableIRQ(CDOG_IRQn);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Deinitialize CDOG
+ *
+ * This function stops CDOG secure counter.
+ *
+ * param base CDOG peripheral base address
+ */
+void CDOG_Deinit(CDOG_Type *base)
+{
+ NVIC_DisableIRQ(CDOG_IRQn);
+
+#if !(defined(FSL_FEATURE_CDOG_HAS_NO_RESET) && FSL_FEATURE_CDOG_HAS_NO_RESET)
+ RESET_SetPeripheralReset(kCDOG_RST_SHIFT_RSTn);
+#endif /* !FSL_FEATURE_CDOG_HAS_NO_RESET */
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#ifdef CDOG_CLOCKS
+ CLOCK_DisableClock(kCLOCK_Cdog);
+#endif /* CDOG_CLOCKS */
+#endif /* !FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.h b/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.h
new file mode 100644
index 0000000000..b93c8dbdfe
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cdog/fsl_cdog.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_CDOG_H_
+#define _FSL_CDOG_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup CDOG
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Defines CDOG driver version 2.1.1.
+ *
+ * Change log:
+ * - Version 2.1.1
+ * - Remove bit CONTROL[CONTROL_CTRL]
+ * - Version 2.1.0
+ * - Rename CWT to CDOG
+ * - Version 2.0.2
+ * - Fix MISRA-2012 issues
+ * - Version 2.0.1
+ * - Fix doxygen issues
+ * - Version 2.0.0
+ * - initial version
+ */
+#define FSL_CDOG_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+
+typedef struct
+{
+ uint8_t lock : 2;
+ uint8_t timeout : 3;
+ uint8_t miscompare : 3;
+ uint8_t sequence : 3;
+ uint8_t state : 3;
+ uint8_t address : 3;
+ uint8_t reserved : 8;
+ uint8_t irq_pause : 2;
+ uint8_t debug_halt : 2;
+} cdog_config_t;
+
+enum __cdog_debug_Action_ctrl_enum
+{
+ kCDOG_DebugHaltCtrl_Run = 0x1,
+ kCDOG_DebugHaltCtrl_Pause = 0x2,
+};
+
+enum __cdog_irq_pause_ctrl_enum
+{
+ kCDOG_IrqPauseCtrl_Run = 0x1,
+ kCDOG_IrqPauseCtrl_Pause = 0x2,
+};
+
+enum __cdog_fault_ctrl_enum
+{
+ kCDOG_FaultCtrl_EnableReset = 0x1U,
+ kCDOG_FaultCtrl_EnableInterrupt = 0x2U,
+ kCDOG_FaultCtrl_NoAction = 0x4U,
+};
+
+enum __code_lock_ctrl_enum
+{
+ kCDOG_LockCtrl_Lock = 0x1,
+ kCDOG_LockCtrl_Unlock = 0x2,
+};
+
+typedef uint32_t secure_counter_t;
+
+#define SC_ADD(add) \
+ do \
+ { \
+ CDOG->ADD = (secure_counter_t)(add); \
+ } while (0)
+
+#define SC_ADD1 \
+ do \
+ { \
+ CDOG->ADD1 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_ADD16 \
+ do \
+ { \
+ CDOG->ADD16 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_ADD256 \
+ do \
+ { \
+ CDOG->ADD256 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_SUB(sub) \
+ do \
+ { \
+ CDOG->SUB = (secure_counter_t)(sub); \
+ } while (0)
+
+#define SC_SUB1 \
+ do \
+ { \
+ CDOG->SUB1 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_SUB16 \
+ do \
+ { \
+ CDOG->SUB16 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_SUB256 \
+ do \
+ { \
+ CDOG->SUB256 = (secure_counter_t)0x1U; \
+ } while (0)
+
+#define SC_CHECK(val) \
+ do \
+ { \
+ CDOG->RESTART = (secure_counter_t)val; \
+ } while (0)
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+extern void CDOG_DriverIRQHandler(void);
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name CDOG Functional Operation
+ * @{
+ */
+
+/*!
+ * @brief Initialize CDOG
+ *
+ * This function initializes CDOG block and setting.
+ *
+ * @param base CDOG peripheral base address
+ * @param conf CDOG configuration structure
+ * @return Status of the init operation
+ */
+status_t CDOG_Init(CDOG_Type *base, cdog_config_t *conf);
+
+/*!
+ * @brief Deinitialize CDOG
+ *
+ * This function deinitializes CDOG secure counter.
+ *
+ * @param base CDOG peripheral base address
+ */
+void CDOG_Deinit(CDOG_Type *base);
+
+/*!
+ * @brief Sets the default configuration of CDOG
+ *
+ * This function initialize CDOG config structure to default values.
+ *
+ * @param conf CDOG configuration structure
+ */
+void CDOG_GetDefaultConfig(cdog_config_t *conf);
+
+/*!
+ * @brief Stops secure counter and instruction timer
+ *
+ * This function stops instruction timer and secure counter.
+ * This also change state od CDOG to IDLE.
+ *
+ * @param base CDOG peripheral base address
+ * @param stop expected value which will be compared with value of secure counter
+ */
+void CDOG_Stop(CDOG_Type *base, uint32_t stop);
+
+/*!
+ * @brief Sets secure counter and instruction timer values
+ *
+ * This function sets value in RELOAD and START registers
+ * for instruction timer and secure counter
+ *
+ * @param base CDOG peripheral base address
+ * @param reload reload value
+ * @param start start value
+ */
+void CDOG_Start(CDOG_Type *base, uint32_t reload, uint32_t start);
+
+/*!
+ * @brief Checks secure counter.
+ *
+ * This function compares stop value in handler with secure counter value
+ * by writting to RELOAD refister.
+ *
+ * @param base CDOG peripheral base address
+ * @param check expected (stop) value
+ */
+void CDOG_Check(CDOG_Type *base, uint32_t check);
+
+/*!
+ * @brief Sets secure counter and instruction timer values
+ *
+ * This function sets value in STOP, RELOAD and START registers
+ * for instruction timer and secure counter.
+ *
+ * @param base CDOG peripheral base address
+ * @param stop expected value which will be compared with value of secure counter
+ * @param reload reload value for instruction timer
+ * @param start start value for secure timer
+ */
+void CDOG_Set(CDOG_Type *base, uint32_t stop, uint32_t reload, uint32_t start);
+
+/*!
+ * @brief Add value to secure counter
+ *
+ * This function add specified value to secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ * @param add Value to be added.
+ */
+void CDOG_Add(CDOG_Type *base, uint32_t add);
+
+/*!
+ * @brief Add 1 to secure counter
+ *
+ * This function add 1 to secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Add1(CDOG_Type *base);
+
+/*!
+ * @brief Add 16 to secure counter
+ *
+ * This function add 16 to secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Add16(CDOG_Type *base);
+
+/*!
+ * @brief Add 256 to secure counter
+ *
+ * This function add 256 to secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Add256(CDOG_Type *base);
+
+/*!
+ * brief Substract value to secure counter
+ *
+ * This function substract specified value to secure counter.
+ *
+ * param base CDOG peripheral base address.
+ * param sub Value to be substracted.
+ */
+void CDOG_Sub(CDOG_Type *base, uint32_t sub);
+
+/*!
+ * @brief Substract 1 from secure counter
+ *
+ * This function substract specified 1 from secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Sub1(CDOG_Type *base);
+
+/*!
+ * @brief Substract 16 from secure counter
+ *
+ * This function substract specified 16 from secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Sub16(CDOG_Type *base);
+
+/*!
+ * @brief Substract 256 from secure counter
+ *
+ * This function substract specified 256 from secure counter.
+ *
+ * @param base CDOG peripheral base address.
+ */
+void CDOG_Sub256(CDOG_Type *base);
+
+/*!
+ * @brief Set the CDOG persistent word.
+ *
+ * @param base CDOG peripheral base address.
+ * @param value The value to be written.
+ */
+void CDOG_WritePersistent(CDOG_Type *base, uint32_t value);
+
+/*!
+ * @brief Get the CDOG persistent word.
+ *
+ * @param base CDOG peripheral base address.
+ * @return The persistent word.
+ */
+uint32_t CDOG_ReadPersistent(CDOG_Type *base);
+
+/*! @}*/
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/ /* end of group cdog */
+
+#endif /* _FSL_CDOG_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.c b/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.c
new file mode 100644
index 0000000000..8f6bed69b4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_cmp.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.cmp"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for CMP module.
+ *
+ * @param base CMP peripheral base address
+ */
+static uint32_t CMP_GetInstance(CMP_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to CMP bases for each instance. */
+static CMP_Type *const s_cmpBases[] = CMP_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to CMP clocks for each instance. */
+static const clock_ip_name_t s_cmpClocks[] = CMP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t CMP_GetInstance(CMP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_cmpBases); instance++)
+ {
+ if (s_cmpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_cmpBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the CMP.
+ *
+ * This function initializes the CMP module. The operations included are as follows.
+ * - Enabling the clock for CMP module.
+ * - Configuring the comparator.
+ * - Enabling the CMP module.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, to enable the clock for
+ * any instance enables all CMPs. See the appropriate MCU reference manual for the clock assignment of the CMP.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void CMP_Init(CMP_Type *base, const cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure. */
+ CMP_Enable(base, false); /* Disable the CMP module during configuring. */
+ /* CMPx_CR1. */
+ tmp8 = (uint8_t)(base->CR1 & ~(CMP_CR1_PMODE_MASK | CMP_CR1_INV_MASK | CMP_CR1_COS_MASK | CMP_CR1_OPE_MASK));
+ if (true == config->enableHighSpeed)
+ {
+ tmp8 |= CMP_CR1_PMODE_MASK;
+ }
+ if (true == config->enableInvertOutput)
+ {
+ tmp8 |= CMP_CR1_INV_MASK;
+ }
+ if (true == config->useUnfilteredOutput)
+ {
+ tmp8 |= CMP_CR1_COS_MASK;
+ }
+ if (true == config->enablePinOut)
+ {
+ tmp8 |= CMP_CR1_OPE_MASK;
+ }
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ if (true == config->enableTriggerMode)
+ {
+ tmp8 |= CMP_CR1_TRIGM_MASK;
+ }
+ else
+ {
+ tmp8 &= ~(uint8_t)CMP_CR1_TRIGM_MASK;
+ }
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+ base->CR1 = tmp8;
+
+ /* CMPx_CR0. */
+ tmp8 = base->CR0 & ~(uint8_t)CMP_CR0_HYSTCTR_MASK;
+ tmp8 |= CMP_CR0_HYSTCTR(config->hysteresisMode);
+ base->CR0 = tmp8;
+
+ CMP_Enable(base, config->enableCmp); /* Enable the CMP module after configured or not. */
+}
+
+/*!
+ * brief De-initializes the CMP module.
+ *
+ * This function de-initializes the CMP module. The operations included are as follows.
+ * - Disabling the CMP module.
+ * - Disabling the clock for CMP module.
+ *
+ * This function disables the clock for the CMP.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, before disabling the
+ * clock for the CMP, ensure that all the CMP instances are not used.
+ *
+ * param base CMP peripheral base address.
+ */
+void CMP_Deinit(CMP_Type *base)
+{
+ /* Disable the CMP module. */
+ CMP_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Initializes the CMP user configuration structure.
+ *
+ * This function initializes the user configuration structure to these default values.
+ * code
+ * config->enableCmp = true;
+ * config->hysteresisMode = kCMP_HysteresisLevel0;
+ * config->enableHighSpeed = false;
+ * config->enableInvertOutput = false;
+ * config->useUnfilteredOutput = false;
+ * config->enablePinOut = false;
+ * config->enableTriggerMode = false;
+ * endcode
+ * param config Pointer to the configuration structure.
+ */
+void CMP_GetDefaultConfig(cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableCmp = true; /* Enable the CMP module after initialization. */
+ config->hysteresisMode = kCMP_HysteresisLevel0;
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ config->enableTriggerMode = false;
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+}
+
+/*!
+ * brief Sets the input channels for the comparator.
+ *
+ * This function sets the input channels for the comparator.
+ * Note that two input channels cannot be set the same way in the application. When the user selects the same input
+ * from the analog mux to the positive and negative port, the comparator is disabled automatically.
+ *
+ * param base CMP peripheral base address.
+ * param positiveChannel Positive side input channel number. Available range is 0-7.
+ * param negativeChannel Negative side input channel number. Available range is 0-7.
+ */
+void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel)
+{
+ uint8_t tmp8 = base->MUXCR;
+
+ tmp8 &= ~(uint8_t)(CMP_MUXCR_PSEL_MASK | CMP_MUXCR_MSEL_MASK);
+ tmp8 |= CMP_MUXCR_PSEL(positiveChannel) | CMP_MUXCR_MSEL(negativeChannel);
+ base->MUXCR = tmp8;
+}
+
+#if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
+/*!
+ * brief Enables/disables the DMA request for rising/falling events.
+ *
+ * This function enables/disables the DMA request for rising/falling events. Either event triggers the generation of
+ * the DMA request from CMP if the DMA feature is enabled. Both events are ignored for generating the DMA request from
+ * the CMP
+ * if the DMA is disabled.
+ *
+ * param base CMP peripheral base address.
+ * param enable Enables or disables the feature.
+ */
+void CMP_EnableDMA(CMP_Type *base, bool enable)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (enable)
+ {
+ tmp8 |= CMP_SCR_DMAEN_MASK;
+ }
+ else
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_DMAEN_MASK;
+ }
+ base->SCR = tmp8;
+}
+#endif /* FSL_FEATURE_CMP_HAS_DMA */
+
+/*!
+ * brief Configures the filter.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
+ /* Choose the clock source for sampling. */
+ if (config->enableSample)
+ {
+ base->CR1 |= CMP_CR1_SE_MASK; /* Choose the external SAMPLE clock. */
+ }
+ else
+ {
+ base->CR1 &= (uint8_t)(~CMP_CR1_SE_MASK); /* Choose the internal divided bus clock. */
+ }
+#endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
+ /* Set the filter count. */
+ tmp8 = (uint8_t)(base->CR0 & ~CMP_CR0_FILTER_CNT_MASK);
+ tmp8 |= CMP_CR0_FILTER_CNT(config->filterCount);
+ base->CR0 = tmp8;
+ /* Set the filter period. It is used as the divider to bus clock. */
+ base->FPR = CMP_FPR_FILT_PER(config->filterPeriod);
+}
+
+/*!
+ * brief Configures the internal DAC.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure. "NULL" disables the feature.
+ */
+void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config)
+{
+ uint8_t tmp8 = 0U;
+
+ if (NULL == config)
+ {
+ /* Passing "NULL" as input parameter means no available configuration. So the DAC feature is disabled.*/
+ base->DACCR = 0U;
+ return;
+ }
+ /* CMPx_DACCR. */
+ tmp8 |= CMP_DACCR_DACEN_MASK; /* Enable the internal DAC. */
+ if (kCMP_VrefSourceVin2 == config->referenceVoltageSource)
+ {
+ tmp8 |= CMP_DACCR_VRSEL_MASK;
+ }
+ tmp8 |= CMP_DACCR_VOSEL(config->DACValue);
+
+ base->DACCR = tmp8;
+}
+
+/*!
+ * brief Enables the interrupts.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IER_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+/*!
+ * brief Disables the interrupts.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_IER_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+/*!
+ * brief Gets the status flags.
+ *
+ * param base CMP peripheral base address.
+ *
+ * return Mask value for the asserted flags. See "_cmp_status_flags".
+ */
+uint32_t CMP_GetStatusFlags(CMP_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ if (0U != (CMP_SCR_CFR_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputRisingEventFlag;
+ }
+ if (0U != (CMP_SCR_CFF_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputFallingEventFlag;
+ }
+ if (0U != (CMP_SCR_COUT_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputAssertEventFlag;
+ }
+ return ret32;
+}
+
+/*!
+ * brief Clears the status flags.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for the flags. See "_cmp_status_flags".
+ */
+void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFR_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFF_MASK;
+ }
+ base->SCR = tmp8;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.h b/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.h
new file mode 100644
index 0000000000..4b5b7bfcb7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/cmp/fsl_cmp.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_CMP_H_
+#define _FSL_CMP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup cmp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief CMP driver version 2.0.2. */
+#define FSL_CMP_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+/*@}*/
+
+/*!
+ * @brief Interrupt enable/disable mask.
+ */
+enum _cmp_interrupt_enable
+{
+ kCMP_OutputRisingInterruptEnable = CMP_SCR_IER_MASK, /*!< Comparator interrupt enable rising. */
+ kCMP_OutputFallingInterruptEnable = CMP_SCR_IEF_MASK, /*!< Comparator interrupt enable falling. */
+};
+
+/*!
+ * @brief Status flags' mask.
+ */
+enum _cmp_status_flags
+{
+ kCMP_OutputRisingEventFlag = CMP_SCR_CFR_MASK, /*!< Rising-edge on the comparison output has occurred. */
+ kCMP_OutputFallingEventFlag = CMP_SCR_CFF_MASK, /*!< Falling-edge on the comparison output has occurred. */
+ kCMP_OutputAssertEventFlag = CMP_SCR_COUT_MASK, /*!< Return the current value of the analog comparator output. */
+};
+
+/*!
+ * @brief CMP Hysteresis mode.
+ */
+typedef enum _cmp_hysteresis_mode
+{
+ kCMP_HysteresisLevel0 = 0U, /*!< Hysteresis level 0. */
+ kCMP_HysteresisLevel1 = 1U, /*!< Hysteresis level 1. */
+ kCMP_HysteresisLevel2 = 2U, /*!< Hysteresis level 2. */
+ kCMP_HysteresisLevel3 = 3U, /*!< Hysteresis level 3. */
+} cmp_hysteresis_mode_t;
+
+/*!
+ * @brief CMP Voltage Reference source.
+ */
+typedef enum _cmp_reference_voltage_source
+{
+ kCMP_VrefSourceVin1 = 0U, /*!< Vin1 is selected as a resistor ladder network supply reference Vin. */
+ kCMP_VrefSourceVin2 = 1U, /*!< Vin2 is selected as a resistor ladder network supply reference Vin. */
+} cmp_reference_voltage_source_t;
+
+/*!
+ * @brief Configures the comparator.
+ */
+typedef struct _cmp_config
+{
+ bool enableCmp; /*!< Enable the CMP module. */
+ cmp_hysteresis_mode_t hysteresisMode; /*!< CMP Hysteresis mode. */
+ bool enableHighSpeed; /*!< Enable High-speed (HS) comparison mode. */
+ bool enableInvertOutput; /*!< Enable the inverted comparator output. */
+ bool useUnfilteredOutput; /*!< Set the compare output(COUT) to equal COUTA(true) or COUT(false). */
+ bool enablePinOut; /*!< The comparator output is available on the associated pin. */
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ bool enableTriggerMode; /*!< Enable the trigger mode. */
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+} cmp_config_t;
+
+/*!
+ * @brief Configures the filter.
+ */
+typedef struct _cmp_filter_config
+{
+#if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
+ bool enableSample; /*!< Using the external SAMPLE as a sampling clock input or using a divided bus clock. */
+#endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
+ uint8_t filterCount; /*!< Filter Sample Count. Available range is 1-7; 0 disables the filter.*/
+ uint8_t filterPeriod; /*!< Filter Sample Period. The divider to the bus clock. Available range is 0-255. */
+} cmp_filter_config_t;
+
+/*!
+ * @brief Configures the internal DAC.
+ */
+typedef struct _cmp_dac_config
+{
+ cmp_reference_voltage_source_t referenceVoltageSource; /*!< Supply voltage reference source. */
+ uint8_t DACValue; /*!< Value for the DAC Output Voltage. Available range is 0-63.*/
+} cmp_dac_config_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+/*!
+ * @name Initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the CMP.
+ *
+ * This function initializes the CMP module. The operations included are as follows.
+ * - Enabling the clock for CMP module.
+ * - Configuring the comparator.
+ * - Enabling the CMP module.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, to enable the clock for
+ * any instance enables all CMPs. See the appropriate MCU reference manual for the clock assignment of the CMP.
+ *
+ * @param base CMP peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void CMP_Init(CMP_Type *base, const cmp_config_t *config);
+
+/*!
+ * @brief De-initializes the CMP module.
+ *
+ * This function de-initializes the CMP module. The operations included are as follows.
+ * - Disabling the CMP module.
+ * - Disabling the clock for CMP module.
+ *
+ * This function disables the clock for the CMP.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, before disabling the
+ * clock for the CMP, ensure that all the CMP instances are not used.
+ *
+ * @param base CMP peripheral base address.
+ */
+void CMP_Deinit(CMP_Type *base);
+
+/*!
+ * @brief Enables/disables the CMP module.
+ *
+ * @param base CMP peripheral base address.
+ * @param enable Enables or disables the module.
+ */
+static inline void CMP_Enable(CMP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR1 |= CMP_CR1_EN_MASK;
+ }
+ else
+ {
+ base->CR1 &= ~(uint8_t)CMP_CR1_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Initializes the CMP user configuration structure.
+ *
+ * This function initializes the user configuration structure to these default values.
+ * @code
+ * config->enableCmp = true;
+ * config->hysteresisMode = kCMP_HysteresisLevel0;
+ * config->enableHighSpeed = false;
+ * config->enableInvertOutput = false;
+ * config->useUnfilteredOutput = false;
+ * config->enablePinOut = false;
+ * config->enableTriggerMode = false;
+ * @endcode
+ * @param config Pointer to the configuration structure.
+ */
+void CMP_GetDefaultConfig(cmp_config_t *config);
+
+/*!
+ * @brief Sets the input channels for the comparator.
+ *
+ * This function sets the input channels for the comparator.
+ * Note that two input channels cannot be set the same way in the application. When the user selects the same input
+ * from the analog mux to the positive and negative port, the comparator is disabled automatically.
+ *
+ * @param base CMP peripheral base address.
+ * @param positiveChannel Positive side input channel number. Available range is 0-7.
+ * @param negativeChannel Negative side input channel number. Available range is 0-7.
+ */
+void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel);
+
+/* @} */
+
+/*!
+ * @name Advanced Features
+ * @{
+ */
+
+#if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
+/*!
+ * @brief Enables/disables the DMA request for rising/falling events.
+ *
+ * This function enables/disables the DMA request for rising/falling events. Either event triggers the generation of
+ * the DMA request from CMP if the DMA feature is enabled. Both events are ignored for generating the DMA request from
+ * the CMP
+ * if the DMA is disabled.
+ *
+ * @param base CMP peripheral base address.
+ * @param enable Enables or disables the feature.
+ */
+void CMP_EnableDMA(CMP_Type *base, bool enable);
+#endif /* FSL_FEATURE_CMP_HAS_DMA */
+
+#if defined(FSL_FEATURE_CMP_HAS_WINDOW_MODE) && FSL_FEATURE_CMP_HAS_WINDOW_MODE
+/*!
+ * @brief Enables/disables the window mode.
+ *
+ * @param base CMP peripheral base address.
+ * @param enable Enables or disables the feature.
+ */
+static inline void CMP_EnableWindowMode(CMP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR1 |= CMP_CR1_WE_MASK;
+ }
+ else
+ {
+ base->CR1 &= (uint8_t)(~CMP_CR1_WE_MASK);
+ }
+}
+#endif /* FSL_FEATURE_CMP_HAS_WINDOW_MODE */
+
+#if defined(FSL_FEATURE_CMP_HAS_PASS_THROUGH_MODE) && FSL_FEATURE_CMP_HAS_PASS_THROUGH_MODE
+/*!
+ * @brief Enables/disables the pass through mode.
+ *
+ * @param base CMP peripheral base address.
+ * @param enable Enables or disables the feature.
+ */
+static inline void CMP_EnablePassThroughMode(CMP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MUXCR |= CMP_MUXCR_PSTM_MASK;
+ }
+ else
+ {
+ base->MUXCR &= (uint8_t)(~CMP_MUXCR_PSTM_MASK);
+ }
+}
+#endif /* FSL_FEATURE_CMP_HAS_PASS_THROUGH_MODE */
+
+/*!
+ * @brief Configures the filter.
+ *
+ * @param base CMP peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config);
+
+/*!
+ * @brief Configures the internal DAC.
+ *
+ * @param base CMP peripheral base address.
+ * @param config Pointer to the configuration structure. "NULL" disables the feature.
+ */
+void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config);
+
+/*!
+ * @brief Enables the interrupts.
+ *
+ * @param base CMP peripheral base address.
+ * @param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the interrupts.
+ *
+ * @param base CMP peripheral base address.
+ * @param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name Results
+ * @{
+ */
+
+/*!
+ * @brief Gets the status flags.
+ *
+ * @param base CMP peripheral base address.
+ *
+ * @return Mask value for the asserted flags. See "_cmp_status_flags".
+ */
+uint32_t CMP_GetStatusFlags(CMP_Type *base);
+
+/*!
+ * @brief Clears the status flags.
+ *
+ * @param base CMP peripheral base address.
+ * @param mask Mask value for the flags. See "_cmp_status_flags".
+ */
+void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask);
+
+/* @} */
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_CMP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.c b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.c
new file mode 100644
index 0000000000..536b64ebb5
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_common.h"
+
+#define SDK_MEM_MAGIC_NUMBER 12345U
+
+typedef struct _mem_align_control_block
+{
+ uint16_t identifier; /*!< Identifier for the memory control block. */
+ uint16_t offset; /*!< offset from aligned address to real address */
+} mem_align_cb_t;
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.common"
+#endif
+
+#if !((defined(__DSC__) && defined(__CW__)))
+void *SDK_Malloc(size_t size, size_t alignbytes)
+{
+ mem_align_cb_t *p_cb = NULL;
+ uint32_t alignedsize;
+
+ /* Check overflow. */
+ alignedsize = (uint32_t)(unsigned int)SDK_SIZEALIGN(size, alignbytes);
+ if (alignedsize < size)
+ {
+ return NULL;
+ }
+
+ if (alignedsize > SIZE_MAX - alignbytes - sizeof(mem_align_cb_t))
+ {
+ return NULL;
+ }
+
+ alignedsize += alignbytes + (uint32_t)sizeof(mem_align_cb_t);
+
+ union
+ {
+ void *pointer_value;
+ uintptr_t unsigned_value;
+ } p_align_addr, p_addr;
+
+ p_addr.pointer_value = malloc((size_t)alignedsize);
+
+ if (p_addr.pointer_value == NULL)
+ {
+ return NULL;
+ }
+
+ p_align_addr.unsigned_value = SDK_SIZEALIGN(p_addr.unsigned_value + sizeof(mem_align_cb_t), alignbytes);
+
+ p_cb = (mem_align_cb_t *)(p_align_addr.unsigned_value - 4U);
+ p_cb->identifier = SDK_MEM_MAGIC_NUMBER;
+ p_cb->offset = (uint16_t)(p_align_addr.unsigned_value - p_addr.unsigned_value);
+
+ return p_align_addr.pointer_value;
+}
+
+void SDK_Free(void *ptr)
+{
+ union
+ {
+ void *pointer_value;
+ uintptr_t unsigned_value;
+ } p_free;
+
+ p_free.pointer_value = ptr;
+ mem_align_cb_t *p_cb = (mem_align_cb_t *)(p_free.unsigned_value - 4U);
+
+ if (p_cb->identifier != SDK_MEM_MAGIC_NUMBER)
+ {
+ return;
+ }
+
+ p_free.unsigned_value = p_free.unsigned_value - p_cb->offset;
+
+ free(p_free.pointer_value);
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.h b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.h
new file mode 100644
index 0000000000..17eaadb84d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common.h
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_COMMON_H_
+#define _FSL_COMMON_H_
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__ICCARM__) || (defined(__CC_ARM) || defined(__ARMCC_VERSION)) || defined(__GNUC__)
+#include <stddef.h>
+#endif
+
+#include "fsl_device_registers.h"
+
+#ifdef __rtems__
+/* Usually provided by modern CMSIS */
+#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
+#endif /* __rtems__ */
+/*!
+ * @addtogroup ksdk_common
+ * @{
+ */
+
+/*******************************************************************************
+ * Configurations
+ ******************************************************************************/
+
+/*! @brief Macro to use the default weak IRQ handler in drivers. */
+#ifndef FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+#define FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ 1
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Construct a status code value from a group and code number. */
+#define MAKE_STATUS(group, code) ((((group)*100L) + (code)))
+
+/*! @brief Construct the version number for drivers.
+ *
+ * The driver version is a 32-bit number, for both 32-bit platforms(such as Cortex M)
+ * and 16-bit platforms(such as DSC).
+ *
+ * @verbatim
+
+ | Unused || Major Version || Minor Version || Bug Fix |
+ 31 25 24 17 16 9 8 0
+
+ @endverbatim
+ */
+#define MAKE_VERSION(major, minor, bugfix) (((major)*65536L) + ((minor)*256L) + (bugfix))
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief common driver version. */
+#define FSL_COMMON_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
+/*@}*/
+
+/* Debug console type definition. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_NONE 0U /*!< No debug console. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_UART 1U /*!< Debug console based on UART. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_LPUART 2U /*!< Debug console based on LPUART. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_LPSCI 3U /*!< Debug console based on LPSCI. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_USBCDC 4U /*!< Debug console based on USBCDC. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_FLEXCOMM 5U /*!< Debug console based on FLEXCOMM. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_IUART 6U /*!< Debug console based on i.MX UART. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_VUSART 7U /*!< Debug console based on LPC_VUSART. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_MINI_USART 8U /*!< Debug console based on LPC_USART. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_SWO 9U /*!< Debug console based on SWO. */
+#define DEBUG_CONSOLE_DEVICE_TYPE_QSCI 10U /*!< Debug console based on QSCI. */
+
+/*! @brief Status group numbers. */
+enum _status_groups
+{
+ kStatusGroup_Generic = 0, /*!< Group number for generic status codes. */
+ kStatusGroup_FLASH = 1, /*!< Group number for FLASH status codes. */
+ kStatusGroup_LPSPI = 4, /*!< Group number for LPSPI status codes. */
+ kStatusGroup_FLEXIO_SPI = 5, /*!< Group number for FLEXIO SPI status codes. */
+ kStatusGroup_DSPI = 6, /*!< Group number for DSPI status codes. */
+ kStatusGroup_FLEXIO_UART = 7, /*!< Group number for FLEXIO UART status codes. */
+ kStatusGroup_FLEXIO_I2C = 8, /*!< Group number for FLEXIO I2C status codes. */
+ kStatusGroup_LPI2C = 9, /*!< Group number for LPI2C status codes. */
+ kStatusGroup_UART = 10, /*!< Group number for UART status codes. */
+ kStatusGroup_I2C = 11, /*!< Group number for UART status codes. */
+ kStatusGroup_LPSCI = 12, /*!< Group number for LPSCI status codes. */
+ kStatusGroup_LPUART = 13, /*!< Group number for LPUART status codes. */
+ kStatusGroup_SPI = 14, /*!< Group number for SPI status code.*/
+ kStatusGroup_XRDC = 15, /*!< Group number for XRDC status code.*/
+ kStatusGroup_SEMA42 = 16, /*!< Group number for SEMA42 status code.*/
+ kStatusGroup_SDHC = 17, /*!< Group number for SDHC status code */
+ kStatusGroup_SDMMC = 18, /*!< Group number for SDMMC status code */
+ kStatusGroup_SAI = 19, /*!< Group number for SAI status code */
+ kStatusGroup_MCG = 20, /*!< Group number for MCG status codes. */
+ kStatusGroup_SCG = 21, /*!< Group number for SCG status codes. */
+ kStatusGroup_SDSPI = 22, /*!< Group number for SDSPI status codes. */
+ kStatusGroup_FLEXIO_I2S = 23, /*!< Group number for FLEXIO I2S status codes */
+ kStatusGroup_FLEXIO_MCULCD = 24, /*!< Group number for FLEXIO LCD status codes */
+ kStatusGroup_FLASHIAP = 25, /*!< Group number for FLASHIAP status codes */
+ kStatusGroup_FLEXCOMM_I2C = 26, /*!< Group number for FLEXCOMM I2C status codes */
+ kStatusGroup_I2S = 27, /*!< Group number for I2S status codes */
+ kStatusGroup_IUART = 28, /*!< Group number for IUART status codes */
+ kStatusGroup_CSI = 29, /*!< Group number for CSI status codes */
+ kStatusGroup_MIPI_DSI = 30, /*!< Group number for MIPI DSI status codes */
+ kStatusGroup_SDRAMC = 35, /*!< Group number for SDRAMC status codes. */
+ kStatusGroup_POWER = 39, /*!< Group number for POWER status codes. */
+ kStatusGroup_ENET = 40, /*!< Group number for ENET status codes. */
+ kStatusGroup_PHY = 41, /*!< Group number for PHY status codes. */
+ kStatusGroup_TRGMUX = 42, /*!< Group number for TRGMUX status codes. */
+ kStatusGroup_SMARTCARD = 43, /*!< Group number for SMARTCARD status codes. */
+ kStatusGroup_LMEM = 44, /*!< Group number for LMEM status codes. */
+ kStatusGroup_QSPI = 45, /*!< Group number for QSPI status codes. */
+ kStatusGroup_DMA = 50, /*!< Group number for DMA status codes. */
+ kStatusGroup_EDMA = 51, /*!< Group number for EDMA status codes. */
+ kStatusGroup_DMAMGR = 52, /*!< Group number for DMAMGR status codes. */
+ kStatusGroup_FLEXCAN = 53, /*!< Group number for FlexCAN status codes. */
+ kStatusGroup_LTC = 54, /*!< Group number for LTC status codes. */
+ kStatusGroup_FLEXIO_CAMERA = 55, /*!< Group number for FLEXIO CAMERA status codes. */
+ kStatusGroup_LPC_SPI = 56, /*!< Group number for LPC_SPI status codes. */
+ kStatusGroup_LPC_USART = 57, /*!< Group number for LPC_USART status codes. */
+ kStatusGroup_DMIC = 58, /*!< Group number for DMIC status codes. */
+ kStatusGroup_SDIF = 59, /*!< Group number for SDIF status codes.*/
+ kStatusGroup_SPIFI = 60, /*!< Group number for SPIFI status codes. */
+ kStatusGroup_OTP = 61, /*!< Group number for OTP status codes. */
+ kStatusGroup_MCAN = 62, /*!< Group number for MCAN status codes. */
+ kStatusGroup_CAAM = 63, /*!< Group number for CAAM status codes. */
+ kStatusGroup_ECSPI = 64, /*!< Group number for ECSPI status codes. */
+ kStatusGroup_USDHC = 65, /*!< Group number for USDHC status codes.*/
+ kStatusGroup_LPC_I2C = 66, /*!< Group number for LPC_I2C status codes.*/
+ kStatusGroup_DCP = 67, /*!< Group number for DCP status codes.*/
+ kStatusGroup_MSCAN = 68, /*!< Group number for MSCAN status codes.*/
+ kStatusGroup_ESAI = 69, /*!< Group number for ESAI status codes. */
+ kStatusGroup_FLEXSPI = 70, /*!< Group number for FLEXSPI status codes. */
+ kStatusGroup_MMDC = 71, /*!< Group number for MMDC status codes. */
+ kStatusGroup_PDM = 72, /*!< Group number for MIC status codes. */
+ kStatusGroup_SDMA = 73, /*!< Group number for SDMA status codes. */
+ kStatusGroup_ICS = 74, /*!< Group number for ICS status codes. */
+ kStatusGroup_SPDIF = 75, /*!< Group number for SPDIF status codes. */
+ kStatusGroup_LPC_MINISPI = 76, /*!< Group number for LPC_MINISPI status codes. */
+ kStatusGroup_HASHCRYPT = 77, /*!< Group number for Hashcrypt status codes */
+ kStatusGroup_LPC_SPI_SSP = 78, /*!< Group number for LPC_SPI_SSP status codes. */
+ kStatusGroup_I3C = 79, /*!< Group number for I3C status codes */
+ kStatusGroup_LPC_I2C_1 = 97, /*!< Group number for LPC_I2C_1 status codes. */
+ kStatusGroup_NOTIFIER = 98, /*!< Group number for NOTIFIER status codes. */
+ kStatusGroup_DebugConsole = 99, /*!< Group number for debug console status codes. */
+ kStatusGroup_SEMC = 100, /*!< Group number for SEMC status codes. */
+ kStatusGroup_ApplicationRangeStart = 101, /*!< Starting number for application groups. */
+ kStatusGroup_IAP = 102, /*!< Group number for IAP status codes */
+ kStatusGroup_SFA = 103, /*!< Group number for SFA status codes*/
+ kStatusGroup_SPC = 104, /*!< Group number for SPC status codes. */
+ kStatusGroup_PUF = 105, /*!< Group number for PUF status codes. */
+ kStatusGroup_TOUCH_PANEL = 106, /*!< Group number for touch panel status codes */
+ kStatusGroup_VBAT = 107, /*!< Group number for VBAT status codes */
+
+ kStatusGroup_HAL_GPIO = 121, /*!< Group number for HAL GPIO status codes. */
+ kStatusGroup_HAL_UART = 122, /*!< Group number for HAL UART status codes. */
+ kStatusGroup_HAL_TIMER = 123, /*!< Group number for HAL TIMER status codes. */
+ kStatusGroup_HAL_SPI = 124, /*!< Group number for HAL SPI status codes. */
+ kStatusGroup_HAL_I2C = 125, /*!< Group number for HAL I2C status codes. */
+ kStatusGroup_HAL_FLASH = 126, /*!< Group number for HAL FLASH status codes. */
+ kStatusGroup_HAL_PWM = 127, /*!< Group number for HAL PWM status codes. */
+ kStatusGroup_HAL_RNG = 128, /*!< Group number for HAL RNG status codes. */
+ kStatusGroup_HAL_I2S = 129, /*!< Group number for HAL I2S status codes. */
+ kStatusGroup_TIMERMANAGER = 135, /*!< Group number for TiMER MANAGER status codes. */
+ kStatusGroup_SERIALMANAGER = 136, /*!< Group number for SERIAL MANAGER status codes. */
+ kStatusGroup_LED = 137, /*!< Group number for LED status codes. */
+ kStatusGroup_BUTTON = 138, /*!< Group number for BUTTON status codes. */
+ kStatusGroup_EXTERN_EEPROM = 139, /*!< Group number for EXTERN EEPROM status codes. */
+ kStatusGroup_SHELL = 140, /*!< Group number for SHELL status codes. */
+ kStatusGroup_MEM_MANAGER = 141, /*!< Group number for MEM MANAGER status codes. */
+ kStatusGroup_LIST = 142, /*!< Group number for List status codes. */
+ kStatusGroup_OSA = 143, /*!< Group number for OSA status codes. */
+ kStatusGroup_COMMON_TASK = 144, /*!< Group number for Common task status codes. */
+ kStatusGroup_MSG = 145, /*!< Group number for messaging status codes. */
+ kStatusGroup_SDK_OCOTP = 146, /*!< Group number for OCOTP status codes. */
+ kStatusGroup_SDK_FLEXSPINOR = 147, /*!< Group number for FLEXSPINOR status codes.*/
+ kStatusGroup_CODEC = 148, /*!< Group number for codec status codes. */
+ kStatusGroup_ASRC = 149, /*!< Group number for codec status ASRC. */
+ kStatusGroup_OTFAD = 150, /*!< Group number for codec status codes. */
+ kStatusGroup_SDIOSLV = 151, /*!< Group number for SDIOSLV status codes. */
+ kStatusGroup_MECC = 152, /*!< Group number for MECC status codes. */
+ kStatusGroup_ENET_QOS = 153, /*!< Group number for ENET_QOS status codes. */
+ kStatusGroup_LOG = 154, /*!< Group number for LOG status codes. */
+ kStatusGroup_I3CBUS = 155, /*!< Group number for I3CBUS status codes. */
+ kStatusGroup_QSCI = 156, /*!< Group number for QSCI status codes. */
+ kStatusGroup_SNT = 157, /*!< Group number for SNT status codes. */
+ kStatusGroup_QUEUEDSPI = 158, /*!< Group number for QSPI status codes. */
+ kStatusGroup_POWER_MANAGER = 159, /*!< Group number for POWER_MANAGER status codes. */
+ kStatusGroup_IPED = 160, /*!< Group number for IPED status codes. */
+ kStatusGroup_CSS_PKC = 161, /*!< Group number for CSS PKC status codes. */
+ kStatusGroup_HOSTIF = 162, /*!< Group number for HOSTIF status codes. */
+ kStatusGroup_CLIF = 163, /*!< Group number for CLIF status codes. */
+ kStatusGroup_BMA = 164, /*!< Group number for BMA status codes. */
+ kStatusGroup_NETC = 165, /*!< Group number for NETC status codes. */
+};
+
+/*! \public
+ * @brief Generic status return codes.
+ */
+enum
+{
+ kStatus_Success = MAKE_STATUS(kStatusGroup_Generic, 0), /*!< Generic status for Success. */
+ kStatus_Fail = MAKE_STATUS(kStatusGroup_Generic, 1), /*!< Generic status for Fail. */
+ kStatus_ReadOnly = MAKE_STATUS(kStatusGroup_Generic, 2), /*!< Generic status for read only failure. */
+ kStatus_OutOfRange = MAKE_STATUS(kStatusGroup_Generic, 3), /*!< Generic status for out of range access. */
+ kStatus_InvalidArgument = MAKE_STATUS(kStatusGroup_Generic, 4), /*!< Generic status for invalid argument check. */
+ kStatus_Timeout = MAKE_STATUS(kStatusGroup_Generic, 5), /*!< Generic status for timeout. */
+ kStatus_NoTransferInProgress =
+ MAKE_STATUS(kStatusGroup_Generic, 6), /*!< Generic status for no transfer in progress. */
+ kStatus_Busy = MAKE_STATUS(kStatusGroup_Generic, 7), /*!< Generic status for module is busy. */
+ kStatus_NoData =
+ MAKE_STATUS(kStatusGroup_Generic, 8), /*!< Generic status for no data is found for the operation. */
+};
+
+/*! @brief Type used for all status and error return values. */
+typedef int32_t status_t;
+
+/*!
+ * @name Min/max macros
+ * @{
+ */
+#if !defined(MIN)
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#if !defined(MAX)
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+/* @} */
+
+/*! @brief Computes the number of elements in an array. */
+#if !defined(ARRAY_SIZE)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/*! @name UINT16_MAX/UINT32_MAX value */
+/* @{ */
+#if !defined(UINT16_MAX)
+#define UINT16_MAX ((uint16_t)-1)
+#endif
+
+#if !defined(UINT32_MAX)
+#define UINT32_MAX ((uint32_t)-1)
+#endif
+/* @} */
+
+/*! @name UINTPTR_SIZE value */
+/* @{ */
+#if !defined(UINTPTR_SIZE)
+#if UINTPTR_MAX > UINT32_MAX
+ #define UINTPTR_SIZE 8 /* 64-bit processor */
+#elif UINTPTR_MAX > UINT16_MAX
+ #define UINTPTR_SIZE 4 /* 32-bit processor */
+#else
+ #error "UINTPTR_SIZE is unknown!"
+#endif
+#endif
+/* @} */
+
+/*! @name Suppress fallthrough warning macro */
+/* For switch case code block, if case section ends without "break;" statement, there wil be
+ fallthrough warning with compiler flag -Wextra or -Wimplicit-fallthrough=n when using armgcc.
+ To suppress this warning, "SUPPRESS_FALL_THROUGH_WARNING();" need to be added at the end of each
+ case section which misses "break;"statement.
+ */
+/* @{ */
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
+#define SUPPRESS_FALL_THROUGH_WARNING() __attribute__((fallthrough))
+#else
+#define SUPPRESS_FALL_THROUGH_WARNING()
+#endif
+/* @} */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if !((defined(__DSC__) && defined(__CW__)))
+/*!
+ * @brief Allocate memory with given alignment and aligned size.
+ *
+ * This is provided to support the dynamically allocated memory
+ * used in cache-able region.
+ * @param size The length required to malloc.
+ * @param alignbytes The alignment size.
+ * @retval The allocated memory.
+ */
+void *SDK_Malloc(size_t size, size_t alignbytes);
+
+/*!
+ * @brief Free memory.
+ *
+ * @param ptr The memory to be release.
+ */
+void SDK_Free(void *ptr);
+#endif
+
+/*!
+ * @brief Delay at least for some time.
+ * Please note that, this API uses while loop for delay, different run-time environments make the time not precise,
+ * if precise delay count was needed, please implement a new delay function with hardware timer.
+ *
+ * @param delayTime_us Delay time in unit of microsecond.
+ * @param coreClock_Hz Core clock frequency with Hz.
+ */
+void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz);
+
+#ifdef __rtems__
+/* Prototypes for IRQHandlers */
+void ADMA_FLEXCAN0_INT_DriverIRQHandler(void);
+void ADMA_FLEXCAN1_INT_DriverIRQHandler(void);
+void ADMA_FLEXCAN2_INT_DriverIRQHandler(void);
+void ADMA_I2C0_INT_DriverIRQHandler(void);
+void ADMA_I2C1_INT_DriverIRQHandler(void);
+void ADMA_I2C2_INT_DriverIRQHandler(void);
+void ADMA_I2C3_INT_DriverIRQHandler(void);
+void ADMA_I2C4_INT_DriverIRQHandler(void);
+void ADMA_SAI0_INT_DriverIRQHandler(void);
+void ADMA_SAI1_INT_DriverIRQHandler(void);
+void ADMA_SAI2_INT_DriverIRQHandler(void);
+void ADMA_SAI3_INT_DriverIRQHandler(void);
+void ADMA_SAI4_INT_DriverIRQHandler(void);
+void ADMA_SAI5_INT_DriverIRQHandler(void);
+void ADMA_SPI0_INT_DriverIRQHandler(void);
+void ADMA_SPI1_INT_DriverIRQHandler(void);
+void ADMA_SPI2_INT_DriverIRQHandler(void);
+void ADMA_SPI3_INT_DriverIRQHandler(void);
+void ADMA_UART0_INT_DriverIRQHandler(void);
+void ADMA_UART1_INT_DriverIRQHandler(void);
+void ADMA_UART2_INT_DriverIRQHandler(void);
+void ADMA_UART3_INT_DriverIRQHandler(void);
+void ASRC_DriverIRQHandler(void);
+void AUDIO_SAI0_INT_DriverIRQHandler(void);
+void AUDIO_SAI1_INT_DriverIRQHandler(void);
+void AUDIO_SAI2_INT_DriverIRQHandler(void);
+void AUDIO_SAI3_INT_DriverIRQHandler(void);
+void AUDIO_SAI6_INT_DriverIRQHandler(void);
+void AUDIO_SAI7_INT_DriverIRQHandler(void);
+void CAN0_DriverIRQHandler(void);
+void CAN1_DriverIRQHandler(void);
+void CAN2_DriverIRQHandler(void);
+void CAN3_DriverIRQHandler(void);
+void CAN4_DriverIRQHandler(void);
+void CDOG_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_TIMER_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_TIMER_INT_DriverIRQHandler(void);
+void CONNECTIVITY_EQOS_INT_DriverIRQHandler(void);
+void CSI0_DriverIRQHandler(void);
+void CSI_DriverIRQHandler(void);
+void DMA0_04_DriverIRQHandler(void);
+void DMA0_08_DriverIRQHandler(void);
+void DMA0_0_4_DriverIRQHandler(void);
+void DMA0_10_14_DriverIRQHandler(void);
+void DMA0_11_15_DriverIRQHandler(void);
+void DMA0_15_DriverIRQHandler(void);
+void DMA0_16_20_DriverIRQHandler(void);
+void DMA0_17_21_DriverIRQHandler(void);
+void DMA0_18_22_DriverIRQHandler(void);
+void DMA0_19_23_DriverIRQHandler(void);
+void DMA0_19_DriverIRQHandler(void);
+void DMA0_1_5_DriverIRQHandler(void);
+void DMA0_210_DriverIRQHandler(void);
+void DMA0_24_28_DriverIRQHandler(void);
+void DMA0_25_29_DriverIRQHandler(void);
+void DMA0_26_30_DriverIRQHandler(void);
+void DMA0_26_DriverIRQHandler(void);
+void DMA0_27_31_DriverIRQHandler(void);
+void DMA0_2_6_DriverIRQHandler(void);
+void DMA0_311_DriverIRQHandler(void);
+void DMA0_37_DriverIRQHandler(void);
+void DMA0_3_7_DriverIRQHandler(void);
+void DMA0_412_DriverIRQHandler(void);
+void DMA0_513_DriverIRQHandler(void);
+void DMA0_614_DriverIRQHandler(void);
+void DMA0_715_DriverIRQHandler(void);
+void DMA0_8_12_DriverIRQHandler(void);
+void DMA0_9_13_DriverIRQHandler(void);
+void DMA0_DMA16_DriverIRQHandler(void);
+void DMA0_DMA16_DriverIRQHandler(void);
+void DMA0_DriverIRQHandler(void);
+void DMA10_DMA26_DriverIRQHandler(void);
+void DMA10_DMA26_DriverIRQHandler(void);
+void DMA10_DriverIRQHandler(void);
+void DMA11_DMA27_DriverIRQHandler(void);
+void DMA11_DMA27_DriverIRQHandler(void);
+void DMA11_DriverIRQHandler(void);
+void DMA12_DMA28_DriverIRQHandler(void);
+void DMA12_DMA28_DriverIRQHandler(void);
+void DMA12_DriverIRQHandler(void);
+void DMA13_DMA29_DriverIRQHandler(void);
+void DMA13_DMA29_DriverIRQHandler(void);
+void DMA13_DriverIRQHandler(void);
+void DMA14_DMA30_DriverIRQHandler(void);
+void DMA14_DMA30_DriverIRQHandler(void);
+void DMA14_DriverIRQHandler(void);
+void DMA15_DMA31_DriverIRQHandler(void);
+void DMA15_DMA31_DriverIRQHandler(void);
+void DMA15_DriverIRQHandler(void);
+void DMA16_DriverIRQHandler(void);
+void DMA17_DriverIRQHandler(void);
+void DMA18_DriverIRQHandler(void);
+void DMA19_DriverIRQHandler(void);
+void DMA1_04_DriverIRQHandler(void);
+void DMA1_04_DriverIRQHandler(void);
+void DMA1_08_DriverIRQHandler(void);
+void DMA1_15_DriverIRQHandler(void);
+void DMA1_15_DriverIRQHandler(void);
+void DMA1_19_DriverIRQHandler(void);
+void DMA1_210_DriverIRQHandler(void);
+void DMA1_26_DriverIRQHandler(void);
+void DMA1_26_DriverIRQHandler(void);
+void DMA1_311_DriverIRQHandler(void);
+void DMA1_37_DriverIRQHandler(void);
+void DMA1_37_DriverIRQHandler(void);
+void DMA1_412_DriverIRQHandler(void);
+void DMA1_513_DriverIRQHandler(void);
+void DMA1_614_DriverIRQHandler(void);
+void DMA1_715_DriverIRQHandler(void);
+void DMA1_DMA17_DriverIRQHandler(void);
+void DMA1_DMA17_DriverIRQHandler(void);
+void DMA1_DriverIRQHandler(void);
+void DMA20_DriverIRQHandler(void);
+void DMA21_DriverIRQHandler(void);
+void DMA22_DriverIRQHandler(void);
+void DMA23_DriverIRQHandler(void);
+void DMA24_DriverIRQHandler(void);
+void DMA25_DriverIRQHandler(void);
+void DMA26_DriverIRQHandler(void);
+void DMA27_DriverIRQHandler(void);
+void DMA28_DriverIRQHandler(void);
+void DMA29_DriverIRQHandler(void);
+void DMA2_DMA18_DriverIRQHandler(void);
+void DMA2_DMA18_DriverIRQHandler(void);
+void DMA2_DriverIRQHandler(void);
+void DMA30_DriverIRQHandler(void);
+void DMA31_DriverIRQHandler(void);
+void DMA3_DMA19_DriverIRQHandler(void);
+void DMA3_DMA19_DriverIRQHandler(void);
+void DMA3_DriverIRQHandler(void);
+void DMA4_DMA20_DriverIRQHandler(void);
+void DMA4_DMA20_DriverIRQHandler(void);
+void DMA4_DriverIRQHandler(void);
+void DMA5_DMA21_DriverIRQHandler(void);
+void DMA5_DMA21_DriverIRQHandler(void);
+void DMA5_DriverIRQHandler(void);
+void DMA6_DMA22_DriverIRQHandler(void);
+void DMA6_DMA22_DriverIRQHandler(void);
+void DMA6_DriverIRQHandler(void);
+void DMA7_DMA23_DriverIRQHandler(void);
+void DMA7_DMA23_DriverIRQHandler(void);
+void DMA7_DriverIRQHandler(void);
+void DMA8_DMA24_DriverIRQHandler(void);
+void DMA8_DMA24_DriverIRQHandler(void);
+void DMA8_DriverIRQHandler(void);
+void DMA9_DMA25_DriverIRQHandler(void);
+void DMA9_DMA25_DriverIRQHandler(void);
+void DMA9_DriverIRQHandler(void);
+void DMA_FLEXCAN0_INT_DriverIRQHandler(void);
+void DMA_FLEXCAN1_INT_DriverIRQHandler(void);
+void DMA_FLEXCAN2_INT_DriverIRQHandler(void);
+void DMA_I2C0_INT_DriverIRQHandler(void);
+void DMA_I2C1_INT_DriverIRQHandler(void);
+void DMA_I2C2_INT_DriverIRQHandler(void);
+void DMA_I2C3_INT_DriverIRQHandler(void);
+void DMA_I2C4_INT_DriverIRQHandler(void);
+void DMA_SPI0_INT_DriverIRQHandler(void);
+void DMA_SPI1_INT_DriverIRQHandler(void);
+void DMA_SPI2_INT_DriverIRQHandler(void);
+void DMA_SPI3_INT_DriverIRQHandler(void);
+void DMA_UART0_INT_DriverIRQHandler(void);
+void DMA_UART1_INT_DriverIRQHandler(void);
+void DMA_UART2_INT_DriverIRQHandler(void);
+void DMA_UART3_INT_DriverIRQHandler(void);
+void DMA_UART4_INT_DriverIRQHandler(void);
+void ENET1_1588_Timer_DriverIRQHandler(void);
+void ENET1_DriverIRQHandler(void);
+void ENET1_MAC0_Rx_Tx_Done1_DriverIRQHandler(void);
+void ENET1_MAC0_Rx_Tx_Done2_DriverIRQHandler(void);
+void ENET2_1588_Timer_DriverIRQHandler(void);
+void ENET2_DriverIRQHandler(void);
+void ENET_1588_Timer_DriverIRQHandler(void);
+void ENET_1G_1588_Timer_DriverIRQHandler(void);
+void ENET_1G_DriverIRQHandler(void);
+void ENET_1G_MAC0_Tx_Rx_1_DriverIRQHandler(void);
+void ENET_1G_MAC0_Tx_Rx_2_DriverIRQHandler(void);
+void ENET_DriverIRQHandler(void);
+void ENET_Error_DriverIRQHandler(void);
+void ENET_MAC0_Rx_Tx_Done1_DriverIRQHandler(void);
+void ENET_MAC0_Rx_Tx_Done2_DriverIRQHandler(void);
+void ENET_QOS_DriverIRQHandler(void);
+void ENET_Receive_DriverIRQHandler(void);
+void ENET_Transmit_DriverIRQHandler(void);
+void FLEXIO0_DriverIRQHandler(void);
+void FLEXIO1_DriverIRQHandler(void);
+void FLEXIO2_DriverIRQHandler(void);
+void FLEXIO3_DriverIRQHandler(void);
+void FLEXIO_DriverIRQHandler(void);
+void FLEXSPI0_DriverIRQHandler(void);
+void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void);
+void FLEXSPI1_DriverIRQHandler(void);
+void FLEXSPI_DriverIRQHandler(void);
+void I2S0_DriverIRQHandler(void);
+void I2S0_Rx_DriverIRQHandler(void);
+void I2S0_Tx_DriverIRQHandler(void);
+void I2S1_DriverIRQHandler(void);
+void I2S1_Rx_DriverIRQHandler(void);
+void I2S1_Tx_DriverIRQHandler(void);
+void I2S2_DriverIRQHandler(void);
+void I2S2_Rx_DriverIRQHandler(void);
+void I2S2_Tx_DriverIRQHandler(void);
+void I2S3_DriverIRQHandler(void);
+void I2S3_Rx_DriverIRQHandler(void);
+void I2S3_Tx_DriverIRQHandler(void);
+void I2S4_DriverIRQHandler(void);
+void I2S4_Rx_DriverIRQHandler(void);
+void I2S4_Tx_DriverIRQHandler(void);
+void I2S56_DriverIRQHandler(void);
+void I2S56_Rx_DriverIRQHandler(void);
+void I2S56_Tx_DriverIRQHandler(void);
+void I2S5_DriverIRQHandler(void);
+void I2S5_Rx_DriverIRQHandler(void);
+void I2S5_Tx_DriverIRQHandler(void);
+void I2S6_DriverIRQHandler(void);
+void I2S6_Rx_DriverIRQHandler(void);
+void I2S6_Tx_DriverIRQHandler(void);
+void LPI2C0_DriverIRQHandler(void);
+void LPI2C1_DriverIRQHandler(void);
+void LPI2C2_DriverIRQHandler(void);
+void LPI2C3_DriverIRQHandler(void);
+void LPI2C4_DriverIRQHandler(void);
+void LPI2C5_DriverIRQHandler(void);
+void LPI2C6_DriverIRQHandler(void);
+void LPSPI0_DriverIRQHandler(void);
+void LPSPI1_DriverIRQHandler(void);
+void LPSPI2_DriverIRQHandler(void);
+void LPSPI3_DriverIRQHandler(void);
+void LPSPI4_DriverIRQHandler(void);
+void LPSPI5_DriverIRQHandler(void);
+void LPUART0_DriverIRQHandler(void);
+void LPUART0_LPUART1_DriverIRQHandler(void);
+void LPUART0_LPUART1_RX_DriverIRQHandler(void);
+void LPUART0_LPUART1_TX_DriverIRQHandler(void);
+void LPUART0_RX_DriverIRQHandler(void);
+void LPUART0_TX_DriverIRQHandler(void);
+void LPUART10_DriverIRQHandler(void);
+void LPUART10_RX_DriverIRQHandler(void);
+void LPUART10_TX_DriverIRQHandler(void);
+void LPUART11_DriverIRQHandler(void);
+void LPUART11_RX_DriverIRQHandler(void);
+void LPUART11_TX_DriverIRQHandler(void);
+void LPUART12_DriverIRQHandler(void);
+void LPUART12_RX_DriverIRQHandler(void);
+void LPUART12_TX_DriverIRQHandler(void);
+void LPUART1_DriverIRQHandler(void);
+void LPUART1_RX_DriverIRQHandler(void);
+void LPUART1_TX_DriverIRQHandler(void);
+void LPUART2_DriverIRQHandler(void);
+void LPUART2_RX_DriverIRQHandler(void);
+void LPUART2_TX_DriverIRQHandler(void);
+void LPUART3_DriverIRQHandler(void);
+void LPUART3_RX_DriverIRQHandler(void);
+void LPUART3_TX_DriverIRQHandler(void);
+void LPUART4_DriverIRQHandler(void);
+void LPUART4_RX_DriverIRQHandler(void);
+void LPUART4_TX_DriverIRQHandler(void);
+void LPUART5_DriverIRQHandler(void);
+void LPUART5_RX_DriverIRQHandler(void);
+void LPUART5_TX_DriverIRQHandler(void);
+void LPUART6_DriverIRQHandler(void);
+void LPUART6_RX_DriverIRQHandler(void);
+void LPUART6_TX_DriverIRQHandler(void);
+void LPUART7_DriverIRQHandler(void);
+void LPUART7_RX_DriverIRQHandler(void);
+void LPUART7_TX_DriverIRQHandler(void);
+void LPUART8_DriverIRQHandler(void);
+void LPUART8_RX_DriverIRQHandler(void);
+void LPUART8_TX_DriverIRQHandler(void);
+void LPUART9_DriverIRQHandler(void);
+void LPUART9_RX_DriverIRQHandler(void);
+void LPUART9_TX_DriverIRQHandler(void);
+void LSIO_OCTASPI0_INT_DriverIRQHandler(void);
+void LSIO_OCTASPI1_INT_DriverIRQHandler(void);
+void M4_0_LPI2C_DriverIRQHandler(void);
+void M4_0_LPUART_DriverIRQHandler(void);
+void M4_1_LPI2C_DriverIRQHandler(void);
+void M4_1_LPUART_DriverIRQHandler(void);
+void M4_LPI2C_DriverIRQHandler(void);
+void M4_LPUART_DriverIRQHandler(void);
+void MIPI_DSI_DriverIRQHandler(void);
+void PDM_EVENT_DriverIRQHandler(void);
+void PDM_HWVAD_ERROR_DriverIRQHandler(void);
+void PDM_HWVAD_EVENT_DriverIRQHandler(void);
+void SAI0_DriverIRQHandler(void);
+void SAI1_DriverIRQHandler(void);
+void SAI2_DriverIRQHandler(void);
+void SAI3_DriverIRQHandler(void);
+void SAI3_RX_DriverIRQHandler(void);
+void SAI3_TX_DriverIRQHandler(void);
+void SAI4_DriverIRQHandler(void);
+void SAI5_DriverIRQHandler(void);
+void SAI6_DriverIRQHandler(void);
+void SPDIF_DriverIRQHandler(void);
+void UART2_FLEXIO_DriverIRQHandler(void);
+void USDHC0_DriverIRQHandler(void);
+void USDHC1_DriverIRQHandler(void);
+void USDHC2_DriverIRQHandler(void);
+#endif /* __rtems__ */
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @} */
+
+#if (defined(__DSC__) && defined(__CW__))
+#include "fsl_common_dsc.h"
+#elif defined(__XCC__)
+#include "fsl_common_dsp.h"
+#else
+#include "fsl_common_arm.h"
+#endif
+
+#endif /* _FSL_COMMON_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.c b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.c
new file mode 100644
index 0000000000..241005e922
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_common.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.common_arm"
+#endif
+
+#ifndef __GIC_PRIO_BITS
+#if defined(ENABLE_RAM_VECTOR_TABLE)
+uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
+{
+#ifdef __VECTOR_TABLE
+#undef __VECTOR_TABLE
+#endif
+
+/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+ extern uint32_t Image$$VECTOR_ROM$$Base[];
+ extern uint32_t Image$$VECTOR_RAM$$Base[];
+ extern uint32_t Image$$RW_m_data$$Base[];
+
+#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
+#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
+#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
+#elif defined(__ICCARM__)
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+#elif defined(__GNUC__)
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
+ uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
+#endif /* defined(__CC_ARM) || defined(__ARMCC_VERSION) */
+ uint32_t n;
+ uint32_t ret;
+ uint32_t irqMaskValue;
+
+ irqMaskValue = DisableGlobalIRQ();
+ if (SCB->VTOR != (uint32_t)__VECTOR_RAM)
+ {
+ /* Copy the vector table from ROM to RAM */
+ for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++)
+ {
+ __VECTOR_RAM[n] = __VECTOR_TABLE[n];
+ }
+ /* Point the VTOR to the position of vector table */
+ SCB->VTOR = (uint32_t)__VECTOR_RAM;
+ }
+
+ ret = __VECTOR_RAM[(int32_t)irq + 16];
+ /* make sure the __VECTOR_RAM is noncachable */
+ __VECTOR_RAM[(int32_t)irq + 16] = irqHandler;
+
+ EnableGlobalIRQ(irqMaskValue);
+
+ return ret;
+}
+#endif /* ENABLE_RAM_VECTOR_TABLE. */
+#endif /* __GIC_PRIO_BITS. */
+
+#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
+
+/*
+ * When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
+ * powerlib should be used instead of these functions.
+ */
+#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
+
+/*
+ * When the SYSCON STARTER registers are discontinuous, these functions are
+ * implemented in fsl_power.c.
+ */
+#if !(defined(FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) && FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS)
+
+void EnableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t intNumber = (uint32_t)interrupt;
+
+ uint32_t index = 0;
+
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ SYSCON->STARTERSET[index] = 1UL << intNumber;
+ (void)EnableIRQ(interrupt); /* also enable interrupt at NVIC */
+}
+
+void DisableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t intNumber = (uint32_t)interrupt;
+
+ (void)DisableIRQ(interrupt); /* also disable interrupt at NVIC */
+ uint32_t index = 0;
+
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ SYSCON->STARTERCLR[index] = 1UL << intNumber;
+}
+#endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */
+#endif /* FSL_FEATURE_POWERLIB_EXTEND */
+#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
+
+#if defined(DWT)
+/* Use WDT. */
+void MSDK_EnableCpuCycleCounter(void)
+{
+ /* Make sure the DWT trace fucntion is enabled. */
+ if (CoreDebug_DEMCR_TRCENA_Msk != (CoreDebug_DEMCR_TRCENA_Msk & CoreDebug->DEMCR))
+ {
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ }
+
+ /* CYCCNT not supported on this device. */
+ assert(DWT_CTRL_NOCYCCNT_Msk != (DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk));
+
+ /* Read CYCCNT directly if CYCCENT has already been enabled, otherwise enable CYCCENT first. */
+ if (DWT_CTRL_CYCCNTENA_Msk != (DWT_CTRL_CYCCNTENA_Msk & DWT->CTRL))
+ {
+ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+ }
+}
+
+uint32_t MSDK_GetCpuCycleCount(void)
+{
+ return DWT->CYCCNT;
+}
+#endif /* defined(DWT) */
+
+#if !(defined(SDK_DELAY_USE_DWT) && defined(DWT))
+/* Use software loop. */
+#if defined(__CC_ARM) /* This macro is arm v5 specific */
+/* clang-format off */
+__ASM static void DelayLoop(uint32_t count)
+{
+loop
+ SUBS R0, R0, #1
+ CMP R0, #0
+ BNE loop
+ BX LR
+}
+#elif defined(__ARM_ARCH_8A__) /* This macro is ARMv8-A specific */
+static void DelayLoop(uint32_t count)
+{
+ __ASM volatile(" MOV X0, %0" : : "r"(count));
+ __ASM volatile(
+ "loop: \n"
+ " SUB X0, X0, #1 \n"
+ " CMP X0, #0 \n"
+
+ " BNE loop \n"
+ :
+ :
+ : "r0");
+}
+/* clang-format on */
+#elif defined(__ARMCC_VERSION) || defined(__ICCARM__) || defined(__GNUC__)
+/* Cortex-M0 has a smaller instruction set, SUBS isn't supported in thumb-16 mode reported from __GNUC__ compiler,
+ * use SUB and CMP here for compatibility */
+static void DelayLoop(uint32_t count)
+{
+ __ASM volatile(" MOV R0, %0" : : "r"(count));
+ __ASM volatile(
+ "loop: \n"
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
+ " SUB R0, R0, #1 \n"
+#else
+ " SUBS R0, R0, #1 \n"
+#endif
+ " CMP R0, #0 \n"
+
+ " BNE loop \n"
+ :
+ :
+ : "r0");
+}
+#endif /* defined(__CC_ARM) */
+#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */
+
+/*!
+ * @brief Delay at least for some time.
+ * Please note that, if not uses DWT, this API will use while loop for delay, different run-time environments have
+ * effect on the delay time. If precise delay is needed, please enable DWT delay. The two parmeters delayTime_us and
+ * coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delayTime_us only supports
+ * up to 4294967 in current code. If long time delay is needed, please implement a new delay function.
+ *
+ * @param delayTime_us Delay time in unit of microsecond.
+ * @param coreClock_Hz Core clock frequency with Hz.
+ */
+void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz)
+{
+ uint64_t count;
+
+ if (delayTime_us > 0U)
+ {
+ count = USEC_TO_COUNT(delayTime_us, coreClock_Hz);
+
+ assert(count <= UINT32_MAX);
+
+#if defined(SDK_DELAY_USE_DWT) && defined(DWT) /* Use DWT for better accuracy */
+
+ MSDK_EnableCpuCycleCounter();
+ /* Calculate the count ticks. */
+ count += MSDK_GetCpuCycleCount();
+
+ if (count > UINT32_MAX)
+ {
+ count -= UINT32_MAX;
+ /* Wait for cyccnt overflow. */
+ while (count < MSDK_GetCpuCycleCount())
+ {
+ }
+ }
+
+ /* Wait for cyccnt reach count value. */
+ while (count > MSDK_GetCpuCycleCount())
+ {
+ }
+#else
+ /* Divide value may be different in various environment to ensure delay is precise.
+ * Every loop count includes three instructions, due to Cortex-M7 sometimes executes
+ * two instructions in one period, through test here set divide 1.5. Other M cores use
+ * divide 4. By the way, divide 1.5 or 4 could let the count lose precision, but it does
+ * not matter because other instructions outside while loop is enough to fill the time.
+ */
+#if (__CORTEX_M == 7)
+ count = count / 3U * 2U;
+#else
+ count = count / 4U;
+#endif
+ DelayLoop((uint32_t)count);
+#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.h b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.h
new file mode 100644
index 0000000000..49d50de92a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_arm.h
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_COMMON_ARM_H_
+#define _FSL_COMMON_ARM_H_
+
+/*
+ * For CMSIS pack RTE.
+ * CMSIS pack RTE generates "RTC_Components.h" which contains the statements
+ * of the related <RTE_Components_h> element for all selected software components.
+ */
+#ifdef _RTE_
+#include "RTE_Components.h"
+#endif
+
+/*!
+ * @addtogroup ksdk_common
+ * @{
+ */
+
+/*! @name Atomic modification
+ *
+ * These macros are used for atomic access, such as read-modify-write
+ * to the peripheral registers.
+ *
+ * - SDK_ATOMIC_LOCAL_ADD
+ * - SDK_ATOMIC_LOCAL_SET
+ * - SDK_ATOMIC_LOCAL_CLEAR
+ * - SDK_ATOMIC_LOCAL_TOGGLE
+ * - SDK_ATOMIC_LOCAL_CLEAR_AND_SET
+ *
+ * Take SDK_ATOMIC_LOCAL_CLEAR_AND_SET as an example: the parameter @c addr
+ * means the address of the peripheral register or variable you want to modify
+ * atomically, the parameter @c clearBits is the bits to clear, the parameter
+ * @c setBits it the bits to set.
+ * For example, to set a 32-bit register bit1:bit0 to 0b10, use like this:
+ *
+ * @code
+ volatile uint32_t * reg = (volatile uint32_t *)REG_ADDR;
+
+ SDK_ATOMIC_LOCAL_CLEAR_AND_SET(reg, 0x03, 0x02);
+ @endcode
+ *
+ * In this example, the register bit1:bit0 are cleared and bit1 is set, as a result,
+ * register bit1:bit0 = 0b10.
+ *
+ * @note For the platforms don't support exclusive load and store, these macros
+ * disable the global interrupt to pretect the modification.
+ *
+ * @note These macros only guarantee the local processor atomic operations. For
+ * the multi-processor devices, use hardware semaphore such as SEMA42 to
+ * guarantee exclusive access if necessary.
+ *
+ * @{
+ */
+
+/* clang-format off */
+#if ((defined(__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \
+ (defined(__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \
+ (defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ == 1)) || \
+ (defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ == 1)))
+/* clang-format on */
+
+/* If the LDREX and STREX are supported, use them. */
+#define _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, val, ops) \
+ do \
+ { \
+ (val) = __LDREXB(addr); \
+ (ops); \
+ } while (0UL != __STREXB((val), (addr)))
+
+#define _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, val, ops) \
+ do \
+ { \
+ (val) = __LDREXH(addr); \
+ (ops); \
+ } while (0UL != __STREXH((val), (addr)))
+
+#define _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, val, ops) \
+ do \
+ { \
+ (val) = __LDREXW(addr); \
+ (ops); \
+ } while (0UL != __STREXW((val), (addr)))
+
+static inline void _SDK_AtomicLocalAdd1Byte(volatile uint8_t *addr, uint8_t val)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val += val);
+}
+
+static inline void _SDK_AtomicLocalAdd2Byte(volatile uint16_t *addr, uint16_t val)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val += val);
+}
+
+static inline void _SDK_AtomicLocalAdd4Byte(volatile uint32_t *addr, uint32_t val)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val += val);
+}
+
+static inline void _SDK_AtomicLocalSub1Byte(volatile uint8_t *addr, uint8_t val)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val -= val);
+}
+
+static inline void _SDK_AtomicLocalSub2Byte(volatile uint16_t *addr, uint16_t val)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val -= val);
+}
+
+static inline void _SDK_AtomicLocalSub4Byte(volatile uint32_t *addr, uint32_t val)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val -= val);
+}
+
+static inline void _SDK_AtomicLocalSet1Byte(volatile uint8_t *addr, uint8_t bits)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val |= bits);
+}
+
+static inline void _SDK_AtomicLocalSet2Byte(volatile uint16_t *addr, uint16_t bits)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val |= bits);
+}
+
+static inline void _SDK_AtomicLocalSet4Byte(volatile uint32_t *addr, uint32_t bits)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val |= bits);
+}
+
+static inline void _SDK_AtomicLocalClear1Byte(volatile uint8_t *addr, uint8_t bits)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val &= ~bits);
+}
+
+static inline void _SDK_AtomicLocalClear2Byte(volatile uint16_t *addr, uint16_t bits)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val &= ~bits);
+}
+
+static inline void _SDK_AtomicLocalClear4Byte(volatile uint32_t *addr, uint32_t bits)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val &= ~bits);
+}
+
+static inline void _SDK_AtomicLocalToggle1Byte(volatile uint8_t *addr, uint8_t bits)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val ^= bits);
+}
+
+static inline void _SDK_AtomicLocalToggle2Byte(volatile uint16_t *addr, uint16_t bits)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val ^= bits);
+}
+
+static inline void _SDK_AtomicLocalToggle4Byte(volatile uint32_t *addr, uint32_t bits)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val ^= bits);
+}
+
+static inline void _SDK_AtomicLocalClearAndSet1Byte(volatile uint8_t *addr, uint8_t clearBits, uint8_t setBits)
+{
+ uint8_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
+}
+
+static inline void _SDK_AtomicLocalClearAndSet2Byte(volatile uint16_t *addr, uint16_t clearBits, uint16_t setBits)
+{
+ uint16_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
+}
+
+static inline void _SDK_AtomicLocalClearAndSet4Byte(volatile uint32_t *addr, uint32_t clearBits, uint32_t setBits)
+{
+ uint32_t s_val;
+
+ _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
+}
+
+#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
+ ((1UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalAdd1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(val)) : \
+ ((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalAdd2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(val)) : \
+ _SDK_AtomicLocalAdd4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(val))))
+
+#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
+ ((1UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalSet1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
+ ((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalSet2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
+ _SDK_AtomicLocalSet4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
+
+#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
+ ((1UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalClear1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
+ ((2UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalClear2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
+ _SDK_AtomicLocalClear4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
+
+#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
+ ((1UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalToggle1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
+ ((2UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalToggle2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
+ _SDK_AtomicLocalToggle4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
+
+#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
+ ((1UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalClearAndSet1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(clearBits), (uint8_t)(setBits)) : \
+ ((2UL == sizeof(*(addr))) ? \
+ _SDK_AtomicLocalClearAndSet2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(clearBits), (uint16_t)(setBits)) : \
+ _SDK_AtomicLocalClearAndSet4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(clearBits), (uint32_t)(setBits))))
+#else
+
+#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
+ do \
+ { \
+ uint32_t s_atomicOldInt; \
+ s_atomicOldInt = DisableGlobalIRQ(); \
+ *(addr) += (val); \
+ EnableGlobalIRQ(s_atomicOldInt); \
+ } while (0)
+
+#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
+ do \
+ { \
+ uint32_t s_atomicOldInt; \
+ s_atomicOldInt = DisableGlobalIRQ(); \
+ *(addr) |= (bits); \
+ EnableGlobalIRQ(s_atomicOldInt); \
+ } while (0)
+
+#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
+ do \
+ { \
+ uint32_t s_atomicOldInt; \
+ s_atomicOldInt = DisableGlobalIRQ(); \
+ *(addr) &= ~(bits); \
+ EnableGlobalIRQ(s_atomicOldInt); \
+ } while (0)
+
+#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
+ do \
+ { \
+ uint32_t s_atomicOldInt; \
+ s_atomicOldInt = DisableGlobalIRQ(); \
+ *(addr) ^= (bits); \
+ EnableGlobalIRQ(s_atomicOldInt); \
+ } while (0)
+
+#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
+ do \
+ { \
+ uint32_t s_atomicOldInt; \
+ s_atomicOldInt = DisableGlobalIRQ(); \
+ *(addr) = (*(addr) & ~(clearBits)) | (setBits); \
+ EnableGlobalIRQ(s_atomicOldInt); \
+ } while (0)
+
+#endif
+/* @} */
+
+/*! @name Timer utilities */
+/* @{ */
+/*! Macro to convert a microsecond period to raw count value */
+#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)(((uint64_t)(us) * (clockFreqInHz)) / 1000000U)
+/*! Macro to convert a raw count value to microsecond */
+#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count)*1000000U / (clockFreqInHz))
+
+/*! Macro to convert a millisecond period to raw count value */
+#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)(ms) * (clockFreqInHz) / 1000U)
+/*! Macro to convert a raw count value to millisecond */
+#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count)*1000U / (clockFreqInHz))
+/* @} */
+
+/*! @name ISR exit barrier
+ * @{
+ *
+ * ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
+ * exception return operation might vector to incorrect interrupt.
+ * For Cortex-M7, if core speed much faster than peripheral register write speed,
+ * the peripheral interrupt flags may be still set after exiting ISR, this results to
+ * the same error similar with errata 83869.
+ */
+#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U))
+#define SDK_ISR_EXIT_BARRIER __DSB()
+#else
+#define SDK_ISR_EXIT_BARRIER
+#endif
+
+/* @} */
+
+/*! @name Alignment variable definition macros */
+/* @{ */
+#if (defined(__ICCARM__))
+/*
+ * Workaround to disable MISRA C message suppress warnings for IAR compiler.
+ * http:/ /supp.iar.com/Support/?note=24725
+ */
+_Pragma("diag_suppress=Pm120")
+#define SDK_PRAGMA(x) _Pragma(#x)
+ _Pragma("diag_error=Pm120")
+/*! Macro to define a variable with alignbytes alignment */
+#define SDK_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
+#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
+/*! Macro to define a variable with alignbytes alignment */
+#define SDK_ALIGN(var, alignbytes) __attribute__((aligned(alignbytes))) var
+#elif defined(__GNUC__)
+/*! Macro to define a variable with alignbytes alignment */
+#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
+#else
+#error Toolchain not supported
+#endif
+
+/*! Macro to define a variable with L1 d-cache line size alignment */
+#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
+#define SDK_L1DCACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
+#endif
+/*! Macro to define a variable with L2 cache line size alignment */
+#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
+#define SDK_L2CACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
+#endif
+
+/*! Macro to change a value to a given size aligned value */
+#define SDK_SIZEALIGN(var, alignbytes) \
+ ((unsigned int)((var) + ((alignbytes)-1U)) & (unsigned int)(~(unsigned int)((alignbytes)-1U)))
+/* @} */
+
+/*! @name Non-cacheable region definition macros */
+/* For initialized non-zero non-cacheable variables, please using "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or
+ * "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them, for zero-inited non-cacheable
+ * variables, please using "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them,
+ * these zero-inited variables will be initialized to zero in system startup.
+ */
+/* @{ */
+
+#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && \
+ defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
+
+#if (defined(__ICCARM__))
+#define AT_NONCACHEABLE_SECTION(var) var @"NonCacheable"
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable"
+#define AT_NONCACHEABLE_SECTION_INIT(var) var @"NonCacheable.init"
+#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
+ SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init"
+
+#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
+#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
+#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
+ __attribute__((section("NonCacheable.init"))) __attribute__((aligned(alignbytes))) var
+#if (defined(__CC_ARM))
+#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
+ __attribute__((section("NonCacheable"), zero_init)) __attribute__((aligned(alignbytes))) var
+#else
+#define AT_NONCACHEABLE_SECTION(var) __attribute__((section(".bss.NonCacheable"))) var
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
+ __attribute__((section(".bss.NonCacheable"))) __attribute__((aligned(alignbytes))) var
+#endif
+
+#elif (defined(__GNUC__))
+#if defined(__ARM_ARCH_8A__) /* This macro is ARMv8-A specific */
+#define __CS "//"
+#else
+#define __CS "@"
+#endif
+
+/* For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA"
+ * in your projects to make sure the non-cacheable section variables will be initialized in system startup.
+ */
+#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
+#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
+ __attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
+#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable,\"aw\",%nobits " __CS))) var
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
+ __attribute__((section("NonCacheable,\"aw\",%nobits " __CS))) var __attribute__((aligned(alignbytes)))
+#else
+#error Toolchain not supported.
+#endif
+
+#else
+
+#define AT_NONCACHEABLE_SECTION(var) var
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_ALIGN(var, alignbytes)
+#define AT_NONCACHEABLE_SECTION_INIT(var) var
+#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_ALIGN(var, alignbytes)
+
+#endif
+
+/* @} */
+
+/*!
+ * @name Time sensitive region
+ * @{
+ */
+#if (defined(__ICCARM__))
+#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
+#define AT_QUICKACCESS_SECTION_DATA(var) var @"DataQuickAccess"
+#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
+ SDK_PRAGMA(data_alignment = alignbytes) var @"DataQuickAccess"
+#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
+#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
+#define AT_QUICKACCESS_SECTION_DATA(var) __attribute__((section("DataQuickAccess"))) var
+#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
+ __attribute__((section("DataQuickAccess"))) __attribute__((aligned(alignbytes))) var
+#elif (defined(__GNUC__))
+#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
+#define AT_QUICKACCESS_SECTION_DATA(var) __attribute__((section("DataQuickAccess"))) var
+#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
+ __attribute__((section("DataQuickAccess"))) var __attribute__((aligned(alignbytes)))
+#else
+#error Toolchain not supported.
+#endif /* defined(__ICCARM__) */
+
+/*! @name Ram Function */
+#if (defined(__ICCARM__))
+#define RAMFUNCTION_SECTION_CODE(func) func @"RamFunction"
+#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
+#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
+#elif (defined(__GNUC__))
+#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
+#else
+#error Toolchain not supported.
+#endif /* defined(__ICCARM__) */
+/* @} */
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+ void DefaultISR(void);
+#endif
+
+/*
+ * The fsl_clock.h is included here because it needs MAKE_VERSION/MAKE_STATUS/status_t
+ * defined in previous of this file.
+ */
+#include "fsl_clock.h"
+
+/*
+ * Chip level peripheral reset API, for MCUs that implement peripheral reset control external to a peripheral
+ */
+#if ((defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) || \
+ (defined(FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT) && (FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT > 0)))
+#include "fsl_reset.h"
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief Enable specific interrupt.
+ *
+ * Enable LEVEL1 interrupt. For some devices, there might be multiple interrupt
+ * levels. For example, there are NVIC and intmux. Here the interrupts connected
+ * to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
+ * The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
+ * to NVIC first then routed to core.
+ *
+ * This function only enables the LEVEL1 interrupts. The number of LEVEL1 interrupts
+ * is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
+ *
+ * @param interrupt The IRQ number.
+ * @retval kStatus_Success Interrupt enabled successfully
+ * @retval kStatus_Fail Failed to enable the interrupt
+ */
+static inline status_t EnableIRQ(IRQn_Type interrupt)
+{
+ status_t status = kStatus_Success;
+
+ if (NotAvail_IRQn == interrupt)
+ {
+ status = kStatus_Fail;
+ }
+
+#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
+ else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+ else
+ {
+#if defined(__GIC_PRIO_BITS)
+ GIC_EnableIRQ(interrupt);
+#else
+ NVIC_EnableIRQ(interrupt);
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Disable specific interrupt.
+ *
+ * Disable LEVEL1 interrupt. For some devices, there might be multiple interrupt
+ * levels. For example, there are NVIC and intmux. Here the interrupts connected
+ * to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
+ * The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
+ * to NVIC first then routed to core.
+ *
+ * This function only disables the LEVEL1 interrupts. The number of LEVEL1 interrupts
+ * is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
+ *
+ * @param interrupt The IRQ number.
+ * @retval kStatus_Success Interrupt disabled successfully
+ * @retval kStatus_Fail Failed to disable the interrupt
+ */
+static inline status_t DisableIRQ(IRQn_Type interrupt)
+{
+ status_t status = kStatus_Success;
+
+ if (NotAvail_IRQn == interrupt)
+ {
+ status = kStatus_Fail;
+ }
+
+#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
+ else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+ else
+ {
+#if defined(__GIC_PRIO_BITS)
+ GIC_DisableIRQ(interrupt);
+#else
+ NVIC_DisableIRQ(interrupt);
+#endif
+ }
+
+ return status;
+}
+
+#if defined(__GIC_PRIO_BITS)
+#define NVIC_SetPriority(irq, prio) do {} while(0)
+#endif
+
+/*!
+ * @brief Enable the IRQ, and also set the interrupt priority.
+ *
+ * Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
+ * levels. For example, there are NVIC and intmux. Here the interrupts connected
+ * to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
+ * The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
+ * to NVIC first then routed to core.
+ *
+ * This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
+ * is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
+ *
+ * @param interrupt The IRQ to Enable.
+ * @param priNum Priority number set to interrupt controller register.
+ * @retval kStatus_Success Interrupt priority set successfully
+ * @retval kStatus_Fail Failed to set the interrupt priority.
+ */
+static inline status_t EnableIRQWithPriority(IRQn_Type interrupt, uint8_t priNum)
+{
+ status_t status = kStatus_Success;
+
+ if (NotAvail_IRQn == interrupt)
+ {
+ status = kStatus_Fail;
+ }
+
+#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
+ else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+ else
+ {
+#if defined(__GIC_PRIO_BITS)
+ GIC_SetPriority(interrupt, priNum);
+ GIC_EnableIRQ(interrupt);
+#else
+ NVIC_SetPriority(interrupt, priNum);
+ NVIC_EnableIRQ(interrupt);
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Set the IRQ priority.
+ *
+ * Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
+ * levels. For example, there are NVIC and intmux. Here the interrupts connected
+ * to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
+ * The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
+ * to NVIC first then routed to core.
+ *
+ * This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
+ * is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
+ *
+ * @param interrupt The IRQ to set.
+ * @param priNum Priority number set to interrupt controller register.
+ *
+ * @retval kStatus_Success Interrupt priority set successfully
+ * @retval kStatus_Fail Failed to set the interrupt priority.
+ */
+static inline status_t IRQ_SetPriority(IRQn_Type interrupt, uint8_t priNum)
+{
+ status_t status = kStatus_Success;
+
+ if (NotAvail_IRQn == interrupt)
+ {
+ status = kStatus_Fail;
+ }
+
+#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
+ else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+ else
+ {
+#if defined(__GIC_PRIO_BITS)
+ GIC_SetPriority(interrupt, priNum);
+#else
+ NVIC_SetPriority(interrupt, priNum);
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Clear the pending IRQ flag.
+ *
+ * Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
+ * levels. For example, there are NVIC and intmux. Here the interrupts connected
+ * to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
+ * The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
+ * to NVIC first then routed to core.
+ *
+ * This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
+ * is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
+ *
+ * @param interrupt The flag which IRQ to clear.
+ *
+ * @retval kStatus_Success Interrupt priority set successfully
+ * @retval kStatus_Fail Failed to set the interrupt priority.
+ */
+static inline status_t IRQ_ClearPendingIRQ(IRQn_Type interrupt)
+{
+ status_t status = kStatus_Success;
+
+ if (NotAvail_IRQn == interrupt)
+ {
+ status = kStatus_Fail;
+ }
+
+#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
+ else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+ else
+ {
+#if defined(__GIC_PRIO_BITS)
+ GIC_ClearPendingIRQ(interrupt);
+#else
+ NVIC_ClearPendingIRQ(interrupt);
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Disable the global IRQ
+ *
+ * Disable the global interrupt and return the current primask register. User is required to provided the primask
+ * register for the EnableGlobalIRQ().
+ *
+ * @return Current primask value.
+ */
+static inline uint32_t DisableGlobalIRQ(void)
+{
+ uint32_t mask;
+
+#if defined(CPSR_I_Msk)
+ mask = __get_CPSR() & CPSR_I_Msk;
+#elif defined(DAIF_I_BIT)
+ mask = __get_DAIF() & DAIF_I_BIT;
+#else
+ mask = __get_PRIMASK();
+#endif
+ __disable_irq();
+
+ return mask;
+}
+
+/*!
+ * @brief Enable the global IRQ
+ *
+ * Set the primask register with the provided primask value but not just enable the primask. The idea is for the
+ * convenience of integration of RTOS. some RTOS get its own management mechanism of primask. User is required to
+ * use the EnableGlobalIRQ() and DisableGlobalIRQ() in pair.
+ *
+ * @param primask value of primask register to be restored. The primask value is supposed to be provided by the
+ * DisableGlobalIRQ().
+ */
+static inline void EnableGlobalIRQ(uint32_t primask)
+{
+#if defined(CPSR_I_Msk)
+ __set_CPSR((__get_CPSR() & ~CPSR_I_Msk) | primask);
+#elif defined(DAIF_I_BIT)
+ if (0UL == primask)
+ {
+ __enable_irq();
+ }
+#else
+ __set_PRIMASK(primask);
+#endif
+}
+
+#if defined(ENABLE_RAM_VECTOR_TABLE)
+/*!
+ * @brief install IRQ handler
+ *
+ * @param irq IRQ number
+ * @param irqHandler IRQ handler address
+ * @return The old IRQ handler address
+ */
+uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler);
+#endif /* ENABLE_RAM_VECTOR_TABLE. */
+
+#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
+
+/*
+ * When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
+ * powerlib should be used instead of these functions.
+ */
+#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
+/*!
+ * @brief Enable specific interrupt for wake-up from deep-sleep mode.
+ *
+ * Enable the interrupt for wake-up from deep sleep mode.
+ * Some interrupts are typically used in sleep mode only and will not occur during
+ * deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
+ * those clocks (significantly increasing power consumption in the reduced power mode),
+ * making these wake-ups possible.
+ *
+ * @note This function also enables the interrupt in the NVIC (EnableIRQ() is called internaly).
+ *
+ * @param interrupt The IRQ number.
+ */
+void EnableDeepSleepIRQ(IRQn_Type interrupt);
+
+/*!
+ * @brief Disable specific interrupt for wake-up from deep-sleep mode.
+ *
+ * Disable the interrupt for wake-up from deep sleep mode.
+ * Some interrupts are typically used in sleep mode only and will not occur during
+ * deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
+ * those clocks (significantly increasing power consumption in the reduced power mode),
+ * making these wake-ups possible.
+ *
+ * @note This function also disables the interrupt in the NVIC (DisableIRQ() is called internaly).
+ *
+ * @param interrupt The IRQ number.
+ */
+void DisableDeepSleepIRQ(IRQn_Type interrupt);
+#endif /* FSL_FEATURE_POWERLIB_EXTEND */
+#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
+
+#if defined(DWT)
+/*!
+ * @brief Enable the counter to get CPU cycles.
+ */
+void MSDK_EnableCpuCycleCounter(void);
+
+/*!
+ * @brief Get the current CPU cycle count.
+ *
+ * @return Current CPU cycle count.
+ */
+uint32_t MSDK_GetCpuCycleCount(void);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_COMMON_ARM_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_dsp.h b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_dsp.h
new file mode 100644
index 0000000000..84fb6a112c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/common/fsl_common_dsp.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_COMMON_DSP_H_
+#define _FSL_COMMON_DSP_H_
+
+/*!
+ * @addtogroup ksdk_common
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Timer utilities */
+/* @{ */
+/*! Macro to convert a microsecond period to raw count value */
+#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)(((uint64_t)(us) * (clockFreqInHz)) / 1000000U)
+/*! Macro to convert a raw count value to microsecond */
+#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count) * 1000000U / (clockFreqInHz))
+
+/*! Macro to convert a millisecond period to raw count value */
+#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)(ms) * (clockFreqInHz) / 1000U)
+/*! Macro to convert a raw count value to millisecond */
+#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count) * 1000U / (clockFreqInHz))
+/* @} */
+
+#define SDK_ISR_EXIT_BARRIER
+
+/*! @name Alignment variable definition macros */
+/* @{ */
+/*! Macro to define a variable with alignbytes alignment */
+#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
+
+/*! Macro to define a variable with L1 d-cache line size alignment */
+#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
+#define SDK_L1DCACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
+#endif
+
+/*! Macro to define a variable with L2 cache line size alignment */
+#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
+#define SDK_L2CACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
+#endif
+
+/*! Macro to change a value to a given size aligned value */
+#define SDK_SIZEALIGN(var, alignbytes) \
+ ((unsigned int)((var) + ((alignbytes)-1U)) & (unsigned int)(~(unsigned int)((alignbytes)-1U)))
+/* @} */
+
+/*! @name Non-cacheable region definition macros */
+/* For initialized non-zero non-cacheable variables, please using "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or
+ * "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them, for zero-inited non-cacheable variables,
+ * please using "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them, these zero-inited variables
+ * will be initialized to zero in system startup.
+ */
+/* @{ */
+
+#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
+#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"))) var
+#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
+ __attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
+#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
+ __attribute__((section("NonCacheable"))) var __attribute__((aligned(alignbytes)))
+
+/* @} */
+
+/*!
+ * @name Time sensitive region
+ * @{
+ */
+#if (defined(FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE) && FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE)
+
+#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
+#define AT_QUICKACCESS_SECTION_DATA(func) __attribute__((section("DataQuickAccess"))) func
+
+#else /* __FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE */
+
+#define AT_QUICKACCESS_SECTION_CODE(func) func
+#define AT_QUICKACCESS_SECTION_DATA(func) func
+
+#endif /* __FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE */
+/* @} */
+
+/* Macros for compatibility. */
+#define NVIC_SetPriorityGrouping(value) do {} while(0)
+#define NVIC_GetPriorityGrouping() do {} while(0)
+#define NVIC_EnableIRQ(value) do {} while(0)
+#define NVIC_GetEnableIRQ(value) do {} while(0)
+#define NVIC_DisableIRQ(value) do {} while(0)
+#define NVIC_GetPendingIRQ(value) do {} while(0)
+#define NVIC_SetPendingIRQ(value) do {} while(0)
+#define NVIC_ClearPendingIRQ(value) do {} while(0)
+#define NVIC_GetActive(value) do {} while(0)
+
+/*
+ * The fsl_clock.h is included here because it needs MAKE_VERSION/MAKE_STATUS/status_t
+ * defined in previous of this file.
+ */
+#include "fsl_clock.h"
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Enable specific interrupt.
+ *
+ * Empty function for build compatibility.
+ *
+ * @param interrupt The IRQ number.
+ * @return Always return kStatus_Success.
+ */
+static inline status_t EnableIRQ(IRQn_Type interrupt)
+{
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Disable specific interrupt.
+ *
+ * Empty function for build compatibility.
+ *
+ * @param interrupt The IRQ number.
+ * @return Always return kStatus_Success.
+ */
+static inline status_t DisableIRQ(IRQn_Type interrupt)
+{
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Disable the global IRQ
+ *
+ * Empty function for build compatibility.
+ *
+ * @return Always return 0;
+ */
+static inline uint32_t DisableGlobalIRQ(void)
+{
+ return 0;
+}
+
+/*!
+ * @brief Enable the global IRQ
+ *
+ * Empty function for build compatibility.
+ *
+ * @param primask Not used.
+ */
+static inline void EnableGlobalIRQ(uint32_t primask)
+{
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @} */
+
+#endif /* _FSL_COMMON_DSP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.c b/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.c
new file mode 100644
index 0000000000..e23fba521b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.c
@@ -0,0 +1,1417 @@
+/*
+ * Copyright 2017-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_csi.h"
+#if CSI_DRIVER_FRAG_MODE
+#include "fsl_cache.h"
+#endif
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#include "fsl_memory.h"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* Macro remap. */
+#if (!defined(CSI_CR3_TWO_8BIT_SENSOR_MASK) && defined(CSI_CR3_SENSOR_16BITS_MASK))
+#define CSI_CR3_TWO_8BIT_SENSOR_MASK CSI_CR3_SENSOR_16BITS_MASK
+#endif
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.csi"
+#endif
+
+/* Two frame buffer loaded to CSI register at most. */
+#define CSI_MAX_ACTIVE_FRAME_NUM 2U
+
+/* CSI driver only support RGB565 and YUV422 in fragment mode, 2 bytes per pixel. */
+#define CSI_FRAG_INPUT_BYTES_PER_PIXEL 2U
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#define CSI_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
+#define CSI_ADDR_IP_2_CPU(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_DMA2Local))
+#else
+#define CSI_ADDR_CPU_2_IP(addr) (addr)
+#define CSI_ADDR_IP_2_CPU(addr) (addr)
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+/*!
+ * @brief Used for conversion between `void*` and `uint32_t`.
+ */
+typedef union pvoid_to_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pvoid_to_u32_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base CSI peripheral base address
+ *
+ * @return The CSI module instance
+ */
+static uint32_t CSI_GetInstance(CSI_Type *base);
+
+#if !CSI_DRIVER_FRAG_MODE
+/*!
+ * @brief Get the delta value of two index in queue.
+ *
+ * @param startIdx Start index.
+ * @param endIdx End index.
+ *
+ * @return The delta between startIdx and endIdx in queue.
+ */
+static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx);
+
+/*!
+ * @brief Increase a index value in queue.
+ *
+ * This function increases the index value in the queue, if the index is out of
+ * the queue range, it is reset to 0.
+ *
+ * @param idx The index value to increase.
+ *
+ * @return The index value after increase.
+ */
+static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx);
+
+/*!
+ * @brief Get the empty frame buffer count in queue.
+ *
+ * @param base CSI peripheral base address
+ * @param handle Pointer to CSI driver handle.
+ *
+ * @return Number of the empty frame buffer count in queue.
+ */
+static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle);
+
+/*!
+ * @brief Get the empty frame buffer.
+ *
+ * This function should only be called when frame buffer count larger than 0.
+ *
+ * @param handle Pointer to CSI driver handle.
+ *
+ * @return Empty buffer
+ */
+static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle);
+
+/*!
+ * @brief Put the empty frame buffer.
+ *
+ * @param handle Pointer to CSI driver handle.
+ * @param buffer The empty buffer to put.
+ */
+static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer);
+
+/*!
+ * @brief Get the RX frame buffer address.
+ *
+ * @param base CSI peripheral base address.
+ * @param index Buffer index.
+ * @return Frame buffer address.
+ */
+static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index);
+
+/* Typedef for interrupt handler. */
+typedef void (*csi_isr_t)(CSI_Type *base, csi_handle_t *handle);
+
+#else
+
+/* Typedef for interrupt handler to work in fragment mode. */
+typedef void (*csi_isr_t)(CSI_Type *base, csi_frag_handle_t *handle);
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to CSI bases for each instance. */
+static CSI_Type *const s_csiBases[] = CSI_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to CSI clocks for each CSI submodule. */
+static const clock_ip_name_t s_csiClocks[] = CSI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* Array for the CSI driver handle. */
+#if !CSI_DRIVER_FRAG_MODE
+static csi_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
+#else
+static csi_frag_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
+#endif
+
+/* Array of CSI IRQ number. */
+static const IRQn_Type s_csiIRQ[] = CSI_IRQS;
+
+/* CSI ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static csi_isr_t s_csiIsr = (csi_isr_t)DefaultISR;
+#else
+static csi_isr_t s_csiIsr;
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t CSI_GetInstance(CSI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_csiBases); instance++)
+ {
+ if (s_csiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_csiBases));
+
+ return instance;
+}
+
+#if !CSI_DRIVER_FRAG_MODE
+static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx)
+{
+ uint8_t ret;
+
+ if (endIdx >= startIdx)
+ {
+ ret = endIdx - startIdx;
+ }
+ else
+ {
+ ret = (uint8_t)(endIdx + CSI_DRIVER_ACTUAL_QUEUE_SIZE - startIdx);
+ }
+
+ return ret;
+}
+
+static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx)
+{
+ uint8_t ret;
+
+ /*
+ * Here not use the method:
+ * ret = (idx+1) % CSI_DRIVER_ACTUAL_QUEUE_SIZE;
+ *
+ * Because the mod function might be slow.
+ */
+
+ ret = idx + 1U;
+
+ if (ret >= CSI_DRIVER_ACTUAL_QUEUE_SIZE)
+ {
+ ret = 0U;
+ }
+
+ return ret;
+}
+
+static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle)
+{
+ return handle->emptyBufferCnt;
+}
+
+static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle)
+{
+ pvoid_to_u32_t buf;
+
+ buf.pvoid = handle->emptyBuffer;
+ handle->emptyBufferCnt--;
+ handle->emptyBuffer = *(void **)(buf.pvoid);
+
+ return buf.u32;
+}
+
+static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer)
+{
+ pvoid_to_u32_t buf;
+ buf.u32 = buffer;
+
+ *(void **)(buf.pvoid) = handle->emptyBuffer;
+ handle->emptyBuffer = buf.pvoid;
+ handle->emptyBufferCnt++;
+}
+
+static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index)
+{
+ uint32_t addr;
+
+ if (index != 0U)
+ {
+ addr = CSI_REG_DMASA_FB2(base);
+ }
+ else
+ {
+ addr = CSI_REG_DMASA_FB1(base);
+ }
+
+ return CSI_ADDR_IP_2_CPU(addr);
+}
+
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+/*!
+ * brief Initialize the CSI.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * param base CSI peripheral base address.
+ * param config Pointer to the configuration structure.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_Init(CSI_Type *base, const csi_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+ uint32_t imgWidth_Bytes;
+ uint8_t busCyclePerPixel;
+
+ imgWidth_Bytes = (uint32_t)config->width * (uint32_t)config->bytesPerPixel;
+
+ /* The image width and frame buffer pitch should be multiple of 8-bytes. */
+ if ((0U != (imgWidth_Bytes & 0x07U)) || (0U != ((uint32_t)config->linePitch_Bytes & 0x07U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_EnableClock(s_csiClocks[instance]);
+#endif
+
+ CSI_Reset(base);
+
+ /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
+ reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CR1_FCC_MASK;
+
+ if (config->useExtVsync)
+ {
+ reg |= CSI_CR1_EXT_VSYNC_MASK;
+ }
+
+ CSI_REG_CR1(base) = reg;
+
+ /*
+ * Generally, CSIIMAG_PARA[IMAGE_WIDTH] indicates how many data bus cycles per line.
+ * One special case is when receiving 24-bit pixels through 8-bit data bus.
+ * In this case, the CSIIMAG_PARA[IMAGE_WIDTH] should be set to the pixel number per line.
+ */
+ if ((kCSI_DataBus8Bit == config->dataBus) && (2U == config->bytesPerPixel))
+ {
+ busCyclePerPixel = 2U;
+ }
+ else
+ {
+ busCyclePerPixel = 1U;
+ }
+
+ if (4U == config->bytesPerPixel)
+ {
+ CSI_REG_CR18(base) |= CSI_CR18_PARALLEL24_EN_MASK;
+ }
+
+ if (kCSI_DataBus16Bit == config->dataBus)
+ {
+ CSI_REG_CR3(base) |= CSI_CR3_TWO_8BIT_SENSOR_MASK;
+ }
+
+ /* Image parameter. */
+ CSI_REG_IMAG_PARA(base) =
+ (((uint32_t)config->width * (uint32_t)busCyclePerPixel) << CSI_IMAG_PARA_IMAGE_WIDTH_SHIFT) |
+ ((uint32_t)(config->height) << CSI_IMAG_PARA_IMAGE_HEIGHT_SHIFT);
+
+ /* The CSI frame buffer bus is 8-byte width. */
+ CSI_REG_FBUF_PARA(base) = (uint32_t)((config->linePitch_Bytes - imgWidth_Bytes) / 8U)
+ << CSI_FBUF_PARA_FBUF_STRIDE_SHIFT;
+
+ /* Enable auto ECC. */
+ CSI_REG_CR3(base) |= CSI_CR3_ECC_AUTO_EN_MASK;
+
+ /*
+ * For better performance.
+ * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
+ * choose the best burst size based on bytes per line.
+ */
+ if (0U == (imgWidth_Bytes % (8U * 16U)))
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(3U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((2U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+ else if (0U == (imgWidth_Bytes % (8U * 8U)))
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(2U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((1U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+ else
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(1U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((0U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+
+ CSI_ReflashFifoDma(base, kCSI_RxFifo);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_Deinit(CSI_Type *base)
+{
+ /* Disable transfer first. */
+ CSI_Stop(base);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_DisableClock(s_csiClocks[instance]);
+#endif
+}
+
+/*!
+ * brief Reset the CSI.
+ *
+ * This function resets the CSI peripheral registers to default status.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_Reset(CSI_Type *base)
+{
+ uint32_t csisr;
+
+ /* Disable transfer first. */
+ CSI_Stop(base);
+
+ /* Disable DMA request. */
+ CSI_REG_CR3(base) = 0U;
+
+ /* Reset the fame count. */
+ CSI_REG_CR3(base) |= CSI_CR3_FRMCNT_RST_MASK;
+ while (0U != (CSI_REG_CR3(base) & CSI_CR3_FRMCNT_RST_MASK))
+ {
+ }
+
+ /* Clear the RX FIFO. */
+ CSI_ClearFifo(base, kCSI_AllFifo);
+
+ /* Reflash DMA. */
+ CSI_ReflashFifoDma(base, kCSI_AllFifo);
+
+ /* Clear the status. */
+ csisr = CSI_REG_SR(base);
+ CSI_REG_SR(base) = csisr;
+
+ /* Set the control registers to default value. */
+ CSI_REG_CR1(base) = CSI_CR1_HSYNC_POL_MASK | CSI_CR1_EXT_VSYNC_MASK;
+ CSI_REG_CR2(base) = 0U;
+ CSI_REG_CR3(base) = 0U;
+#if defined(CSI_CR18_CSI_LCDIF_BUFFER_LINES)
+ CSI_REG_CR18(base) = CSI_CR18_AHB_HPROT(0x0DU) | CSI_CR18_CSI_LCDIF_BUFFER_LINES(0x02U);
+#else
+ CSI_REG_CR18(base) = CSI_CR18_AHB_HPROT(0x0DU);
+#endif
+ CSI_REG_FBUF_PARA(base) = 0U;
+ CSI_REG_IMAG_PARA(base) = 0U;
+}
+
+/*!
+ * brief Get the default configuration for to initialize the CSI.
+ *
+ * The default configuration value is:
+ *
+ * code
+ config->width = 320U;
+ config->height = 240U;
+ config->polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge;
+ config->bytesPerPixel = 2U;
+ config->linePitch_Bytes = 320U * 2U;
+ config->workMode = kCSI_GatedClockMode;
+ config->dataBus = kCSI_DataBus8Bit;
+ config->useExtVsync = true;
+ endcode
+ *
+ * param config Pointer to the CSI configuration.
+ */
+void CSI_GetDefaultConfig(csi_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->width = 320U;
+ config->height = 240U;
+ config->polarityFlags = (uint32_t)kCSI_HsyncActiveHigh | (uint32_t)kCSI_DataLatchOnRisingEdge;
+ config->bytesPerPixel = 2U;
+ config->linePitch_Bytes = 320U * 2U;
+ config->workMode = kCSI_GatedClockMode;
+ config->dataBus = kCSI_DataBus8Bit;
+ config->useExtVsync = true;
+}
+
+/*!
+ * brief Set the RX frame buffer address.
+ *
+ * param base CSI peripheral base address.
+ * param index Buffer index.
+ * param addr Frame buffer address to set.
+ */
+void CSI_SetRxBufferAddr(CSI_Type *base, uint8_t index, uint32_t addr)
+{
+ addr = CSI_ADDR_CPU_2_IP(addr);
+
+ if (0U != index)
+ {
+ CSI_REG_DMASA_FB2(base) = addr;
+ }
+ else
+ {
+ CSI_REG_DMASA_FB1(base) = addr;
+ }
+}
+
+/*!
+ * brief Clear the CSI FIFO.
+ *
+ * This function clears the CSI FIFO.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO to clear.
+ */
+void CSI_ClearFifo(CSI_Type *base, csi_fifo_t fifo)
+{
+ uint32_t cr1;
+ uint32_t mask = 0U;
+
+ /* The FIFO could only be cleared when CSICR1[FCC] = 0, so first clear the FCC. */
+ cr1 = CSI_REG_CR1(base);
+ CSI_REG_CR1(base) = (cr1 & ~CSI_CR1_FCC_MASK);
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ mask |= CSI_CR1_CLR_RXFIFO_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ mask |= CSI_CR1_CLR_STATFIFO_MASK;
+ }
+
+ CSI_REG_CR1(base) = (cr1 & ~CSI_CR1_FCC_MASK) | mask;
+
+ /* Wait clear completed. */
+ while (0U != (CSI_REG_CR1(base) & mask))
+ {
+ }
+
+ /* Recover the FCC. */
+ CSI_REG_CR1(base) = cr1;
+}
+
+/*!
+ * brief Reflash the CSI FIFO DMA.
+ *
+ * This function reflashes the CSI FIFO DMA.
+ *
+ * For RXFIFO, there are two frame buffers. When the CSI module started, it saves
+ * the frames to frame buffer 0 then frame buffer 1, the two buffers will be
+ * written by turns. After reflash DMA using this function, the CSI is reset to
+ * save frame to buffer 0.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO DMA to reflash.
+ */
+void CSI_ReflashFifoDma(CSI_Type *base, csi_fifo_t fifo)
+{
+ uint32_t cr3 = 0U;
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ cr3 |= CSI_CR3_DMA_REFLASH_RFF_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ cr3 |= CSI_CR3_DMA_REFLASH_SFF_MASK;
+ }
+
+ CSI_REG_CR3(base) |= cr3;
+
+ /* Wait clear completed. */
+ while (0U != (CSI_REG_CR3(base) & cr3))
+ {
+ }
+}
+
+/*!
+ * brief Enable or disable the CSI FIFO DMA request.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO DMA reques to enable or disable.
+ * param enable True to enable, false to disable.
+ */
+void CSI_EnableFifoDmaRequest(CSI_Type *base, csi_fifo_t fifo, bool enable)
+{
+ uint32_t cr3 = 0U;
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ cr3 |= CSI_CR3_DMA_REQ_EN_RFF_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ cr3 |= CSI_CR3_DMA_REQ_EN_SFF_MASK;
+ }
+
+ if (enable)
+ {
+ CSI_REG_CR3(base) |= cr3;
+ }
+ else
+ {
+ CSI_REG_CR3(base) &= ~cr3;
+ }
+}
+
+/*!
+ * brief Enables CSI interrupt requests.
+ *
+ * param base CSI peripheral base address.
+ * param mask The interrupts to enable, pass in as OR'ed value of ref _csi_interrupt_enable.
+ */
+void CSI_EnableInterrupts(CSI_Type *base, uint32_t mask)
+{
+ CSI_REG_CR1(base) |= (mask & CSI_CR1_INT_EN_MASK);
+ CSI_REG_CR3(base) |= (mask & CSI_CR3_INT_EN_MASK);
+ CSI_REG_CR18(base) |= ((mask & CSI_CR18_INT_EN_MASK) >> 6U);
+}
+
+/*!
+ * brief Disable CSI interrupt requests.
+ *
+ * param base CSI peripheral base address.
+ * param mask The interrupts to disable, pass in as OR'ed value of ref _csi_interrupt_enable.
+ */
+void CSI_DisableInterrupts(CSI_Type *base, uint32_t mask)
+{
+ CSI_REG_CR1(base) &= ~(mask & CSI_CR1_INT_EN_MASK);
+ CSI_REG_CR3(base) &= ~(mask & CSI_CR3_INT_EN_MASK);
+ CSI_REG_CR18(base) &= ~((mask & CSI_CR18_INT_EN_MASK) >> 6U);
+}
+
+#if !CSI_DRIVER_FRAG_MODE
+/*!
+ * brief Initializes the CSI handle.
+ *
+ * This function initializes CSI handle, it should be called before any other
+ * CSI transactional functions.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param callback Callback function for CSI transfer.
+ * param userData Callback function parameter.
+ *
+ * retval kStatus_Success Handle created successfully.
+ */
+status_t CSI_TransferCreateHandle(CSI_Type *base,
+ csi_handle_t *handle,
+ csi_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+ uint32_t instance;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Get instance from peripheral base address. */
+ instance = CSI_GetInstance(base);
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_csiHandle[instance] = handle;
+
+ s_csiIsr = CSI_TransferHandleIRQ;
+
+ /* Enable interrupt. */
+ (void)EnableIRQ(s_csiIRQ[instance]);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Start the transfer using transactional functions.
+ *
+ * When the empty frame buffers have been submit to CSI driver using function
+ * ref CSI_TransferSubmitEmptyBuffer, user could call this function to start
+ * the transfer. The incoming frame will be saved to the empty frame buffer,
+ * and user could be optionally notified through callback function.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_NoEmptyBuffer Could not start because no empty frame buffer in queue.
+ */
+status_t CSI_TransferStart(CSI_Type *base, csi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ uint32_t emptyBufferCount;
+
+ emptyBufferCount = CSI_TransferGetEmptyBufferCount(handle);
+
+ if (emptyBufferCount < 2U)
+ {
+ return kStatus_CSI_NoEmptyBuffer;
+ }
+
+ /*
+ * Write to memory from first completed frame.
+ * DMA base addr switch at the edge of the first data of each frame, thus
+ * if one frame is broken, it could be reset at the next frame.
+ */
+ CSI_REG_CR18(base) = (CSI_REG_CR18(base) & ~CSI_CR18_MASK_OPTION_MASK) | CSI_CR18_MASK_OPTION(0) |
+ CSI_CR18_BASEADDR_SWITCH_SEL_MASK | CSI_CR18_BASEADDR_SWITCH_EN_MASK;
+
+ /* Load the frame buffer to CSI register, there are at least two empty buffers. */
+ CSI_REG_DMASA_FB1(base) = CSI_ADDR_CPU_2_IP(CSI_TransferGetEmptyBuffer(handle));
+ CSI_REG_DMASA_FB2(base) = CSI_ADDR_CPU_2_IP(CSI_TransferGetEmptyBuffer(handle));
+
+ handle->activeBufferNum = CSI_MAX_ACTIVE_FRAME_NUM;
+
+ /* After reflash DMA, the CSI saves frame to frame buffer 0. */
+ CSI_ReflashFifoDma(base, kCSI_RxFifo);
+
+ handle->transferStarted = true;
+
+ CSI_EnableInterrupts(
+ base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ CSI_Start(base);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Stop the transfer using transactional functions.
+ *
+ * The driver does not clean the full frame buffers in queue. In other words, after
+ * calling this function, user still could get the full frame buffers in queue
+ * using function ref CSI_TransferGetFullBuffer.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ *
+ * retval kStatus_Success Stoped successfully.
+ */
+status_t CSI_TransferStop(CSI_Type *base, csi_handle_t *handle)
+{
+ assert(NULL != handle);
+ uint8_t activeBufferNum;
+ uint8_t bufIdx;
+
+ CSI_Stop(base);
+ CSI_DisableInterrupts(
+ base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ activeBufferNum = handle->activeBufferNum;
+
+ handle->transferStarted = false;
+ handle->activeBufferNum = 0;
+
+ /*
+ * Put active buffers to empty queue.
+ *
+ * If there is only one active frame buffers, then FB0 and FB1 use the same address,
+ * put FB0 to empty buffer queue is OK.
+ */
+ for (bufIdx = 0; bufIdx < activeBufferNum; bufIdx++)
+ {
+ CSI_TransferPutEmptyBuffer(handle, CSI_GetRxBufferAddr(base, bufIdx));
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Submit empty frame buffer to queue.
+ *
+ * This function could be called before ref CSI_TransferStart or after ref
+ * CSI_TransferStart. If there is no room in queue to store the empty frame
+ * buffer, this function returns error.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param frameBuffer Empty frame buffer to submit.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_QueueFull Could not submit because there is no room in queue.
+ */
+status_t CSI_TransferSubmitEmptyBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t frameBuffer)
+{
+ uint32_t csicr1;
+
+ /* Disable the interrupt to protect the index information in handle. */
+ csicr1 = CSI_REG_CR1(base);
+
+ CSI_REG_CR1(base) = (csicr1 & ~(CSI_CR1_FB2_DMA_DONE_INTEN_MASK | CSI_CR1_FB1_DMA_DONE_INTEN_MASK));
+
+ /* Save the empty frame buffer address to queue. */
+ CSI_TransferPutEmptyBuffer(handle, frameBuffer);
+
+ CSI_REG_CR1(base) = csicr1;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get one full frame buffer from queue.
+ *
+ * After the transfer started using function ref CSI_TransferStart, the incoming
+ * frames will be saved to the empty frame buffers in queue. This function gets
+ * the full-filled frame buffer from the queue. If there is no full frame buffer
+ * in queue, this function returns error.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param frameBuffer Full frame buffer.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_NoFullBuffer There is no full frame buffer in queue.
+ */
+status_t CSI_TransferGetFullBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t *frameBuffer)
+{
+ uint32_t csicr1;
+ status_t status;
+ uint8_t queueReadIdx;
+ uint8_t queueWriteIdx;
+
+ queueReadIdx = handle->queueReadIdx;
+ queueWriteIdx = handle->queueWriteIdx;
+
+ /* No full frame buffer. */
+ if (queueReadIdx == queueWriteIdx)
+ {
+ status = kStatus_CSI_NoFullBuffer;
+ }
+ else
+ {
+ /* Disable the interrupt to protect the index information in handle. */
+ csicr1 = CSI_REG_CR1(base);
+
+ CSI_REG_CR1(base) = (csicr1 & ~(CSI_CR1_FB2_DMA_DONE_INTEN_MASK | CSI_CR1_FB1_DMA_DONE_INTEN_MASK));
+
+ *frameBuffer = handle->frameBufferQueue[handle->queueReadIdx];
+
+ handle->queueReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueReadIdx);
+
+ CSI_REG_CR1(base) = csicr1;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver transactional
+ * APIs.
+ *
+ * param base CSI peripheral base address.
+ * param handle CSI handle pointer.
+ */
+void CSI_TransferHandleIRQ(CSI_Type *base, csi_handle_t *handle)
+{
+ uint8_t queueWriteIdx;
+ uint8_t queueReadIdx;
+ uint8_t dmaDoneBufferIdx;
+ uint32_t frameBuffer;
+ uint32_t csisr = CSI_REG_SR(base);
+
+ /* Clear the error flags. */
+ CSI_REG_SR(base) = csisr;
+
+ /*
+ * If both frame buffer 0 and frame buffer 1 flags assert, driver does not
+ * know which frame buffer ready just now, so skip them.
+ */
+ if ((csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)) ==
+ (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK))
+ {
+ ; /* Skip the frames. */
+ }
+ else if (0U != (csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)))
+ {
+ if (0U != (csisr & CSI_SR_DMA_TSF_DONE_FB2_MASK))
+ {
+ dmaDoneBufferIdx = 1;
+ }
+ else
+ {
+ dmaDoneBufferIdx = 0;
+ }
+
+ if (handle->activeBufferNum == CSI_MAX_ACTIVE_FRAME_NUM)
+ {
+ queueWriteIdx = handle->queueWriteIdx;
+ queueReadIdx = handle->queueReadIdx;
+
+ if (CSI_TransferGetQueueDelta(queueReadIdx, queueWriteIdx) < CSI_DRIVER_QUEUE_SIZE)
+ {
+ /* Put the full frame buffer to full buffer queue. */
+ frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx);
+ handle->frameBufferQueue[queueWriteIdx] = frameBuffer;
+
+ handle->queueWriteIdx = CSI_TransferIncreaseQueueIdx(queueWriteIdx);
+
+ handle->activeBufferNum--;
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
+ }
+ }
+ else
+ {
+ }
+ }
+
+ /*
+ * User may submit new frame buffer in callback, so recheck activeBufferNum here,
+ * if there is only one active buffer in CSI device, the two buffer registers
+ * are both set to the frame buffer address.
+ */
+ if (handle->activeBufferNum < CSI_MAX_ACTIVE_FRAME_NUM)
+ {
+ if (CSI_TransferGetEmptyBufferCount(handle) > 0U)
+ {
+ /* Get the empty frameBuffer, and submit to CSI device. */
+ CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, CSI_TransferGetEmptyBuffer(handle));
+ handle->activeBufferNum++;
+ }
+ else
+ {
+ /* If there is only one active frame buffer, then the two CSI
+ * output buffer address are all set to this frame buffer.
+ */
+ frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx ^ 1U);
+ CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, frameBuffer);
+ }
+ }
+ }
+ else
+ {
+ }
+}
+
+#else /* CSI_DRIVER_FRAG_MODE */
+
+#if defined(__CC_ARM)
+__asm void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ push {r4-r7, lr}
+10
+ LDMIA R1!, {r3-r6}
+ bfi r7, r3, #0, #8 /* Y0 */
+ bfi ip, r5, #0, #8 /* Y4 */
+ lsr r3, r3, #16
+ lsr r5, r5, #16
+ bfi r7, r3, #8, #8 /* Y1 */
+ bfi ip, r5, #8, #8 /* Y5 */
+ bfi r7, r4, #16, #8 /* Y2 */
+ bfi ip, r6, #16, #8 /* Y6 */
+ lsr r4, r4, #16
+ lsr r6, r6, #16
+ bfi r7, r4, #24, #8 /* Y3 */
+ bfi ip, r6, #24, #8 /* Y7 */
+ STMIA r0!, {r7, ip}
+ subs r2, #8
+ bne %b10
+ pop {r4-r7, pc}
+ /* clang-format on */
+}
+
+__asm void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ push {r4-r7, lr}
+10
+ LDMIA R1!, {r3-r6}
+ lsr r3, r3, #8
+ lsr r5, r5, #8
+ bfi r7, r3, #0, #8 /* Y0 */
+ bfi ip, r5, #0, #8 /* Y4 */
+ lsr r3, r3, #16
+ lsr r5, r5, #16
+ bfi r7, r3, #8, #8 /* Y1 */
+ bfi ip, r5, #8, #8 /* Y5 */
+ lsr r4, r4, #8
+ lsr r6, r6, #8
+ bfi r7, r4, #16, #8 /* Y2 */
+ bfi ip, r6, #16, #8 /* Y6 */
+ lsr r4, r4, #16
+ lsr r6, r6, #16
+ bfi r7, r4, #24, #8 /* Y3 */
+ bfi ip, r6, #24, #8 /* Y7 */
+ STMIA r0!, {r7, ip}
+ subs r2, #8
+ bne %b10
+ pop {r4-r7, pc}
+ /* clang-format on */
+}
+
+#elif (defined(__GNUC__) || defined(__ICCARM__)) || defined(__ARMCC_VERSION)
+#if defined(__ICCARM__)
+#pragma diag_suppress = Pe940
+#endif
+__attribute__((naked)) void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count);
+void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ __asm volatile(
+ " push {r1-r7, r12, lr} \n"
+ "loop0: \n"
+ " ldmia r1!, {r3-r6} \n"
+ " bfi r7, r3, #0, #8 \n" /* Y0 */
+ " bfi r12, r5, #0, #8 \n" /* Y4 */
+ " lsr r3, r3, #16 \n"
+ " lsr r5, r5, #16 \n"
+ " bfi r7, r3, #8, #8 \n" /* Y1 */
+ " bfi r12, r5, #8, #8 \n" /* Y5 */
+ " bfi r7, r4, #16, #8 \n" /* Y2 */
+ " bfi r12, r6, #16, #8 \n" /* Y6 */
+ " lsr r4, r4, #16 \n"
+ " lsr r6, r6, #16 \n"
+ " bfi r7, r4, #24, #8 \n" /* Y3 */
+ " bfi r12, r6, #24, #8 \n" /* Y7 */
+ " stmia r0!, {r7, r12} \n"
+ " subs r2, #8 \n"
+ " bne loop0 \n"
+ " pop {r1-r7, r12, pc} \n");
+ /* clang-format on */
+}
+
+__attribute__((naked)) void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count);
+void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ __asm volatile(
+ " push {r1-r7, r12, lr} \n"
+ "loop1: \n"
+ " ldmia r1!, {r3-r6} \n"
+ " lsr r3, r3, #8 \n"
+ " lsr r5, r5, #8 \n"
+ " bfi r7, r3, #0, #8 \n" /* Y0 */
+ " bfi r12, r5, #0, #8 \n" /* Y4 */
+ " lsr r3, r3, #16 \n"
+ " lsr r5, r5, #16 \n"
+ " bfi r7, r3, #8, #8 \n" /* Y1 */
+ " bfi r12, r5, #8, #8 \n" /* Y5 */
+ " lsr r4, r4, #8 \n"
+ " lsr r6, r6, #8 \n"
+ " bfi r7, r4, #16, #8 \n" /* Y2 */
+ " bfi r12, r6, #16, #8 \n" /* Y6 */
+ " lsr r4, r4, #16 \n"
+ " lsr r6, r6, #16 \n"
+ " bfi r7, r4, #24, #8 \n" /* Y3 */
+ " bfi r12, r6, #24, #8 \n" /* Y7 */
+ " stmia r0!, {r7, r12} \n"
+ " subs r2, #8 \n"
+ " bne loop1 \n"
+ " pop {r1-r7, r12, pc} \n");
+ /* clang-format on */
+}
+#if defined(__ICCARM__)
+#pragma diag_default = Pe940
+#endif
+#else
+#error Toolchain not supported.
+#endif
+
+static void CSI_MemCopy(void *pDest, const void *pSrc, size_t cnt)
+{
+ (void)memcpy(pDest, pSrc, cnt);
+}
+
+/*!
+ * brief Initialize the CSI to work in fragment mode.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_FragModeInit(CSI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_EnableClock(s_csiClocks[instance]);
+#endif
+
+ CSI_Reset(base);
+}
+
+/*!
+ * brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_FragModeDeinit(CSI_Type *base)
+{
+ CSI_Deinit(base);
+}
+
+/*!
+ * brief Create handle for CSI work in fragment mode.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ * param config Pointer to the configuration structure.
+ * param callback Callback function for CSI transfer.
+ * param userData Callback function parameter.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeCreateHandle(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_config_t *config,
+ csi_frag_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != config);
+ uint32_t reg;
+ uint32_t instance;
+ uint32_t imgWidth_Bytes;
+
+ if (config->dataBus != kCSI_DataBus8Bit)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ imgWidth_Bytes = (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+
+ /* The image buffer line width should be multiple of 8-bytes. */
+ if ((imgWidth_Bytes & 0x07U) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Camera frame height must be dividable by DMA buffer line. */
+ if (config->height % config->dmaBufferLine != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ (void)memset(handle, 0, sizeof(*handle));
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->height = config->height;
+ handle->width = config->width;
+ handle->maxLinePerFrag = config->dmaBufferLine;
+ handle->dmaBytePerLine = config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+ handle->isDmaBufferCachable = config->isDmaBufferCachable;
+
+ /* Get instance from peripheral base address. */
+ instance = CSI_GetInstance(base);
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_csiHandle[instance] = handle;
+
+ s_csiIsr = CSI_FragModeTransferHandleIRQ;
+
+ (void)EnableIRQ(s_csiIRQ[instance]);
+
+ /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
+ reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CR1_FCC_MASK;
+
+ if (config->useExtVsync)
+ {
+ reg |= CSI_CR1_EXT_VSYNC_MASK;
+ }
+
+ CSI_REG_CR1(base) = reg;
+
+ /* No stride. */
+ CSI_REG_FBUF_PARA(base) = 0;
+
+ /* Enable auto ECC. */
+ CSI_REG_CR3(base) |= CSI_CR3_ECC_AUTO_EN_MASK;
+
+ /*
+ * For better performance.
+ * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
+ * choose the best burst size based on bytes per line.
+ */
+ if (0U == (imgWidth_Bytes % (8U * 16U)))
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(3U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((2U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+ else if (0U == (imgWidth_Bytes % (8U * 8U)))
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(2U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((1U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+ else
+ {
+ CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(1U);
+ CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((0U << CSI_CR3_RxFF_LEVEL_SHIFT));
+ }
+
+ CSI_REG_DMASA_FB1(base) = CSI_ADDR_CPU_2_IP(config->dmaBufferAddr0);
+ CSI_REG_DMASA_FB2(base) = CSI_ADDR_CPU_2_IP(config->dmaBufferAddr1);
+
+ if (handle->isDmaBufferCachable)
+ {
+ DCACHE_CleanInvalidateByRange(
+ config->dmaBufferAddr0,
+ (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+ DCACHE_CleanInvalidateByRange(
+ config->dmaBufferAddr1,
+ (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Start to capture a image.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ * param config Pointer to the capture configuration.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeTransferCaptureImage(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_capture_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t windowWidth;
+
+ /*
+ * If no special window setting, capture full frame.
+ * If capture window, then capture 1 one each fragment.
+ */
+ if (config->window != NULL)
+ {
+ handle->windowULX = config->window->windowULX;
+ handle->windowULY = config->window->windowULY;
+ handle->windowLRX = config->window->windowLRX;
+ handle->windowLRY = config->window->windowLRY;
+ handle->linePerFrag = 1;
+ }
+ else
+ {
+ handle->windowULX = 0;
+ handle->windowULY = 0;
+ handle->windowLRX = handle->width - 1U;
+ handle->windowLRY = handle->height - 1U;
+ handle->linePerFrag = handle->maxLinePerFrag;
+ }
+
+ windowWidth = handle->windowLRX - handle->windowULX + 1U;
+
+ if (config->outputGrayScale)
+ {
+ /* When output format is gray, the window width must be multiple value of 8. */
+ if (windowWidth % 8U != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ handle->datBytePerLine = windowWidth;
+ if (handle->inputFormat == kCSI_FragInputYUYV)
+ {
+ handle->copyFunc = CSI_ExtractYFromYUYV;
+ }
+ else
+ {
+ handle->copyFunc = CSI_ExtractYFromUYVY;
+ }
+ }
+ else
+ {
+ handle->datBytePerLine = windowWidth * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+ handle->copyFunc = CSI_MemCopy;
+ }
+
+ handle->dmaCurLine = 0;
+ handle->outputBuffer = (uint32_t)config->buffer;
+ handle->datCurWriteAddr = (uint32_t)config->buffer;
+
+ /* Image parameter. */
+ CSI_REG_IMAG_PARA(base) =
+ (((uint32_t)handle->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL) << CSI_IMAG_PARA_IMAGE_WIDTH_SHIFT) |
+ ((uint32_t)(handle->linePerFrag) << CSI_IMAG_PARA_IMAGE_HEIGHT_SHIFT);
+
+ /*
+ * Write to memory from first completed frame.
+ * DMA base addr switch at dma transfer done.
+ */
+ CSI_REG_CR18(base) = (CSI_REG_CR18(base) & ~CSI_CR18_MASK_OPTION_MASK) | CSI_CR18_MASK_OPTION(0);
+
+ CSI_EnableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Abort image capture.
+ *
+ * Abort image capture initialized by ref CSI_FragModeTransferCaptureImage.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ */
+void CSI_FragModeTransferAbortCaptureImage(CSI_Type *base, csi_frag_handle_t *handle)
+{
+ CSI_Stop(base);
+ CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+}
+
+/*!
+ * brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver fragment mode
+ * APIs.
+ *
+ * param base CSI peripheral base address.
+ * param handle CSI handle pointer.
+ */
+void CSI_FragModeTransferHandleIRQ(CSI_Type *base, csi_frag_handle_t *handle)
+{
+ uint32_t csisr = CSI_REG_SR(base);
+ uint32_t dmaBufAddr;
+ uint16_t line;
+ pvoid_to_u32_t memSrc;
+ pvoid_to_u32_t memDest;
+
+ /* Clear the error flags. */
+ CSI_REG_SR(base) = csisr;
+
+ /* Start of frame, clear the FIFO and start receiving. */
+ if (0U != (csisr & (uint32_t)kCSI_StartOfFrameFlag))
+ {
+ /* Reflash the DMA and enable RX DMA request. */
+ CSI_REG_CR3(base) |= (CSI_CR3_DMA_REFLASH_RFF_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
+ CSI_Start(base);
+ handle->dmaCurLine = 0;
+ handle->datCurWriteAddr = handle->outputBuffer;
+ }
+ else if ((csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)) != 0U)
+ {
+ if ((csisr & CSI_SR_DMA_TSF_DONE_FB1_MASK) == CSI_SR_DMA_TSF_DONE_FB1_MASK)
+ {
+ dmaBufAddr = CSI_REG_DMASA_FB1(base);
+ }
+ else
+ {
+ dmaBufAddr = CSI_REG_DMASA_FB2(base);
+ }
+
+ dmaBufAddr = CSI_ADDR_IP_2_CPU(dmaBufAddr);
+
+ if (handle->isDmaBufferCachable)
+ {
+ DCACHE_InvalidateByRange(dmaBufAddr, (uint32_t)handle->dmaBytePerLine * (uint32_t)handle->linePerFrag);
+ }
+
+ /* Copy from DMA buffer to user data buffer. */
+ dmaBufAddr += ((uint32_t)handle->windowULX * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+
+ for (line = 0; line < handle->linePerFrag; line++)
+ {
+ if (handle->dmaCurLine + line > handle->windowLRY)
+ {
+ /* out of window range */
+ break;
+ }
+ else if (handle->dmaCurLine + line >= handle->windowULY)
+ {
+ memDest.u32 = handle->datCurWriteAddr;
+ memSrc.u32 = dmaBufAddr;
+
+ handle->copyFunc(memDest.pvoid, memSrc.pvoid, handle->datBytePerLine);
+ handle->datCurWriteAddr += handle->datBytePerLine;
+ dmaBufAddr += handle->dmaBytePerLine;
+ }
+ else
+ {
+ ; /* For MISRA C-2012 Rule 15.7 */
+ }
+ }
+
+ handle->dmaCurLine += handle->linePerFrag;
+
+ if (handle->dmaCurLine >= handle->height)
+ {
+ CSI_Stop(base);
+ CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ /* Image captured. Stop the CSI. */
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
+ }
+ }
+ }
+ else
+ {
+ }
+}
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+#if defined(CSI)
+void CSI_DriverIRQHandler(void);
+void CSI_DriverIRQHandler(void)
+{
+ s_csiIsr(CSI, s_csiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CSI0)
+void CSI0_DriverIRQHandler(void);
+void CSI0_DriverIRQHandler(void)
+{
+ s_csiIsr(CSI, s_csiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.h b/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.h
new file mode 100644
index 0000000000..dd6f5c08d8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/csi/fsl_csi.h
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2017-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_CSI_H_
+#define _FSL_CSI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup csi_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_CSI_DRIVER_VERSION (MAKE_VERSION(2, 1, 5))
+/*@}*/
+
+#define CSI_REG_CR1(base) (base)->CR1
+#define CSI_REG_CR2(base) (base)->CR2
+#define CSI_REG_CR3(base) (base)->CR3
+#define CSI_REG_CR18(base) (base)->CR18
+#define CSI_REG_SR(base) (base)->SR
+#define CSI_REG_DMASA_FB1(base) (base)->DMASA_FB1
+#define CSI_REG_DMASA_FB2(base) (base)->DMASA_FB2
+#define CSI_REG_IMAG_PARA(base) (base)->IMAG_PARA
+#define CSI_REG_FBUF_PARA(base) (base)->FBUF_PARA
+
+/*! @brief Size of the frame buffer queue used in CSI transactional function. */
+#ifndef CSI_DRIVER_QUEUE_SIZE
+#define CSI_DRIVER_QUEUE_SIZE 4U
+#endif
+
+/*! @brief Enable fragment capture function or not. */
+#ifndef CSI_DRIVER_FRAG_MODE
+#define CSI_DRIVER_FRAG_MODE 0U
+#endif
+
+/*
+ * There is one empty room in queue, used to distinguish whether the queue
+ * is full or empty. When header equals tail, the queue is empty; when header
+ * equals tail + 1, the queue is full.
+ */
+#define CSI_DRIVER_ACTUAL_QUEUE_SIZE (CSI_DRIVER_QUEUE_SIZE + 1U)
+
+/*
+ * The queue max size is 254, so that the queue element index could use `uint8_t`.
+ */
+#if (CSI_DRIVER_ACTUAL_QUEUE_SIZE > 254)
+#error Required queue size is too large
+#endif
+
+/*
+ * The interrupt enable bits are in registers CSICR1[16:31], CSICR3[0:7],
+ * and CSICR18[2:9]. So merge them into an uint32_t value, place CSICR18 control
+ * bits to [8:15].
+ */
+#define CSI_CR1_INT_EN_MASK 0xFFFF0000U
+#define CSI_CR3_INT_EN_MASK 0x000000FFU
+#define CSI_CR18_INT_EN_MASK 0x0000FF00U
+
+#if ((~CSI_CR1_INT_EN_MASK) & \
+ (CSI_CR1_EOF_INT_EN_MASK | CSI_CR1_COF_INT_EN_MASK | CSI_CR1_SF_OR_INTEN_MASK | CSI_CR1_RF_OR_INTEN_MASK | \
+ CSI_CR1_SFF_DMA_DONE_INTEN_MASK | CSI_CR1_STATFF_INTEN_MASK | CSI_CR1_FB2_DMA_DONE_INTEN_MASK | \
+ CSI_CR1_FB1_DMA_DONE_INTEN_MASK | CSI_CR1_RXFF_INTEN_MASK | CSI_CR1_SOF_INTEN_MASK))
+#error CSI_CR1_INT_EN_MASK could not cover all interrupt bits in CSICR1.
+#endif
+
+#if ((~CSI_CR3_INT_EN_MASK) & (CSI_CR3_ECC_INT_EN_MASK | CSI_CR3_HRESP_ERR_EN_MASK))
+#error CSI_CR3_INT_EN_MASK could not cover all interrupt bits in CSICR3.
+#endif
+
+#if ((~CSI_CR18_INT_EN_MASK) & \
+ ((CSI_CR18_FIELD0_DONE_IE_MASK | CSI_CR18_DMA_FIELD1_DONE_IE_MASK | CSI_CR18_BASEADDR_CHANGE_ERROR_IE_MASK) \
+ << 6U))
+#error CSI_CR18_INT_EN_MASK could not cover all interrupt bits in CSICR18.
+#endif
+
+/*! @brief Error codes for the CSI driver. */
+enum
+{
+ kStatus_CSI_NoEmptyBuffer = MAKE_STATUS(kStatusGroup_CSI, 0), /*!< No empty frame buffer in queue to load to CSI. */
+ kStatus_CSI_NoFullBuffer = MAKE_STATUS(kStatusGroup_CSI, 1), /*!< No full frame buffer in queue to read out. */
+ kStatus_CSI_QueueFull = MAKE_STATUS(kStatusGroup_CSI, 2), /*!< Queue is full, no room to save new empty buffer. */
+ kStatus_CSI_FrameDone = MAKE_STATUS(kStatusGroup_CSI, 3), /*!< New frame received and saved to queue. */
+};
+
+/*!
+ * @brief CSI work mode.
+ *
+ * The CCIR656 interlace mode is not supported currently.
+ */
+typedef enum _csi_work_mode
+{
+ kCSI_GatedClockMode = CSI_CR1_GCLK_MODE(1U), /*!< HSYNC, VSYNC, and PIXCLK signals are used. */
+ kCSI_NonGatedClockMode = 0U, /*!< VSYNC, and PIXCLK signals are used. */
+ kCSI_CCIR656ProgressiveMode = CSI_CR1_CCIR_EN(1U), /*!< CCIR656 progressive mode. */
+} csi_work_mode_t;
+
+/*!
+ * @brief CSI data bus witdh.
+ */
+typedef enum _csi_data_bus
+{
+ kCSI_DataBus8Bit, /*!< 8-bit data bus. */
+ kCSI_DataBus16Bit, /*!< 16-bit data bus. */
+ kCSI_DataBus24Bit, /*!< 24-bit data bus. */
+} csi_data_bus_t;
+
+/*! @brief CSI signal polarity. */
+enum _csi_polarity_flags
+{
+ kCSI_HsyncActiveLow = 0U, /*!< HSYNC is active low. */
+ kCSI_HsyncActiveHigh = CSI_CR1_HSYNC_POL_MASK, /*!< HSYNC is active high. */
+ kCSI_DataLatchOnRisingEdge = CSI_CR1_REDGE_MASK, /*!< Pixel data latched at rising edge of pixel clock. */
+ kCSI_DataLatchOnFallingEdge = 0U, /*!< Pixel data latched at falling edge of pixel clock. */
+ kCSI_VsyncActiveHigh = 0U, /*!< VSYNC is active high. */
+ kCSI_VsyncActiveLow = CSI_CR1_SOF_POL_MASK, /*!< VSYNC is active low. */
+};
+
+/*! @brief Configuration to initialize the CSI module. */
+typedef struct _csi_config
+{
+ uint16_t width; /*!< Pixels of the input frame. */
+ uint16_t height; /*!< Lines of the input frame. */
+ uint32_t polarityFlags; /*!< Timing signal polarity flags, OR'ed value of @ref _csi_polarity_flags. */
+ uint8_t bytesPerPixel; /*!< Bytes per pixel, valid values are:
+ - 2: Used for RGB565, YUV422, and so on.
+ - 4: Used for XRGB8888, XYUV444, and so on.
+ */
+ uint16_t linePitch_Bytes; /*!< Frame buffer line pitch, must be 8-byte aligned. */
+ csi_work_mode_t workMode; /*!< CSI work mode. */
+ csi_data_bus_t dataBus; /*!< Data bus width. */
+ bool useExtVsync; /*!< In CCIR656 progressive mode, set true to use external VSYNC signal, set false
+ to use internal VSYNC signal decoded from SOF. */
+} csi_config_t;
+
+/*! @brief The CSI FIFO, used for FIFO operation. */
+typedef enum _csi_fifo
+{
+ kCSI_RxFifo = (1U << 0U), /*!< RXFIFO. */
+ kCSI_StatFifo = (1U << 1U), /*!< STAT FIFO. */
+ kCSI_AllFifo = 0x01 | 0x02, /*!< Both RXFIFO and STAT FIFO. */
+} csi_fifo_t;
+
+/*! @brief CSI feature interrupt source. */
+enum _csi_interrupt_enable
+{
+ kCSI_EndOfFrameInterruptEnable = CSI_CR1_EOF_INT_EN_MASK, /*!< End of frame interrupt enable. */
+ kCSI_ChangeOfFieldInterruptEnable = CSI_CR1_COF_INT_EN_MASK, /*!< Change of field interrupt enable. */
+ kCSI_StatFifoOverrunInterruptEnable = CSI_CR1_SF_OR_INTEN_MASK, /*!< STAT FIFO overrun interrupt enable. */
+ kCSI_RxFifoOverrunInterruptEnable = CSI_CR1_RF_OR_INTEN_MASK, /*!< RXFIFO overrun interrupt enable. */
+ kCSI_StatFifoDmaDoneInterruptEnable = CSI_CR1_SFF_DMA_DONE_INTEN_MASK, /*!< STAT FIFO DMA done interrupt enable. */
+ kCSI_StatFifoFullInterruptEnable = CSI_CR1_STATFF_INTEN_MASK, /*!< STAT FIFO full interrupt enable. */
+ kCSI_RxBuffer1DmaDoneInterruptEnable = CSI_CR1_FB2_DMA_DONE_INTEN_MASK, /*!< RX frame buffer 1 DMA transfer done. */
+ kCSI_RxBuffer0DmaDoneInterruptEnable = CSI_CR1_FB1_DMA_DONE_INTEN_MASK, /*!< RX frame buffer 0 DMA transfer done. */
+ kCSI_RxFifoFullInterruptEnable = CSI_CR1_RXFF_INTEN_MASK, /*!< RXFIFO full interrupt enable. */
+ kCSI_StartOfFrameInterruptEnable = CSI_CR1_SOF_INTEN_MASK, /*!< Start of frame (SOF) interrupt enable. */
+
+ kCSI_EccErrorInterruptEnable = CSI_CR3_ECC_INT_EN_MASK, /*!< ECC error detection interrupt enable. */
+ kCSI_AhbResErrorInterruptEnable = CSI_CR3_HRESP_ERR_EN_MASK, /*!< AHB response Error interrupt enable. */
+
+ /*! The DMA output buffer base address changes before DMA completed. */
+ kCSI_BaseAddrChangeErrorInterruptEnable = CSI_CR18_BASEADDR_CHANGE_ERROR_IE_MASK << 6U,
+
+ kCSI_Field0DoneInterruptEnable = CSI_CR18_FIELD0_DONE_IE_MASK << 6U, /*!< Field 0 done interrupt enable. */
+ kCSI_Field1DoneInterruptEnable = CSI_CR18_DMA_FIELD1_DONE_IE_MASK << 6U, /*!< Field 1 done interrupt enable. */
+};
+
+/*!
+ * @brief CSI status flags.
+ *
+ * The following status register flags can be cleared:
+ * - kCSI_EccErrorFlag
+ * - kCSI_AhbResErrorFlag
+ * - kCSI_ChangeOfFieldFlag
+ * - kCSI_StartOfFrameFlag
+ * - kCSI_EndOfFrameFlag
+ * - kCSI_RxBuffer1DmaDoneFlag
+ * - kCSI_RxBuffer0DmaDoneFlag
+ * - kCSI_StatFifoDmaDoneFlag
+ * - kCSI_StatFifoOverrunFlag
+ * - kCSI_RxFifoOverrunFlag
+ * - kCSI_Field0DoneFlag
+ * - kCSI_Field1DoneFlag
+ * - kCSI_BaseAddrChangeErrorFlag
+ */
+enum _csi_flags
+{
+ kCSI_RxFifoDataReadyFlag = CSI_SR_DRDY_MASK, /*!< RXFIFO data ready. */
+ kCSI_EccErrorFlag = CSI_SR_ECC_INT_MASK, /*!< ECC error detected. */
+ kCSI_AhbResErrorFlag = CSI_SR_HRESP_ERR_INT_MASK, /*!< Hresponse (AHB bus response) Error. */
+ kCSI_ChangeOfFieldFlag = CSI_SR_COF_INT_MASK, /*!< Change of field. */
+ kCSI_Field0PresentFlag = CSI_SR_F1_INT_MASK, /*!< Field 0 present in CCIR mode. */
+ kCSI_Field1PresentFlag = CSI_SR_F2_INT_MASK, /*!< Field 1 present in CCIR mode. */
+ kCSI_StartOfFrameFlag = CSI_SR_SOF_INT_MASK, /*!< Start of frame (SOF) detected. */
+ kCSI_EndOfFrameFlag = CSI_SR_EOF_INT_MASK, /*!< End of frame (EOF) detected. */
+ kCSI_RxFifoFullFlag = CSI_SR_RxFF_INT_MASK, /*!< RXFIFO full (Number of data reaches trigger level). */
+ kCSI_RxBuffer1DmaDoneFlag = CSI_SR_DMA_TSF_DONE_FB2_MASK, /*!< RX frame buffer 1 DMA transfer done. */
+ kCSI_RxBuffer0DmaDoneFlag = CSI_SR_DMA_TSF_DONE_FB1_MASK, /*!< RX frame buffer 0 DMA transfer done. */
+ kCSI_StatFifoFullFlag = CSI_SR_STATFF_INT_MASK, /*!< STAT FIFO full (Reach trigger level). */
+ kCSI_StatFifoDmaDoneFlag = CSI_SR_DMA_TSF_DONE_SFF_MASK, /*!< STAT FIFO DMA transfer done. */
+ kCSI_StatFifoOverrunFlag = CSI_SR_SF_OR_INT_MASK, /*!< STAT FIFO overrun. */
+ kCSI_RxFifoOverrunFlag = CSI_SR_RF_OR_INT_MASK, /*!< RXFIFO overrun. */
+ kCSI_Field0DoneFlag = CSI_SR_DMA_FIELD0_DONE_MASK, /*!< Field 0 transfer done. */
+ kCSI_Field1DoneFlag = CSI_SR_DMA_FIELD1_DONE_MASK, /*!< Field 1 transfer done. */
+ kCSI_BaseAddrChangeErrorFlag = CSI_SR_BASEADDR_CHHANGE_ERROR_MASK, /*!< The DMA output buffer base address
+ changes before DMA completed. */
+};
+
+/* Forward declaration of the handle typedef. */
+typedef struct _csi_handle csi_handle_t;
+
+/*!
+ * @brief CSI transfer callback function.
+ *
+ * When a new frame is received and saved to the frame buffer queue, the callback
+ * is called and the pass the status @ref kStatus_CSI_FrameDone to upper layer.
+ */
+typedef void (*csi_transfer_callback_t)(CSI_Type *base, csi_handle_t *handle, status_t status, void *userData);
+
+/*!
+ * @brief CSI handle structure.
+ *
+ * Please see the user guide for the details of the CSI driver queue mechanism.
+ */
+struct _csi_handle
+{
+ uint32_t frameBufferQueue[CSI_DRIVER_ACTUAL_QUEUE_SIZE]; /*!< Frame buffer queue. */
+
+ volatile uint8_t queueWriteIdx; /*!< Pointer to save incoming item. */
+ volatile uint8_t queueReadIdx; /*!< Pointer to read out the item. */
+ void *volatile emptyBuffer; /*!< Pointer to maintain the empty frame buffers. */
+ volatile uint8_t emptyBufferCnt; /*!< Empty frame buffers count. */
+
+ volatile uint8_t activeBufferNum; /*!< How many frame buffers are in progres currently. */
+
+ volatile bool transferStarted; /*!< User has called @ref CSI_TransferStart to start frame receiving. */
+
+ csi_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< CSI callback function parameter.*/
+};
+
+#if CSI_DRIVER_FRAG_MODE
+
+/*! @brief Input pixel format when CSI works in fragment mode. */
+typedef enum _csi_frag_input_pixel_format
+{
+ kCSI_FragInputRGB565 = 0, /*!< Input pixel format is RGB565. */
+ kCSI_FragInputYUYV, /*!< Input pixel format is YUV422 (Y-U-Y-V). */
+ kCSI_FragInputUYVY, /*!< Input pixel format is YUV422 (U-Y-V-Y). */
+} csi_frag_input_pixel_format_t;
+
+/*! @brief Configuration for CSI module to work in fragment mode. */
+typedef struct _csi_frag_config
+{
+ uint16_t width; /*!< Pixels of the input frame. */
+ uint16_t height; /*!< Lines of the input frame. */
+ uint32_t polarityFlags; /*!< Timing signal polarity flags, OR'ed value of @ref _csi_polarity_flags. */
+ csi_work_mode_t workMode; /*!< CSI work mode. */
+ csi_data_bus_t dataBus; /*!< Data bus width. */
+ bool useExtVsync; /*!< In CCIR656 progressive mode, set true to use external VSYNC signal, set false
+ to use internal VSYNC signal decoded from SOF. */
+ csi_frag_input_pixel_format_t inputFormat; /*!< Input pixel format. */
+
+ uint32_t dmaBufferAddr0; /*!< Buffer 0 used for CSI DMA, must be double word aligned. */
+ uint32_t dmaBufferAddr1; /*!< Buffer 1 used for CSI DMA, must be double word aligned. */
+ uint16_t dmaBufferLine; /*!< Lines of each DMA buffer. The size of DMA buffer 0 and
+ buffer 1 must be the same. Camera frame height must be
+ dividable by this value. */
+ bool isDmaBufferCachable; /*!< Is DMA buffer cachable or not. */
+} csi_frag_config_t;
+
+/* Forward declaration of the handle typedef. */
+typedef struct _csi_frag_handle csi_frag_handle_t;
+
+/*!
+ * @brief CSI fragment transfer callback function.
+ *
+ * When a new frame is received and saved to the frame buffer queue, the callback
+ * is called and the pass the status @ref kStatus_CSI_FrameDone to upper layer.
+ */
+typedef void (*csi_frag_transfer_callback_t)(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief Function to copy data from CSI DMA buffer to user buffer.
+ */
+typedef void (*csi_frag_copy_func_t)(void *pDest, const void *pSrc, size_t cnt);
+
+/*! @brief Handle for CSI module to work in fragment mode. */
+struct _csi_frag_handle
+{
+ uint16_t width; /*!< Pixels of the input frame. */
+ uint16_t height; /*!< Lines of the input frame. */
+ uint16_t maxLinePerFrag; /*!< Max line saved per fragment. */
+ uint16_t linePerFrag; /*!< Actual line saved per fragment. */
+ uint16_t dmaBytePerLine; /*!< How many bytes DMA transfered each line. */
+ uint16_t datBytePerLine; /*!< How many bytes copied to user buffer each line. */
+ uint16_t dmaCurLine; /*!< Current line index in whole frame. */
+ uint16_t windowULX; /*!< X of windows upper left corner. */
+ uint16_t windowULY; /*!< Y of windows upper left corner. */
+ uint16_t windowLRX; /*!< X of windows lower right corner. */
+ uint16_t windowLRY; /*!< Y of windows lower right corner. */
+ uint32_t outputBuffer; /*!< Address of buffer to save the captured image. */
+ uint32_t datCurWriteAddr; /*!< Current write address to the user buffer. */
+ csi_frag_input_pixel_format_t inputFormat; /*!< Input pixel format. */
+
+ csi_frag_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< CSI callback function parameter.*/
+ csi_frag_copy_func_t copyFunc; /*!< Function to copy data from CSI DMA buffer to user buffer. */
+ bool isDmaBufferCachable; /*!< Is DMA buffer cachable or not. */
+};
+
+/*! @brief Handle for CSI module to work in fragment mode. */
+typedef struct _csi_frag_window
+{
+ uint16_t windowULX; /*!< X of windows upper left corner. */
+ uint16_t windowULY; /*!< Y of windows upper left corner. */
+ uint16_t windowLRX; /*!< X of windows lower right corner. */
+ uint16_t windowLRY; /*!< Y of windows lower right corner. */
+} csi_frag_window_t;
+
+/*! @brief Handle for CSI module to work in fragment mode. */
+typedef struct _csi_frag_capture_config
+{
+ bool outputGrayScale; /*!< Output gray scale image or not, could only enable when input format is YUV. */
+ uint32_t buffer; /*!< Buffer to save the captured image. */
+ csi_frag_window_t *window; /*!< Capture window. Capture full frame if set this to NULL. When output format is gray,
+ the window width must be multiple value of 8. */
+} csi_frag_capture_config_t;
+
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize the CSI.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * @param base CSI peripheral base address.
+ * @param config Pointer to the configuration structure.
+ *
+ * @retval kStatus_Success Initialize successfully.
+ * @retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_Init(CSI_Type *base, const csi_config_t *config);
+
+/*!
+ * @brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * @param base CSI peripheral base address.
+ */
+void CSI_Deinit(CSI_Type *base);
+
+/*!
+ * @brief Reset the CSI.
+ *
+ * This function resets the CSI peripheral registers to default status.
+ *
+ * @param base CSI peripheral base address.
+ */
+void CSI_Reset(CSI_Type *base);
+
+/*!
+ * @brief Get the default configuration for to initialize the CSI.
+ *
+ * The default configuration value is:
+ *
+ * @code
+ config->width = 320U;
+ config->height = 240U;
+ config->polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge;
+ config->bytesPerPixel = 2U;
+ config->linePitch_Bytes = 320U * 2U;
+ config->workMode = kCSI_GatedClockMode;
+ config->dataBus = kCSI_DataBus8Bit;
+ config->useExtVsync = true;
+ @endcode
+ *
+ * @param config Pointer to the CSI configuration.
+ */
+void CSI_GetDefaultConfig(csi_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Module operation
+ * @{
+ */
+
+/*!
+ * @brief Clear the CSI FIFO.
+ *
+ * This function clears the CSI FIFO.
+ *
+ * @param base CSI peripheral base address.
+ * @param fifo The FIFO to clear.
+ */
+void CSI_ClearFifo(CSI_Type *base, csi_fifo_t fifo);
+
+/*!
+ * @brief Reflash the CSI FIFO DMA.
+ *
+ * This function reflashes the CSI FIFO DMA.
+ *
+ * For RXFIFO, there are two frame buffers. When the CSI module started, it saves
+ * the frames to frame buffer 0 then frame buffer 1, the two buffers will be
+ * written by turns. After reflash DMA using this function, the CSI is reset to
+ * save frame to buffer 0.
+ *
+ * @param base CSI peripheral base address.
+ * @param fifo The FIFO DMA to reflash.
+ */
+void CSI_ReflashFifoDma(CSI_Type *base, csi_fifo_t fifo);
+
+/*!
+ * @brief Enable or disable the CSI FIFO DMA request.
+ *
+ * @param base CSI peripheral base address.
+ * @param fifo The FIFO DMA reques to enable or disable.
+ * @param enable True to enable, false to disable.
+ */
+void CSI_EnableFifoDmaRequest(CSI_Type *base, csi_fifo_t fifo, bool enable);
+
+/*!
+ * @brief Start to receive data.
+ *
+ * @param base CSI peripheral base address.
+ */
+static inline void CSI_Start(CSI_Type *base)
+{
+ CSI_EnableFifoDmaRequest(base, kCSI_RxFifo, true);
+ CSI_REG_CR18(base) |= CSI_CR18_CSI_ENABLE_MASK;
+}
+
+/*!
+ * @brief Stop to receiving data.
+ *
+ * @param base CSI peripheral base address.
+ */
+static inline void CSI_Stop(CSI_Type *base)
+{
+ CSI_REG_CR18(base) &= ~CSI_CR18_CSI_ENABLE_MASK;
+ CSI_EnableFifoDmaRequest(base, kCSI_RxFifo, false);
+}
+
+/*!
+ * @brief Set the RX frame buffer address.
+ *
+ * @param base CSI peripheral base address.
+ * @param index Buffer index.
+ * @param addr Frame buffer address to set.
+ */
+void CSI_SetRxBufferAddr(CSI_Type *base, uint8_t index, uint32_t addr);
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables CSI interrupt requests.
+ *
+ * @param base CSI peripheral base address.
+ * @param mask The interrupts to enable, pass in as OR'ed value of @ref _csi_interrupt_enable.
+ */
+void CSI_EnableInterrupts(CSI_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disable CSI interrupt requests.
+ *
+ * @param base CSI peripheral base address.
+ * @param mask The interrupts to disable, pass in as OR'ed value of @ref _csi_interrupt_enable.
+ */
+void CSI_DisableInterrupts(CSI_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the CSI status flags.
+ *
+ * @param base CSI peripheral base address.
+ * @return status flag, it is OR'ed value of @ref _csi_flags.
+ */
+static inline uint32_t CSI_GetStatusFlags(CSI_Type *base)
+{
+ return CSI_REG_SR(base);
+}
+
+/*!
+ * @brief Clears the CSI status flag.
+ *
+ * The flags to clear are passed in as OR'ed value of @ref _csi_flags. The following
+ * flags are cleared automatically by hardware:
+ *
+ * - @ref kCSI_RxFifoFullFlag,
+ * - @ref kCSI_StatFifoFullFlag,
+ * - @ref kCSI_Field0PresentFlag,
+ * - @ref kCSI_Field1PresentFlag,
+ * - @ref kCSI_RxFifoDataReadyFlag,
+ *
+ * @param base CSI peripheral base address.
+ * @param statusMask The status flags mask, OR'ed value of @ref _csi_flags.
+ */
+static inline void CSI_ClearStatusFlags(CSI_Type *base, uint32_t statusMask)
+{
+ CSI_REG_SR(base) = statusMask;
+}
+/* @} */
+
+#if !CSI_DRIVER_FRAG_MODE
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the CSI handle.
+ *
+ * This function initializes CSI handle, it should be called before any other
+ * CSI transactional functions.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the handle structure.
+ * @param callback Callback function for CSI transfer.
+ * @param userData Callback function parameter.
+ *
+ * @retval kStatus_Success Handle created successfully.
+ */
+status_t CSI_TransferCreateHandle(CSI_Type *base,
+ csi_handle_t *handle,
+ csi_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Start the transfer using transactional functions.
+ *
+ * When the empty frame buffers have been submit to CSI driver using function
+ * @ref CSI_TransferSubmitEmptyBuffer, user could call this function to start
+ * the transfer. The incoming frame will be saved to the empty frame buffer,
+ * and user could be optionally notified through callback function.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the handle structure.
+ *
+ * @retval kStatus_Success Started successfully.
+ * @retval kStatus_CSI_NoEmptyBuffer Could not start because no empty frame buffer in queue.
+ */
+status_t CSI_TransferStart(CSI_Type *base, csi_handle_t *handle);
+
+/*!
+ * @brief Stop the transfer using transactional functions.
+ *
+ * The driver does not clean the full frame buffers in queue. In other words, after
+ * calling this function, user still could get the full frame buffers in queue
+ * using function @ref CSI_TransferGetFullBuffer.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the handle structure.
+ *
+ * @retval kStatus_Success Stoped successfully.
+ */
+status_t CSI_TransferStop(CSI_Type *base, csi_handle_t *handle);
+
+/*!
+ * @brief Submit empty frame buffer to queue.
+ *
+ * This function could be called before @ref CSI_TransferStart or after @ref
+ * CSI_TransferStart. If there is no room in queue to store the empty frame
+ * buffer, this function returns error.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the handle structure.
+ * @param frameBuffer Empty frame buffer to submit.
+ *
+ * @retval kStatus_Success Started successfully.
+ * @retval kStatus_CSI_QueueFull Could not submit because there is no room in queue.
+ */
+status_t CSI_TransferSubmitEmptyBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t frameBuffer);
+
+/*!
+ * @brief Get one full frame buffer from queue.
+ *
+ * After the transfer started using function @ref CSI_TransferStart, the incoming
+ * frames will be saved to the empty frame buffers in queue. This function gets
+ * the full-filled frame buffer from the queue. If there is no full frame buffer
+ * in queue, this function returns error.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the handle structure.
+ * @param frameBuffer Full frame buffer.
+ *
+ * @retval kStatus_Success Started successfully.
+ * @retval kStatus_CSI_NoFullBuffer There is no full frame buffer in queue.
+ */
+status_t CSI_TransferGetFullBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t *frameBuffer);
+
+/*!
+ * @brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver transactional
+ * APIs.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle CSI handle pointer.
+ */
+void CSI_TransferHandleIRQ(CSI_Type *base, csi_handle_t *handle);
+/* @} */
+
+#else
+
+/*!
+ * @name Fragment mode
+ * @{
+ */
+
+/*!
+ * @brief Initialize the CSI to work in fragment mode.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * @param base CSI peripheral base address.
+ */
+void CSI_FragModeInit(CSI_Type *base);
+
+/*!
+ * @brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * @param base CSI peripheral base address.
+ */
+void CSI_FragModeDeinit(CSI_Type *base);
+
+/*!
+ * @brief Create handle for CSI work in fragment mode.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the transactional handle.
+ * @param config Pointer to the configuration structure.
+ * @param callback Callback function for CSI transfer.
+ * @param userData Callback function parameter.
+ *
+ * @retval kStatus_Success Initialize successfully.
+ * @retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeCreateHandle(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_config_t *config,
+ csi_frag_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Start to capture a image.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the transactional handle.
+ * @param config Pointer to the capture configuration.
+ *
+ * @retval kStatus_Success Initialize successfully.
+ * @retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeTransferCaptureImage(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_capture_config_t *config);
+
+/*!
+ * @brief Abort image capture.
+ *
+ * Abort image capture initialized by @ref CSI_FragModeTransferCaptureImage.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle Pointer to the transactional handle.
+ */
+void CSI_FragModeTransferAbortCaptureImage(CSI_Type *base, csi_frag_handle_t *handle);
+
+/*!
+ * @brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver fragment mode
+ * APIs.
+ *
+ * @param base CSI peripheral base address.
+ * @param handle CSI handle pointer.
+ */
+void CSI_FragModeTransferHandleIRQ(CSI_Type *base, csi_frag_handle_t *handle);
+
+/* @} */
+
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_CSI_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.c b/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.c
new file mode 100644
index 0000000000..1381faa047
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dac12.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dac12"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for DAC12 module.
+ *
+ * @param base DAC12 peripheral base address
+ */
+static uint32_t DAC12_GetInstance(DAC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to DAC bases for each instance. */
+static DAC_Type *const s_dac12Bases[] = DAC_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to DAC clocks for each instance. */
+static const clock_ip_name_t s_dac12Clocks[] = DAC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t DAC12_GetInstance(DAC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dac12Bases); instance++)
+ {
+ if (s_dac12Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dac12Bases));
+
+ return instance;
+}
+
+/*!
+ * brief Get hardware information about this module.
+ *
+ * param base DAC12 peripheral base address.
+ * param info Pointer to info structure, see to #dac12_hardware_info_t.
+ */
+void DAC12_GetHardwareInfo(DAC_Type *base, dac12_hardware_info_t *info)
+{
+ assert(NULL != info);
+
+ info->fifoSizeInfo =
+ (dac12_fifo_size_info_t)(uint32_t)((DAC_PARAM_FIFOSZ_MASK & base->PARAM) >> DAC_PARAM_FIFOSZ_SHIFT);
+}
+
+/*!
+ * brief Initialize the DAC12 module.
+ *
+ * param base DAC12 peripheral base address.
+ * param config Pointer to configuration structure, see to #dac12_config_t.
+ */
+void DAC12_Init(DAC_Type *base, const dac12_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_dac12Clocks[DAC12_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ tmp32 = DAC_CR_WML(config->fifoWatermarkLevel); /* FIFO watermark level. */
+ switch (config->fifoWorkMode) /* FIFO work mode. */
+ {
+ case kDAC12_FIFOWorkAsNormalMode:
+ tmp32 |= DAC_CR_FIFOEN_MASK;
+ break;
+ case kDAC12_FIFOWorkAsSwingMode:
+ tmp32 |= DAC_CR_FIFOEN_MASK | DAC_CR_SWMD_MASK;
+ break;
+ default: /* kDAC12_FIFODisabled. */
+ break;
+ }
+
+ tmp32 |= DAC_CR_DACRFS(config->referenceVoltageSource) /* Reference voltage source. */
+ | DAC_CR_TRGSEL(config->fifoTriggerMode); /* Trigger mode. */
+
+ base->CR = tmp32;
+
+ /* DACx_CR2. */
+ tmp32 = 0U;
+ /* Reference voltage current. */
+ switch (config->referenceCurrentSource)
+ {
+ case kDAC12_ReferenceCurrentSourceAlt0:
+ tmp32 |= DAC_CR2_IREF_MASK;
+ break;
+ case kDAC12_ReferenceCurrentSourceAlt1:
+ tmp32 |= DAC_CR2_IREF1_MASK;
+ break;
+ case kDAC12_ReferenceCurrentSourceAlt2:
+ tmp32 |= DAC_CR2_IREF2_MASK;
+ break;
+ default: /* kDAC12_ReferenceCurrentSourceDisabled */
+ break;
+ }
+
+ /* Speed mode. */
+ switch (config->speedMode)
+ {
+ case kDAC12_SpeedMiddleMode:
+ tmp32 |= DAC_CR2_BFMS_MASK;
+ break;
+ case kDAC12_SpeedHighMode:
+ tmp32 |= DAC_CR2_BFHS_MASK;
+ break;
+ default: /* kDAC12_SpeedLowMode */
+ break;
+ }
+
+ /* DAC buffered mode needs OPAMP enabled. DAC unbuffered mode needs OPAMP disabled. */
+ if (config->enableAnalogBuffer)
+ {
+ tmp32 |= DAC_CR2_BFEN_MASK; /* OPAMP is used as buffer. */
+ }
+ else
+ {
+ tmp32 |= DAC_CR2_OEN_MASK; /* Output buffer is bypassed. */
+ }
+ base->CR2 = tmp32;
+
+#if !(defined(FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER) && FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER)
+ base->ITRM = DAC_ITRM_TRIM(config->currentReferenceInternalTrimValue);
+#endif /* FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER */
+}
+
+/*!
+ * brief De-initialize the DAC12 module.
+ *
+ * param base DAC12 peripheral base address.
+ */
+void DAC12_Deinit(DAC_Type *base)
+{
+ DAC12_Enable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_dac12Clocks[DAC12_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Initializes the DAC12 user configuration structure.
+ *
+ * This function initializes the user configuration structure to a default value. The default values are:
+ * code
+ * config->fifoWatermarkLevel = 0U;
+ * config->fifoWorkMode = kDAC12_FIFODisabled;
+ * config->referenceVoltageSource = kDAC12_ReferenceVoltageSourceAlt1;
+ * config->fifoTriggerMode = kDAC12_FIFOTriggerByHardwareMode;
+ * config->referenceCurrentSource = kDAC12_ReferenceCurrentSourceAlt0;
+ * config->speedMode = kDAC12_SpeedLowMode;
+ * config->speedMode = false;
+ * config->currentReferenceInternalTrimValue = 0x4;
+ * endcode
+ * param config Pointer to the configuration structure. See "dac12_config_t".
+ */
+void DAC12_GetDefaultConfig(dac12_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->fifoWatermarkLevel = 0U;
+ config->fifoWorkMode = kDAC12_FIFODisabled;
+ config->referenceVoltageSource = kDAC12_ReferenceVoltageSourceAlt1;
+ config->fifoTriggerMode = kDAC12_FIFOTriggerByHardwareMode;
+ config->referenceCurrentSource = kDAC12_ReferenceCurrentSourceAlt0;
+ config->speedMode = kDAC12_SpeedLowMode;
+ config->enableAnalogBuffer = false;
+#if !(defined(FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER) && FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER)
+ config->currentReferenceInternalTrimValue = 0x4;
+#endif /* FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER */
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.h b/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.h
new file mode 100644
index 0000000000..f467ec038c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dac12/fsl_dac12.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_DAC12_H_
+#define _FSL_DAC12_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup dac12
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief DAC12 driver version 2.1.0. */
+#define FSL_DAC12_DRIVER_VERSION (MAKE_VERSION(2, 1, 0))
+/*@}*/
+
+/*! @brief Define "write 1 to clear" flags. */
+#define DAC12_CR_W1C_FLAGS_MASK (DAC_CR_OVFF_MASK | DAC_CR_UDFF_MASK)
+/*! @brief Define all the flag bits in DACx_CR register. */
+#define DAC12_CR_ALL_FLAGS_MASK (DAC12_CR_W1C_FLAGS_MASK | DAC_CR_WMF_MASK | DAC_CR_NEMPTF_MASK | DAC_CR_FULLF_MASK)
+
+/*!
+ * @brief DAC12 flags.
+ */
+enum _dac12_status_flags
+{
+ kDAC12_OverflowFlag = DAC_CR_OVFF_MASK, /*!< FIFO overflow status flag, which indicates that more data has been
+ written into FIFO than it can hold. */
+ kDAC12_UnderflowFlag = DAC_CR_UDFF_MASK, /*!< FIFO underflow status flag, which means that there is a new trigger
+ after the FIFO is nearly empty. */
+ kDAC12_WatermarkFlag = DAC_CR_WMF_MASK, /*!< FIFO wartermark status flag, which indicates the remaining FIFO data is
+ less than the watermark setting. */
+ kDAC12_NearlyEmptyFlag = DAC_CR_NEMPTF_MASK, /*!< FIFO nearly empty flag, which means there is only one data
+ remaining in FIFO. */
+ kDAC12_FullFlag = DAC_CR_FULLF_MASK /*!< FIFO full status flag, which means that the FIFO read pointer equals the
+ write pointer, as the write pointer increase. */
+};
+
+/*!
+ * @brief DAC12 interrupts.
+ */
+enum _dac12_interrupt_enable
+{
+ kDAC12_UnderOrOverflowInterruptEnable = DAC_CR_UVIE_MASK, /*!< Underflow and overflow interrupt enable. */
+ kDAC12_WatermarkInterruptEnable = DAC_CR_WTMIE_MASK, /*!< Watermark interrupt enable. */
+ kDAC12_NearlyEmptyInterruptEnable = DAC_CR_EMPTIE_MASK, /*!< Nearly empty interrupt enable. */
+ kDAC12_FullInterruptEnable = DAC_CR_FULLIE_MASK /*!< Full interrupt enable. */
+};
+
+/*!
+ * @brief DAC12 FIFO size information provided by hardware.
+ */
+typedef enum _dac12_fifo_size_info
+{
+ kDAC12_FIFOSize2 = 0U, /*!< FIFO depth is 2. */
+ kDAC12_FIFOSize4 = 1U, /*!< FIFO depth is 4. */
+ kDAC12_FIFOSize8 = 2U, /*!< FIFO depth is 8. */
+ kDAC12_FIFOSize16 = 3U, /*!< FIFO depth is 16. */
+ kDAC12_FIFOSize32 = 4U, /*!< FIFO depth is 32. */
+ kDAC12_FIFOSize64 = 5U, /*!< FIFO depth is 64. */
+ kDAC12_FIFOSize128 = 6U, /*!< FIFO depth is 128. */
+ kDAC12_FIFOSize256 = 7U, /*!< FIFO depth is 256. */
+} dac12_fifo_size_info_t;
+
+/*!
+ * @brief DAC12 FIFO work mode.
+ */
+typedef enum _dac12_fifo_work_mode
+{
+ kDAC12_FIFODisabled = 0U, /*!< FIFO disabled and only one level buffer is enabled. Any data written from this buffer
+ goes to conversion. */
+ kDAC12_FIFOWorkAsNormalMode = 1U, /*!< Data will first read from FIFO to buffer then go to conversion. */
+ kDAC12_FIFOWorkAsSwingMode = 2U /*!< In Swing mode, the FIFO must be set up to be full. In Swing back mode, a
+ trigger changes the read pointer to make it swing between the FIFO Full and
+ Nearly Empty state. That is, the trigger increases the read pointer till FIFO
+ is nearly empty and decreases the read pointer till the FIFO is full. */
+} dac12_fifo_work_mode_t;
+
+/*!
+ * @brief DAC12 reference voltage source.
+ */
+typedef enum _dac12_reference_voltage_source
+{
+ kDAC12_ReferenceVoltageSourceAlt1 = 0U, /*!< The DAC selects DACREF_1 as the reference voltage. */
+ kDAC12_ReferenceVoltageSourceAlt2 = 1U, /*!< The DAC selects DACREF_2 as the reference voltage. */
+} dac12_reference_voltage_source_t;
+
+/*!
+ * @brief DAC12 FIFO trigger mode.
+ */
+typedef enum _dac12_fifo_trigger_mode
+{
+ kDAC12_FIFOTriggerByHardwareMode = 0U, /*!< Buffer would be triggered by hardware. */
+ kDAC12_FIFOTriggerBySoftwareMode = 1U, /*!< Buffer would be triggered by software. */
+} dac12_fifo_trigger_mode_t;
+
+/*!
+ * @brief DAC internal reference current source.
+ *
+ * Analog module needs reference current to keep working . Such reference current can generated by IP itself, or by
+ * on-chip PMC's "reference part". If no current reference be selected, analog module can’t working normally ,even when
+ * other register can still be assigned, DAC would waste current but no function.
+ * To make the DAC work, either kDAC12_ReferenceCurrentSourceAltx should be selected.
+ */
+typedef enum _dac12_reference_current_source
+{
+ kDAC12_ReferenceCurrentSourceDisabled = 0U, /*!< None of reference current source is enabled. */
+ kDAC12_ReferenceCurrentSourceAlt0 = 1U, /*!< Use the internal reference current generated by the module itself. */
+ kDAC12_ReferenceCurrentSourceAlt1 = 2U, /*!< Use the ZTC(Zero Temperature Coefficient) reference current generated
+ by on-chip power management module. */
+ kDAC12_ReferenceCurrentSourceAlt2 = 3U, /*!< Use the PTAT(Proportional To Absolution Temperature) reference current
+ generated by power management module. */
+} dac12_reference_current_source_t;
+
+/*!
+ * @brief DAC analog buffer speed mode for conversion.
+ */
+typedef enum _dac12_speed_mode
+{
+ kDAC12_SpeedLowMode = 0U, /*!< Low speed mode. */
+ kDAC12_SpeedMiddleMode = 1U, /*!< Middle speed mode. */
+ kDAC12_SpeedHighMode = 2U, /*!< High speed mode. */
+} dac12_speed_mode_t;
+
+/*!
+ * @brief DAC12 hardware information.
+ */
+typedef struct _dac12_hardware_info
+{
+ dac12_fifo_size_info_t fifoSizeInfo; /*!< The number of words in this device's DAC buffer. */
+} dac12_hardware_info_t;
+
+/*!
+ * @brief DAC12 module configuration.
+ *
+ * Actually, the most fields are for FIFO buffer.
+ */
+typedef struct
+{
+ uint32_t fifoWatermarkLevel; /*!< FIFO's watermark, the max value can be the hardware FIFO size. */
+ dac12_fifo_work_mode_t fifoWorkMode; /*!< FIFI's work mode about pointers. */
+ dac12_reference_voltage_source_t referenceVoltageSource; /*!< Select the reference voltage source. */
+ dac12_fifo_trigger_mode_t fifoTriggerMode; /*! Select the trigger mode for FIFO. */
+
+ /* Analog part configuration. */
+ dac12_reference_current_source_t referenceCurrentSource; /*!< Select the reference current source. */
+ dac12_speed_mode_t speedMode; /*!< Select the speed mode for conversion. */
+ bool enableAnalogBuffer; /*!< Enable analog buffer for high drive. */
+#if !(defined(FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER) && FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER)
+ uint32_t currentReferenceInternalTrimValue; /*!< Internal reference current trim value. 3-bit value is available.*/
+#endif /* FSL_FEATURE_DAC12_HAS_NO_ITRM_REGISTER */
+} dac12_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Get hardware information about this module.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param info Pointer to info structure, see to #dac12_hardware_info_t.
+ */
+void DAC12_GetHardwareInfo(DAC_Type *base, dac12_hardware_info_t *info);
+
+/*!
+ * @brief Initialize the DAC12 module.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param config Pointer to configuration structure, see to #dac12_config_t.
+ */
+void DAC12_Init(DAC_Type *base, const dac12_config_t *config);
+
+/*!
+ * @brief Initializes the DAC12 user configuration structure.
+ *
+ * This function initializes the user configuration structure to a default value. The default values are:
+ * @code
+ * config->fifoWatermarkLevel = 0U;
+ * config->fifoWorkMode = kDAC12_FIFODisabled;
+ * config->referenceVoltageSource = kDAC12_ReferenceVoltageSourceAlt1;
+ * config->fifoTriggerMode = kDAC12_FIFOTriggerByHardwareMode;
+ * config->referenceCurrentSource = kDAC12_ReferenceCurrentSourceAlt0;
+ * config->speedMode = kDAC12_SpeedLowMode;
+ * config->speedMode = false;
+ * config->currentReferenceInternalTrimValue = 0x4;
+ * @endcode
+ * @param config Pointer to the configuration structure. See "dac12_config_t".
+ */
+void DAC12_GetDefaultConfig(dac12_config_t *config);
+
+/*!
+ * @brief De-initialize the DAC12 module.
+ *
+ * @param base DAC12 peripheral base address.
+ */
+void DAC12_Deinit(DAC_Type *base);
+
+/*!
+ * @brief Enable the DAC12's converter or not.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param enable Enable the DAC12's converter or not.
+ */
+static inline void DAC12_Enable(DAC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR = (base->CR & ~DAC12_CR_W1C_FLAGS_MASK) | DAC_CR_DACEN_MASK;
+ }
+ else
+ {
+ base->CR &= ~DAC_CR_DACEN_MASK;
+ }
+}
+
+/*!
+ * @brief Reset all internal logic and registers.
+ *
+ * @param base DAC12 peripheral base address.
+ */
+static inline void DAC12_ResetConfig(DAC_Type *base)
+{
+ base->CR = DAC_CR_SWRST_MASK;
+}
+
+/*!
+ * @brief Reset the FIFO pointers.
+ *
+ * FIFO pointers should only be reset when the DAC12 is disabled. This function can be used to configure both pointers
+ * to the same address to reset the FIFO as empty.
+ *
+ * @param base DAC12 peripheral base address.
+ */
+static inline void DAC12_ResetFIFO(DAC_Type *base)
+{
+ /* FIFO pointers should only be reset when the module is disabled. */
+ base->CR = (base->CR & ~DAC12_CR_W1C_FLAGS_MASK) | DAC_CR_FIFORST_MASK;
+}
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Get status flags.
+ *
+ * @param base DAC12 peripheral base address.
+ * @return Mask of current status flags. See to #_dac12_status_flags.
+ */
+static inline uint32_t DAC12_GetStatusFlags(DAC_Type *base)
+{
+ return (DAC12_CR_ALL_FLAGS_MASK & base->CR);
+}
+
+/*!
+ * @brief Clear status flags.
+ *
+ * Note: Not all the flags can be cleared by this API. Several flags need special condition to clear them according to
+ * target chip's reference manual document.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param flags Mask of status flags to be cleared. See to #_dac12_status_flags.
+ */
+static inline void DAC12_ClearStatusFlags(DAC_Type *base, uint32_t flags)
+{
+ base->CR |= (flags & DAC12_CR_W1C_FLAGS_MASK);
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enable interrupts.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param mask Mask value of interrupts to be enabled. See to #_dac12_interrupt_enable.
+ */
+static inline void DAC12_EnableInterrupts(DAC_Type *base, uint32_t mask)
+{
+ base->CR = (base->CR & ~DAC12_CR_W1C_FLAGS_MASK) | mask;
+}
+
+/*!
+ * @brief Disable interrupts.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param mask Mask value of interrupts to be disabled. See to #_dac12_interrupt_enable.
+ */
+static inline void DAC12_DisableInterrupts(DAC_Type *base, uint32_t mask)
+{
+ base->CR &= ~mask;
+}
+
+/* @} */
+
+/*!
+ * @name DMA control
+ * @{
+ */
+
+/*!
+ * @brief Enable DMA or not.
+ *
+ * When DMA is enabled, the DMA request will be generated by original interrupts. The interrupts will not be presented
+ * on this module at the same time.
+ */
+static inline void DAC12_EnableDMA(DAC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR = (base->CR & ~DAC12_CR_W1C_FLAGS_MASK) | DAC_CR_DMAEN_MASK;
+ }
+ else
+ {
+ base->CR &= ~DAC_CR_DMAEN_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Functional feature
+ * @{
+ */
+
+/*!
+ * @brief Set data into the entry of FIFO buffer.
+ *
+ * When the DAC FIFO is disabled, and the one entry buffer is enabled, the DAC converts the data in the buffer to analog
+ * output voltage. Any write to the DATA register will replace the data in the buffer and push data to analog conversion
+ * without trigger support.
+ * When the DAC FIFO is enabled. Writing data would increase the write pointer of FIFO. Also, the data would be restored
+ * into the FIFO buffer.
+ *
+ * @param base DAC12 peripheral base address.
+ * @param value Setting value into FIFO buffer.
+ */
+static inline void DAC12_SetData(DAC_Type *base, uint32_t value)
+{
+ /* The module is connected internally to a 32-bit interface.
+ * For the 8-bit or 16-bit, the write might be ignored. */
+ base->DATA = DAC_DATA_DATA0(value);
+}
+
+/*!
+ * @brief Do trigger the FIFO by software.
+ *
+ * When the DAC FIFO is enabled, and software trigger is used. Doing trigger would increase the read pointer, and the
+ * data in the entry pointed by read pointer would be converted as new output.
+ *
+ * @param base DAC12 peripheral base address.
+ */
+static inline void DAC12_DoSoftwareTrigger(DAC_Type *base)
+{
+ base->CR = (base->CR & ~DAC12_CR_W1C_FLAGS_MASK) | DAC_CR_SWTRG_MASK;
+}
+
+/*!
+ * @brief Get the current read pointer of FIFO.
+ *
+ * @param base DAC12 peripheral base address.
+ * @return Read pointer index of FIFO buffer.
+ */
+static inline uint32_t DAC12_GetFIFOReadPointer(DAC_Type *base)
+{
+ return (DAC_PTR_DACRFP_MASK & base->PTR) >> DAC_PTR_DACRFP_SHIFT;
+}
+
+/*!
+ * @brief Get the current write pointer of FIFO.
+ *
+ * @param base DAC12 peripheral base address.
+ * @return Write pointer index of FIFO buffer
+ */
+static inline uint32_t DAC12_GetFIFOWritePointer(DAC_Type *base)
+{
+ return (DAC_PTR_DACWFP_MASK & base->PTR) >> DAC_PTR_DACWFP_SHIFT;
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_DAC12_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.c b/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.c
new file mode 100644
index 0000000000..a4785dd48f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright 2017-2021, NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dcdc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dcdc_1"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for DCDC module.
+ *
+ * @param base DCDC peripheral base address
+ */
+static uint32_t DCDC_GetInstance(DCDC_Type *base);
+
+#if (defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK)
+/*!
+ * @brief Convert the byte array to word.
+ *
+ * @param ptrArray Pointer to the byte array.
+ * @return The converted result.
+ */
+static uint32_t DCDC_ConvertByteArrayToWord(uint8_t *ptrArray);
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to DCDC bases for each instance. */
+static DCDC_Type *const s_dcdcBases[] = DCDC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to DCDC clocks for each instance. */
+static const clock_ip_name_t s_dcdcClocks[] = DCDC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DCDC_GetInstance(DCDC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dcdcBases); instance++)
+ {
+ if (s_dcdcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dcdcBases));
+
+ return instance;
+}
+
+#if (defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK)
+static uint32_t DCDC_ConvertByteArrayToWord(uint8_t *ptrArray)
+{
+ assert(ptrArray != NULL);
+
+ uint32_t temp32 = 0UL;
+ uint8_t index;
+
+ for (index = 0U; index < 4U; index++)
+ {
+ temp32 |= ptrArray[index] << ((index % 4U) * 8U);
+ }
+
+ return temp32;
+}
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * brief Enable the access to DCDC registers.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void DCDC_Init(DCDC_Type *base, dcdc_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_dcdcClocks[DCDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ uint32_t tmp32 = base->CTRL0;
+
+ tmp32 |= DCDC_CTRL0_CONTROL_MODE(config->controlMode) | DCDC_CTRL0_TRIM_HOLD(config->trimInputMode);
+
+ if (config->enableDcdcTimeout)
+ {
+ tmp32 |= DCDC_CTRL0_ENABLE_DCDC_CNT_MASK;
+ }
+ if (config->enableSwitchingConverterOutput)
+ {
+ tmp32 |= DCDC_CTRL0_DIG_EN_MASK;
+ }
+ base->CTRL0 |= DCDC_CTRL0_ENABLE_MASK;
+ base->CTRL0 = tmp32;
+}
+#else
+/*!
+ * brief Enable the access to DCDC registers.
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_Init(DCDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_dcdcClocks[DCDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REG */
+
+/*!
+ * brief Disable the access to DCDC registers.
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_Deinit(DCDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_dcdcClocks[DCDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * brief Get the default setting for DCDC user configuration structure.
+ *
+ * This function initializes the user configuration structure to a default value. The default values are:
+ * code
+ * config->controlMode = kDCDC_StaticControl;
+ * config->trimInputMode = kDCDC_SampleTrimInput;
+ * config->enableDcdcTimeout = false;
+ * config->enableSwitchingConverterOutput = false;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_config_t"
+ */
+void DCDC_GetDefaultConfig(DCDC_Type *base, dcdc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->controlMode = kDCDC_StaticControl;
+ config->trimInputMode = kDCDC_SampleTrimInput;
+ config->enableDcdcTimeout = false;
+ config->enableSwitchingConverterOutput = false;
+}
+
+/*!
+ * @brief Make DCDC enter into low power modes.
+ *
+ * @param base DCDC peripheral base address.
+ * @param mode DCDC low power mode selection. See to "_dcdc_low_power_mode"
+ */
+void DCDC_EnterLowPowerMode(DCDC_Type *base, dcdc_low_power_mode_t mode)
+{
+ switch (mode)
+ {
+ case kDCDC_StandbyMode:
+ base->CTRL0 |= DCDC_CTRL0_STBY_EN_MASK;
+ break;
+ case kDCDC_LowPowerMode:
+ base->CTRL0 |= DCDC_CTRL0_LP_MODE_EN_MASK;
+ break;
+ case kDCDC_GpcStandbyLowPowerMode:
+ base->CTRL0 |= DCDC_CTRL0_STBY_LP_MODE_EN_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REG */
+
+/*!
+ * brief Configure the DCDC clock source.
+ *
+ * param base DCDC peripheral base address.
+ * param clockSource Clock source for DCDC. See to "dcdc_clock_source_t".
+ */
+void DCDC_SetClockSource(DCDC_Type *base, dcdc_clock_source_t clockSource)
+{
+ uint32_t tmp32;
+
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 & ~(DCDC_REG0_XTAL_24M_OK_MASK | DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK |
+ DCDC_REG0_SEL_CLK_MASK | DCDC_REG0_PWD_OSC_INT_MASK);
+ switch (clockSource)
+ {
+ case kDCDC_ClockInternalOsc:
+ tmp32 |= DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK;
+ break;
+ case kDCDC_ClockExternalOsc:
+ /* Choose the external clock and disable the internal clock. */
+ tmp32 |= DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK | DCDC_REG0_SEL_CLK_MASK | DCDC_REG0_PWD_OSC_INT_MASK;
+ break;
+ case kDCDC_ClockAutoSwitch:
+ /* Set to switch from internal ring osc to xtal 24M if auto mode is enabled. */
+ tmp32 |= DCDC_REG0_XTAL_24M_OK_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get the default setting for detection configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableXtalokDetection = false;
+ * config->powerDownOverVoltageDetection = true;
+ * config->powerDownLowVlotageDetection = false;
+ * config->powerDownOverCurrentDetection = true;
+ * config->powerDownPeakCurrentDetection = true;
+ * config->powerDownZeroCrossDetection = true;
+ * config->OverCurrentThreshold = kDCDC_OverCurrentThresholdAlt0;
+ * config->PeakCurrentThreshold = kDCDC_PeakCurrentThresholdAlt0;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_GetDefaultDetectionConfig(dcdc_detection_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableXtalokDetection = false;
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+ config->powerDownOverVoltageVdd1P8Detection = true;
+ config->powerDownOverVoltageVdd1P0Detection = true;
+#else
+ config->powerDownOverVoltageDetection = true;
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+ config->powerDownLowVlotageDetection = false;
+ config->powerDownOverCurrentDetection = true;
+ config->powerDownPeakCurrentDetection = true;
+ config->powerDownZeroCrossDetection = true;
+ config->OverCurrentThreshold = kDCDC_OverCurrentThresholdAlt0;
+ config->PeakCurrentThreshold = kDCDC_PeakCurrentThresholdAlt0;
+}
+
+/*!
+ * breif Configure the DCDC detection.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_SetDetectionConfig(DCDC_Type *base, const dcdc_detection_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 & ~(DCDC_REG0_XTALOK_DISABLE_MASK
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+ | DCDC_REG0_PWD_HIGH_VDD1P8_DET_MASK | DCDC_REG0_PWD_HIGH_VDD1P0_DET_MASK
+#else
+ | DCDC_REG0_PWD_HIGH_VOLT_DET_MASK
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+#if defined(FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET) && FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET
+ | DCDC_REG0_PWD_CMP_DCDC_IN_DET_MASK
+#else
+ | DCDC_REG0_PWD_CMP_BATT_DET_MASK
+#endif /* FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET */
+ | DCDC_REG0_PWD_OVERCUR_DET_MASK | DCDC_REG0_PWD_CUR_SNS_CMP_MASK | DCDC_REG0_PWD_ZCD_MASK |
+ DCDC_REG0_CUR_SNS_THRSH_MASK | DCDC_REG0_OVERCUR_TRIG_ADJ_MASK);
+
+ tmp32 |= DCDC_REG0_CUR_SNS_THRSH(config->PeakCurrentThreshold) |
+ DCDC_REG0_OVERCUR_TRIG_ADJ(config->OverCurrentThreshold);
+ if (false == config->enableXtalokDetection)
+ {
+ tmp32 |= DCDC_REG0_XTALOK_DISABLE_MASK;
+ }
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+ if (config->powerDownOverVoltageVdd1P8Detection)
+ {
+ tmp32 |= DCDC_REG0_PWD_HIGH_VDD1P8_DET_MASK;
+ }
+ if (config->powerDownOverVoltageVdd1P0Detection)
+ {
+ tmp32 |= DCDC_REG0_PWD_HIGH_VDD1P0_DET_MASK;
+ }
+#else
+ if (config->powerDownOverVoltageDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_HIGH_VOLT_DET_MASK;
+ }
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+ if (config->powerDownLowVlotageDetection)
+ {
+#if defined(FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET) && FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET
+ tmp32 |= DCDC_REG0_PWD_CMP_DCDC_IN_DET_MASK;
+#else
+ tmp32 |= DCDC_REG0_PWD_CMP_BATT_DET_MASK;
+#endif /* FSL_FEATURE_DCDC_HAS_REG0_DCDC_IN_DET */
+ }
+ if (config->powerDownOverCurrentDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_OVERCUR_DET_MASK;
+ }
+ if (config->powerDownPeakCurrentDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_CUR_SNS_CMP_MASK;
+ }
+ if (config->powerDownZeroCrossDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_ZCD_MASK;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get the default setting for low power configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableOverloadDetection = true;
+ * config->enableAdjustHystereticValue = false;
+ * config->countChargingTimePeriod = kDCDC_CountChargingTimePeriod8Cycle;
+ * config->countChargingTimeThreshold = kDCDC_CountChargingTimeThreshold32;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_low_power_config_t"
+ */
+void DCDC_GetDefaultLowPowerConfig(dcdc_low_power_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+#if !(defined(FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS) && FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS)
+ config->enableOverloadDetection = true;
+#endif /* FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS */
+ config->enableAdjustHystereticValue = false;
+ config->countChargingTimePeriod = kDCDC_CountChargingTimePeriod8Cycle;
+ config->countChargingTimeThreshold = kDCDC_CountChargingTimeThreshold32;
+}
+
+/*!
+ * brief Configure the DCDC low power.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_low_power_config_t".
+ */
+void DCDC_SetLowPowerConfig(DCDC_Type *base, const dcdc_low_power_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 &
+ ~(DCDC_REG0_LP_HIGH_HYS_MASK | DCDC_REG0_LP_OVERLOAD_FREQ_SEL_MASK | DCDC_REG0_LP_OVERLOAD_THRSH_MASK
+#if !(defined(FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS) && FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS)
+ | DCDC_REG0_EN_LP_OVERLOAD_SNS_MASK
+#endif /* FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS */
+ );
+ tmp32 |= DCDC_REG0_LP_OVERLOAD_FREQ_SEL(config->countChargingTimePeriod) |
+ DCDC_REG0_LP_OVERLOAD_THRSH(config->countChargingTimeThreshold);
+#if !(defined(FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS) && FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS)
+ if (config->enableOverloadDetection)
+ {
+ tmp32 |= DCDC_REG0_EN_LP_OVERLOAD_SNS_MASK;
+ }
+#endif /* FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS */
+ if (config->enableAdjustHystereticValue)
+ {
+ tmp32 |= DCDC_REG0_LP_HIGH_HYS_MASK;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get DCDC status flags.
+ *
+ * param base peripheral base address.
+ * return Mask of asserted status flags. See to "_dcdc_status_flags_t".
+ */
+uint32_t DCDC_GetstatusFlags(DCDC_Type *base)
+{
+ uint32_t tmp32 = 0U;
+
+ if (DCDC_REG0_STS_DC_OK_MASK == (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ tmp32 |= (uint32_t)kDCDC_LockedOKStatus;
+ }
+
+ return tmp32;
+}
+
+#if !(defined(FSL_FEATURE_DCDC_HAS_NO_CURRENT_ALERT_FUNC) && FSL_FEATURE_DCDC_HAS_NO_CURRENT_ALERT_FUNC)
+/*!
+ * brief Reset current alert signal. Alert signal is generate by peak current detection.
+ *
+ * param base DCDC peripheral base address.
+ * param enable Switcher to reset signal. True means reset signal. False means don't reset signal.
+ */
+void DCDC_ResetCurrentAlertSignal(DCDC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->REG0 |= DCDC_REG0_CURRENT_ALERT_RESET_MASK;
+ }
+ else
+ {
+ base->REG0 &= ~DCDC_REG0_CURRENT_ALERT_RESET_MASK;
+ }
+}
+#endif /* FSL_FEATURE_DCDC_HAS_NO_CURRENT_ALERT_FUNC */
+
+/*!
+ * brief Get the default setting for loop control configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableCommonHysteresis = false;
+ * config->enableCommonThresholdDetection = false;
+ * config->enableInvertHysteresisSign = false;
+ * config->enableRCThresholdDetection = false;
+ * config->enableRCScaleCircuit = 0U;
+ * config->complementFeedForwardStep = 0U;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_loop_control_config_t"
+ */
+void DCDC_GetDefaultLoopControlConfig(dcdc_loop_control_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableCommonHysteresis = false;
+ config->enableCommonThresholdDetection = false;
+ config->enableInvertHysteresisSign = false;
+ config->enableRCThresholdDetection = false;
+ config->enableRCScaleCircuit = 0U;
+ config->complementFeedForwardStep = 0U;
+}
+
+/*!
+ * brief Configure the DCDC loop control.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_loop_control_config_t".
+ */
+void DCDC_SetLoopControlConfig(DCDC_Type *base, const dcdc_loop_control_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ /* Configure the DCDC_REG1 register. */
+#if defined(FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE) && \
+ FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE
+ tmp32 = base->REG1 & ~(DCDC_REG1_LOOPCTRL_EN_DF_HYST_MASK | DCDC_REG1_LOOPCTRL_EN_CM_HYST_MASK |
+ DCDC_REG1_LOOPCTRL_DF_HST_THRESH_MASK | DCDC_REG1_LOOPCTRL_CM_HST_THRESH_MASK);
+ if (config->enableCommonHysteresis)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_EN_CM_HYST_MASK;
+ }
+ if (config->enableCommonThresholdDetection)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_CM_HST_THRESH_MASK;
+ }
+ if (config->enableDifferentialHysteresis)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_EN_DF_HYST_MASK;
+ }
+ if (config->enableDifferentialThresholdDetection)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_DF_HST_THRESH_MASK;
+ }
+#else
+ tmp32 = base->REG1 & ~(DCDC_REG1_LOOPCTRL_EN_HYST_MASK | DCDC_REG1_LOOPCTRL_HST_THRESH_MASK);
+ if (config->enableCommonHysteresis)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_EN_HYST_MASK;
+ }
+ if (config->enableCommonThresholdDetection)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_HST_THRESH_MASK;
+ }
+#endif /* FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE */
+ base->REG1 = tmp32;
+
+ /* configure the DCDC_REG2 register. */
+ tmp32 = base->REG2 & ~(DCDC_REG2_LOOPCTRL_HYST_SIGN_MASK | DCDC_REG2_LOOPCTRL_RCSCALE_THRSH_MASK |
+ DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK | DCDC_REG2_LOOPCTRL_DC_FF_MASK);
+ tmp32 |= DCDC_REG2_LOOPCTRL_DC_FF(config->complementFeedForwardStep) |
+ DCDC_REG2_LOOPCTRL_EN_RCSCALE(config->enableRCScaleCircuit);
+ if (config->enableInvertHysteresisSign)
+ {
+ tmp32 |= DCDC_REG2_LOOPCTRL_HYST_SIGN_MASK;
+ }
+ if (config->enableRCThresholdDetection)
+ {
+ tmp32 |= DCDC_REG2_LOOPCTRL_RCSCALE_THRSH_MASK;
+ }
+ base->REG2 = tmp32;
+}
+
+/*!
+ * brief Configure for the min power.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_min_power_config_t".
+ */
+void DCDC_SetMinPowerConfig(DCDC_Type *base, const dcdc_min_power_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ tmp32 = base->REG3 & ~DCDC_REG3_MINPWR_DC_HALFCLK_MASK;
+ if (config->enableUseHalfFreqForContinuous)
+ {
+ tmp32 |= DCDC_REG3_MINPWR_DC_HALFCLK_MASK;
+ }
+ base->REG3 = tmp32;
+}
+
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode and low power mode.
+ * Do not use this function. It has been superceded by DCDC_AdjustRunTargetVoltage
+ * and DCDC_AdjustLowPowerTargetVoltage.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ * param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t VDDRun, uint32_t VDDStandby, dcdc_voltage_output_sel_t sel)
+{
+ uint32_t tmp32;
+
+ if (sel == kDCDC_VoltageOutput1P8)
+ {
+ /* Unlock the step for the VDD 1P8. */
+ base->REG3 &= ~DCDC_REG3_VDD1P8CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~(DCDC_CTRL1_VDD1P8CTRL_STBY_TRG_MASK | DCDC_CTRL1_VDD1P8CTRL_TRG_MASK);
+
+ tmp32 |= DCDC_CTRL1_VDD1P8CTRL_STBY_TRG(VDDStandby) | DCDC_CTRL1_VDD1P8CTRL_TRG(VDDRun);
+ base->CTRL1 = tmp32;
+ }
+ else if (sel == kDCDC_VoltageOutput1P0)
+ {
+ /* Unlock the step for the VDD 1P0. */
+ base->REG3 &= ~DCDC_REG3_VDD1P0CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~(DCDC_CTRL1_VDD1P0CTRL_STBY_TRG_MASK | DCDC_CTRL1_VDD1P0CTRL_TRG_MASK);
+
+ tmp32 |= DCDC_CTRL1_VDD1P0CTRL_STBY_TRG(VDDStandby) | DCDC_CTRL1_VDD1P0CTRL_TRG(VDDRun);
+ base->CTRL1 = tmp32;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustRunTargetVoltage(DCDC_Type *base, uint32_t VDDRun, dcdc_voltage_output_sel_t sel)
+{
+ uint32_t tmp32;
+
+ if (sel == kDCDC_VoltageOutput1P8)
+ {
+ /* Unlock the step for the VDD 1P8. */
+ base->REG3 &= ~DCDC_REG3_VDD1P8CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~DCDC_CTRL1_VDD1P8CTRL_TRG_MASK;
+
+ tmp32 |= DCDC_CTRL1_VDD1P8CTRL_TRG(VDDRun);
+ base->CTRL1 = tmp32;
+ }
+ else if (sel == kDCDC_VoltageOutput1P0)
+ {
+ /* Unlock the step for the VDD 1P0. */
+ base->REG3 &= ~DCDC_REG3_VDD1P0CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~DCDC_CTRL1_VDD1P0CTRL_TRG_MASK;
+
+ tmp32 |= DCDC_CTRL1_VDD1P0CTRL_TRG(VDDRun);
+ base->CTRL1 = tmp32;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in low power mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ * param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustLowPowerTargetVoltage(DCDC_Type *base, uint32_t VDDStandby, dcdc_voltage_output_sel_t sel)
+{
+ uint32_t tmp32;
+
+ if (sel == kDCDC_VoltageOutput1P8)
+ {
+ /* Unlock the step for the VDD 1P8. */
+ base->REG3 &= ~DCDC_REG3_VDD1P8CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~(DCDC_CTRL1_VDD1P8CTRL_STBY_TRG_MASK);
+
+ tmp32 |= DCDC_CTRL1_VDD1P8CTRL_STBY_TRG(VDDStandby);
+ base->CTRL1 = tmp32;
+ }
+ else if (sel == kDCDC_VoltageOutput1P0)
+ {
+ /* Unlock the step for the VDD 1P0. */
+ base->REG3 &= ~DCDC_REG3_VDD1P0CTRL_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_CTRL1 register. */
+ tmp32 = base->CTRL1 & ~(DCDC_CTRL1_VDD1P0CTRL_STBY_TRG_MASK);
+
+ tmp32 |= DCDC_CTRL1_VDD1P0CTRL_STBY_TRG(VDDStandby);
+ base->CTRL1 = tmp32;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+#else
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode and low power mode.
+ * Do not use this function. It has been superceded by DCDC_AdjustRunTargetVoltage
+ * and DCDC_AdjustLowPowerTargetVoltage
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t VDDRun, uint32_t VDDStandby)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~(DCDC_REG3_TARGET_LP_MASK | DCDC_REG3_TRG_MASK);
+
+ tmp32 |= DCDC_REG3_TARGET_LP(VDDStandby) | DCDC_REG3_TRG(VDDRun);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ */
+void DCDC_AdjustRunTargetVoltage(DCDC_Type *base, uint32_t VDDRun)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~DCDC_REG3_TRG_MASK;
+
+ tmp32 |= DCDC_REG3_TRG(VDDRun);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in low power mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustLowPowerTargetVoltage(DCDC_Type *base, uint32_t VDDStandby)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~DCDC_REG3_TARGET_LP_MASK;
+
+ tmp32 |= DCDC_REG3_TARGET_LP(VDDStandby);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage is set to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2 */
+
+/*!
+ * brief Configure the DCDC internal regulator.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_internal_regulator_config_t".
+ */
+void DCDC_SetInternalRegulatorConfig(DCDC_Type *base, const dcdc_internal_regulator_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if (defined(FSL_FEATURE_DCDC_HAS_REG3_FBK_SEL) && FSL_FEATURE_DCDC_HAS_REG3_FBK_SEL)
+ tmp32 = base->REG3 & ~DCDC_REG3_REG_FBK_SEL_MASK;
+ tmp32 |= DCDC_REG3_REG_FBK_SEL(config->feedbackPoint);
+ base->REG3 = tmp32;
+
+ tmp32 = base->REG1 & ~DCDC_REG1_REG_RLOAD_SW_MASK;
+#else
+ /* Configure the DCDC_REG1 register. */
+ tmp32 = base->REG1 & ~(DCDC_REG1_REG_FBK_SEL_MASK | DCDC_REG1_REG_RLOAD_SW_MASK);
+ tmp32 |= DCDC_REG1_REG_FBK_SEL(config->feedbackPoint);
+#endif /* FSL_FEATURE_DCDC_HAS_REG3_FBK_SEL */
+
+ if (config->enableLoadResistor)
+ {
+ tmp32 |= DCDC_REG1_REG_RLOAD_SW_MASK;
+ }
+ base->REG1 = tmp32;
+}
+
+#if (defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK)
+/*!
+ * brief Init DCDC module when the control mode selected as setpoint mode.
+ *
+ * note The function should be invoked in the initial step to config the
+ * DCDC via setpoint control mode.
+ *
+ * param base DCDC peripheral base address.
+ * param config The pointer to the structure @ref dcdc_setpoint_config_t.
+ */
+void DCDC_SetPointInit(DCDC_Type *base, const dcdc_setpoint_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Enable DCDC Dig Logic. */
+ base->REG5 = config->enableDigLogicMap;
+
+ /* Set DCDC power mode. */
+ base->REG6 = config->lowpowerMap;
+ base->REG7 = config->standbyMap;
+ base->REG7P = config->standbyLowpowerMap;
+
+ /* Set target voltage of VDD1P8 in buck mode. */
+ base->REG8 = DCDC_ConvertByteArrayToWord(config->buckVDD1P8TargetVoltage);
+ base->REG9 = DCDC_ConvertByteArrayToWord(config->buckVDD1P8TargetVoltage + 4U);
+ base->REG10 = DCDC_ConvertByteArrayToWord(config->buckVDD1P8TargetVoltage + 8U);
+ base->REG11 = DCDC_ConvertByteArrayToWord(config->buckVDD1P8TargetVoltage + 12U);
+
+ /* Set target voltage of VDD1P0 in buck mode. */
+ base->REG12 = DCDC_ConvertByteArrayToWord(config->buckVDD1P0TargetVoltage);
+ base->REG13 = DCDC_ConvertByteArrayToWord(config->buckVDD1P0TargetVoltage + 4U);
+ base->REG14 = DCDC_ConvertByteArrayToWord(config->buckVDD1P0TargetVoltage + 8U);
+ base->REG15 = DCDC_ConvertByteArrayToWord(config->buckVDD1P0TargetVoltage + 12U);
+
+ /* Set target voltage of VDD1P8 in low power mode. */
+ base->REG16 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P8TargetVoltage);
+ base->REG17 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P8TargetVoltage + 4U);
+ base->REG18 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P8TargetVoltage + 8U);
+ base->REG19 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P8TargetVoltage + 12U);
+
+ /* Set target voltage of VDD1P0 in low power mode. */
+ base->REG20 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P0TargetVoltage);
+ base->REG21 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P0TargetVoltage + 4U);
+ base->REG22 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P0TargetVoltage + 8U);
+ base->REG23 = DCDC_ConvertByteArrayToWord(config->standbyVDD1P0TargetVoltage + 12U);
+
+ /* Enable DCDC module. */
+ base->REG4 = config->enableDCDCMap;
+}
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+/*!
+ * brief Boot DCDC into DCM(discontinous conduction mode).
+ *
+ * pwd_zcd=0x0;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale= 0x5;
+ * DCM_set_ctrl=1'b1;
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoDCM(DCDC_Type *base)
+{
+ base->REG0 &= ~(DCDC_REG0_PWD_ZCD_MASK | DCDC_REG0_PWD_CMP_OFFSET_MASK);
+ base->REG2 = (~DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK & base->REG2) | DCDC_REG2_LOOPCTRL_EN_RCSCALE(0x5U) |
+ DCDC_REG2_DCM_SET_CTRL_MASK;
+}
+
+/*!
+ * brief Boot DCDC into CCM(continous conduction mode).
+ *
+ * pwd_zcd=0x1;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale=0x3;
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoCCM(DCDC_Type *base)
+{
+ base->REG0 = (~DCDC_REG0_PWD_CMP_OFFSET_MASK & base->REG0) | DCDC_REG0_PWD_ZCD_MASK;
+ base->REG2 = (~DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK & base->REG2) | DCDC_REG2_LOOPCTRL_EN_RCSCALE(0x3U);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.h b/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.h
new file mode 100644
index 0000000000..0335fcc83b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcdc_1/fsl_dcdc.h
@@ -0,0 +1,735 @@
+/*
+ * Copyright 2017-2021, NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __FSL_DCDC_H__
+#define __FSL_DCDC_H__
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup dcdc
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief DCDC driver version. */
+#define FSL_DCDC_DRIVER_VERSION (MAKE_VERSION(2, 3, 0)) /*!< Version 2.3.0. */
+
+/*!
+ * @brief DCDC status flags.
+ */
+enum _dcdc_status_flags_t
+{
+ kDCDC_LockedOKStatus = (1U << 0U), /*!< Indicate DCDC status. 1'b1: DCDC already settled 1'b0: DCDC is settling. */
+};
+
+/*!
+ * @brief The current bias of low power comparator.
+ */
+typedef enum _dcdc_comparator_current_bias
+{
+ kDCDC_ComparatorCurrentBias50nA = 0U, /*!< The current bias of low power comparator is 50nA. */
+ kDCDC_ComparatorCurrentBias100nA = 1U, /*!< The current bias of low power comparator is 100nA. */
+ kDCDC_ComparatorCurrentBias200nA = 2U, /*!< The current bias of low power comparator is 200nA. */
+ kDCDC_ComparatorCurrentBias400nA = 3U, /*!< The current bias of low power comparator is 400nA. */
+} dcdc_comparator_current_bias_t;
+
+/*!
+ * @brief The threshold of over current detection.
+ */
+typedef enum _dcdc_over_current_threshold
+{
+ kDCDC_OverCurrentThresholdAlt0 = 0U, /*!< 1A in the run mode, 0.25A in the power save mode. */
+ kDCDC_OverCurrentThresholdAlt1 = 1U, /*!< 2A in the run mode, 0.25A in the power save mode. */
+ kDCDC_OverCurrentThresholdAlt2 = 2U, /*!< 1A in the run mode, 0.2A in the power save mode. */
+ kDCDC_OverCurrentThresholdAlt3 = 3U, /*!< 2A in the run mode, 0.2A in the power save mode. */
+} dcdc_over_current_threshold_t;
+
+/*!
+ * @brief The threshold if peak current detection.
+ */
+typedef enum _dcdc_peak_current_threshold
+{
+ kDCDC_PeakCurrentThresholdAlt0 = 0U, /*!< 150mA peak current threshold. */
+ kDCDC_PeakCurrentThresholdAlt1 = 1U, /*!< 250mA peak current threshold. */
+ kDCDC_PeakCurrentThresholdAlt2 = 2U, /*!< 350mA peak current threshold. */
+ kDCDC_PeakCurrentThresholdAlt3 = 3U, /*!< 450mA peak current threshold. */
+ kDCDC_PeakCurrentThresholdAlt4 = 4U, /*!< 550mA peak current threshold. */
+ kDCDC_PeakCurrentThresholdAlt5 = 5U, /*!< 650mA peak current threshold. */
+} dcdc_peak_current_threshold_t;
+
+/*!
+ * @brief The period of counting the charging times in power save mode.
+ */
+typedef enum _dcdc_count_charging_time_period
+{
+ kDCDC_CountChargingTimePeriod8Cycle = 0U, /*!< Eight 32k cycle. */
+ kDCDC_CountChargingTimePeriod16Cycle = 1U, /*!< Sixteen 32k cycle. */
+} dcdc_count_charging_time_period_t;
+
+/*!
+ * @brief The threshold of the counting number of charging times
+ */
+typedef enum _dcdc_count_charging_time_threshold
+{
+ kDCDC_CountChargingTimeThreshold32 = 0U, /*!< 0x0: 32. */
+ kDCDC_CountChargingTimeThreshold64 = 1U, /*!< 0x1: 64. */
+ kDCDC_CountChargingTimeThreshold16 = 2U, /*!< 0x2: 16. */
+ kDCDC_CountChargingTimeThreshold8 = 3U, /*!< 0x3: 8. */
+} dcdc_count_charging_time_threshold_t;
+
+/*!
+ * @brief Oscillator clock option.
+ */
+typedef enum _dcdc_clock_source
+{
+ kDCDC_ClockAutoSwitch = 0U, /*!< Automatic clock switch from internal oscillator to external clock. */
+ kDCDC_ClockInternalOsc = 1U, /*!< Use internal oscillator. */
+ kDCDC_ClockExternalOsc = 2U, /*!< Use external 24M crystal oscillator. */
+} dcdc_clock_source_t;
+
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+/*!
+ * @brief Voltage output option.
+ */
+typedef enum _dcdc_voltage_output_sel
+{
+ kDCDC_VoltageOutput1P8 = 0U, /*!< 1.8V output. */
+ kDCDC_VoltageOutput1P0 = 1U, /*!< 1.0V output. */
+} dcdc_voltage_output_sel_t;
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * @brief DCDC low power modes.
+ */
+typedef enum _dcdc_low_power_mode
+{
+ kDCDC_StandbyMode = 0U, /*!< Standby mode. */
+ kDCDC_LowPowerMode = 1U, /*!< Low power mode. */
+ kDCDC_GpcStandbyLowPowerMode = 2U, /*!< low power mode for GPC standby request. */
+} dcdc_low_power_mode_t;
+
+/*!
+ * @brief DCDC control mode.
+ */
+typedef enum _dcdc_control_mode
+{
+ kDCDC_StaticControl = 0U, /*!< Static control. */
+ kDCDC_SetPointControl = 1U, /*!< Controlled by GPC set points. */
+} dcdc_control_mode_t;
+
+/*!
+ * @brief DCDC trim input mode.
+ */
+typedef enum _dcdc_trim_input_mode
+{
+ kDCDC_SampleTrimInput = 0U, /*!< Sample trim input. */
+ kDCDC_HoldTrimInput = 1U, /*!< Hold trim input. */
+} dcdc_trim_input_mode_t;
+
+#if defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK
+/*!
+ * @brief System setpoints enumeration.
+ */
+enum _dcdc_setpoint_map
+{
+ kDCDC_SetPoint0 = 1UL << 0UL, /*!< Set point 0. */
+ kDCDC_SetPoint1 = 1UL << 1UL, /*!< Set point 1. */
+ kDCDC_SetPoint2 = 1UL << 2UL, /*!< Set point 2. */
+ kDCDC_SetPoint3 = 1UL << 3UL, /*!< Set point 3. */
+ kDCDC_SetPoint4 = 1UL << 4UL, /*!< Set point 4. */
+ kDCDC_SetPoint5 = 1UL << 5UL, /*!< Set point 5. */
+ kDCDC_SetPoint6 = 1UL << 6UL, /*!< Set point 6. */
+ kDCDC_SetPoint7 = 1UL << 7UL, /*!< Set point 7. */
+ kDCDC_SetPoint8 = 1UL << 8UL, /*!< Set point 8. */
+ kDCDC_SetPoint9 = 1UL << 9UL, /*!< Set point 9. */
+ kDCDC_SetPoint10 = 1UL << 10UL, /*!< Set point 10. */
+ kDCDC_SetPoint11 = 1UL << 11UL, /*!< Set point 11. */
+ kDCDC_SetPoint12 = 1UL << 12UL, /*!< Set point 12. */
+ kDCDC_SetPoint13 = 1UL << 13UL, /*!< Set point 13. */
+ kDCDC_SetPoint14 = 1UL << 14UL, /*!< Set point 14. */
+ kDCDC_SetPoint15 = 1UL << 15UL /*!< Set point 15. */
+};
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+/*!
+ * @brief Configuration for DCDC.
+ */
+typedef struct _dcdc_config
+{
+ dcdc_control_mode_t controlMode; /*!< DCDC control mode. */
+ dcdc_trim_input_mode_t trimInputMode; /*!< Hold trim input. */
+ bool enableDcdcTimeout; /*!< Enable internal count for DCDC_OK timeout. */
+ bool enableSwitchingConverterOutput; /*!< Enable the VDDIO switching converter output.*/
+} dcdc_config_t;
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REGp */
+
+/*!
+ * @brief Configuration for DCDC detection.
+ */
+typedef struct _dcdc_detection_config
+{
+ bool enableXtalokDetection; /*!< Enable xtalok detection circuit. */
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+ bool powerDownOverVoltageVdd1P8Detection; /*!< Power down over-voltage detection comparator for VDD1P8. */
+ bool powerDownOverVoltageVdd1P0Detection; /*!< Power down over-voltage detection comparator for VDD1P0. */
+#else
+ bool powerDownOverVoltageDetection; /*!< Power down over-voltage detection comparator. */
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+ bool powerDownLowVlotageDetection; /*!< Power down low-voltage detection comparator. */
+ bool powerDownOverCurrentDetection; /*!< Power down over-current detection. */
+ bool powerDownPeakCurrentDetection; /*!< Power down peak-current detection. */
+ bool powerDownZeroCrossDetection; /*!< Power down the zero cross detection function for discontinuous conductor
+ mode. */
+ dcdc_over_current_threshold_t OverCurrentThreshold; /*!< The threshold of over current detection. */
+ dcdc_peak_current_threshold_t PeakCurrentThreshold; /*!< The threshold of peak current detection. */
+} dcdc_detection_config_t;
+
+/*!
+ * @brief Configuration for the loop control.
+ */
+typedef struct _dcdc_loop_control_config
+{
+ bool enableCommonHysteresis; /*!< Enable hysteresis in switching converter common mode analog comparators.
+ This feature will improve transient supply ripple and efficiency. */
+ bool enableCommonThresholdDetection; /*!< Increase the threshold detection for common mode analog comparator. */
+#if defined(FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE) && \
+ FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE
+ bool enableDifferentialHysteresis; /*!< Enable hysteresis in switching converter differential mode analog
+ comparators. This feature will improve transient supply ripple and
+ efficiency. */
+ bool enableDifferentialThresholdDetection; /*!< Increase the threshold detection for differential mode analog
+ comparators. */
+#endif /* FSL_FEATURE_DCDC_HAS_SWITCHING_CONVERTER_DIFFERENTIAL_MODE */
+ bool enableInvertHysteresisSign; /*!< Invert the sign of the hysteresis in DC-DC analog comparators. */
+ bool enableRCThresholdDetection; /*!< Increase the threshold detection for RC scale circuit. */
+ uint32_t enableRCScaleCircuit; /*!< Available range is 0~7. Enable analog circuit of DC-DC converter to respond
+ faster under transient load conditions. */
+ uint32_t complementFeedForwardStep; /*!< Available range is 0~7. Two's complement feed forward step in duty cycle in
+ the switching DC-DC converter. Each time this field makes a transition from
+ 0x0, the loop filter of the DC-DC converter is stepped once by a value
+ proportional to the change. This can be used to force a certain control loop
+ behavior, such as improving response under known heavy load transients. */
+} dcdc_loop_control_config_t;
+/*!
+ * @brief Configuration for DCDC low power.
+ */
+typedef struct _dcdc_low_power_config
+{
+#if !(defined(FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS) && FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS)
+ bool enableOverloadDetection; /*!< Enable the overload detection in power save mode, if current is larger than the
+ overloading threshold (typical value is 50 mA), DCDC will switch to the run mode
+ automatically. */
+#endif /* FSL_FEATURE_DCDC_HAS_NO_REG0_EN_LP_OVERLOAD_SNS */
+ bool enableAdjustHystereticValue; /*!< Adjust hysteretic value in low power from 12.5mV to 25mV. */
+ dcdc_count_charging_time_period_t
+ countChargingTimePeriod; /*!< The period of counting the charging times in power save mode. */
+ dcdc_count_charging_time_threshold_t
+ countChargingTimeThreshold; /*!< the threshold of the counting number of charging times during
+ the period that lp_overload_freq_sel sets in power save mode. */
+} dcdc_low_power_config_t;
+
+/*!
+ * @brief Configuration for DCDC internal regulator.
+ */
+typedef struct _dcdc_internal_regulator_config
+{
+ bool enableLoadResistor; /*!< control the load resistor of the internal regulator of DCDC, the load resistor is
+ connected as default "true", and need set to "false" to disconnect the load
+ resistor. */
+ uint32_t feedbackPoint; /*!< Available range is 0~3. Select the feedback point of the internal regulator. */
+} dcdc_internal_regulator_config_t;
+
+/*!
+ * @brief Configuration for min power setting.
+ */
+typedef struct _dcdc_min_power_config
+{
+ bool enableUseHalfFreqForContinuous; /*!< Set DCDC clock to half frequency for the continuous mode. */
+} dcdc_min_power_config_t;
+
+#if defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK
+/*!
+ * @brief DCDC configuration in set point mode.
+ */
+typedef struct _dcdc_setpoint_config
+{
+ uint32_t enableDCDCMap; /*!< The setpoint map that enable the DCDC module. Should be the OR'ed value of @ref
+ _dcdc_setpoint_map. */
+ uint32_t enableDigLogicMap; /*!< The setpoint map that enable the DCDC dig logic. Should be the OR'ed value of @ref
+ _dcdc_setpoint_map. */
+ uint32_t lowpowerMap; /*!< The setpoint map that enable the DCDC Low powermode. Should be the OR'ed value of @ref
+ _dcdc_setpoint_map. */
+ uint32_t standbyMap; /*!< The setpoint map that enable the DCDC standby mode. Should be the OR'ed value of @ref
+ _dcdc_setpoint_map. */
+ uint32_t standbyLowpowerMap; /*!< The setpoint map that enable the DCDC low power mode, when the related setpoint is
+ in standby mode.
+ @ref _dcdc_setpoint_map. */
+ uint8_t *buckVDD1P8TargetVoltage; /*!< Point to the array that store the target voltage level of VDD1P8 in buck
+ mode. Note that the pointed array must have 16 elements. */
+ uint8_t *buckVDD1P0TargetVoltage; /*!< Point to the array that store the target voltage level of VDD1P0 in buck
+ mode. Note that the pointed array must have 16 elements. */
+ uint8_t *standbyVDD1P8TargetVoltage; /*!< Point to the array that store the target voltage level of VDD1P8 in
+ standby mode. Note that the pointed array must have 16 elements. */
+ uint8_t *standbyVDD1P0TargetVoltage; /*!< Point to the array that store the target voltage level of VDD1P0 in
+ standby mode. Note that the pointed array must have 16 elements. */
+} dcdc_setpoint_config_t;
+
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * @brief Enable the access to DCDC registers.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void DCDC_Init(DCDC_Type *base, dcdc_config_t *config);
+#else
+/*!
+ * @brief Enable the access to DCDC registers.
+ *
+ * @param base DCDC peripheral base address.
+ */
+void DCDC_Init(DCDC_Type *base);
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REG */
+
+/*!
+ * @brief Disable the access to DCDC registers.
+ *
+ * @param base DCDC peripheral base address.
+ */
+void DCDC_Deinit(DCDC_Type *base);
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * brief Get the default setting for DCDC user configuration structure.
+ *
+ * This function initializes the user configuration structure to a default value. The default values are:
+ * code
+ * config->controlMode = kDCDC_StaticControl;
+ * config->trimInputMode = kDCDC_SampleTrimInput;
+ * config->enableDcdcTimeout = false;
+ * config->enableSwitchingConverterOutput = false;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_config_t"
+ */
+void DCDC_GetDefaultConfig(DCDC_Type *base, dcdc_config_t *config);
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REGp */
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Get DCDC status flags.
+ *
+ * @param base peripheral base address.
+ * @return Mask of asserted status flags. See to "_dcdc_status_flags_t".
+ */
+uint32_t DCDC_GetstatusFlags(DCDC_Type *base);
+
+/* @} */
+
+/*!
+ * @name Misc control
+ * @{
+ */
+
+#if defined(FSL_FEATURE_DCDC_HAS_CTRL_REG) && FSL_FEATURE_DCDC_HAS_CTRL_REG
+/*!
+ * @brief Make DCDC enter into low power modes.
+ *
+ * @param base DCDC peripheral base address.
+ * @param mode DCDC low power mode selection. See to "_dcdc_low_power_mode"
+ */
+void DCDC_EnterLowPowerMode(DCDC_Type *base, dcdc_low_power_mode_t mode);
+#endif /* FSL_FEATURE_DCDC_HAS_CTRL_REG */
+
+/*!
+ * @brief Enable the output range comparator.
+ *
+ * The output range comparator is disabled by default.
+ *
+ * @param base DCDC peripheral base address.
+ * @param enable Enable the feature or not.
+ */
+static inline void DCDC_EnableOutputRangeComparator(DCDC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->REG0 &= ~DCDC_REG0_PWD_CMP_OFFSET_MASK;
+ }
+ else
+ {
+ base->REG0 |= DCDC_REG0_PWD_CMP_OFFSET_MASK;
+ }
+}
+
+/*!
+ * @brief Configure the DCDC clock source.
+ *
+ * @param base DCDC peripheral base address.
+ * @param clockSource Clock source for DCDC. See to "dcdc_clock_source_t".
+ */
+void DCDC_SetClockSource(DCDC_Type *base, dcdc_clock_source_t clockSource);
+
+/*!
+ * @brief Get the default setting for detection configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * @code
+ * config->enableXtalokDetection = false;
+ * config->powerDownOverVoltageDetection = true;
+ * config->powerDownLowVlotageDetection = false;
+ * config->powerDownOverCurrentDetection = true;
+ * config->powerDownPeakCurrentDetection = true;
+ * config->powerDownZeroCrossDetection = true;
+ * config->OverCurrentThreshold = kDCDC_OverCurrentThresholdAlt0;
+ * config->PeakCurrentThreshold = kDCDC_PeakCurrentThresholdAlt0;
+ * @endcode
+ *
+ * @param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_GetDefaultDetectionConfig(dcdc_detection_config_t *config);
+
+/*!
+ * @brief Configure the DCDC detection.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_SetDetectionConfig(DCDC_Type *base, const dcdc_detection_config_t *config);
+
+/*!
+ * @brief Get the default setting for low power configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * @code
+ * config->enableOverloadDetection = true;
+ * config->enableAdjustHystereticValue = false;
+ * config->countChargingTimePeriod = kDCDC_CountChargingTimePeriod8Cycle;
+ * config->countChargingTimeThreshold = kDCDC_CountChargingTimeThreshold32;
+ * @endcode
+ *
+ * @param config Pointer to configuration structure. See to "dcdc_low_power_config_t"
+ */
+void DCDC_GetDefaultLowPowerConfig(dcdc_low_power_config_t *config);
+
+/*!
+ * @brief Configure the DCDC low power.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to configuration structure. See to "dcdc_low_power_config_t".
+ */
+void DCDC_SetLowPowerConfig(DCDC_Type *base, const dcdc_low_power_config_t *config);
+
+/*!
+ * @brief Reset current alert signal. Alert signal is generate by peak current detection.
+ *
+ * @param base DCDC peripheral base address.
+ * @param enable Switcher to reset signal. True means reset signal. False means don't reset signal.
+ */
+void DCDC_ResetCurrentAlertSignal(DCDC_Type *base, bool enable);
+
+/*!
+ * @brief Set the bangap trim value to trim bandgap voltage.
+ *
+ * @param base DCDC peripheral base address.
+ * @param trimValue The bangap trim value. Available range is 0U-31U.
+ */
+static inline void DCDC_SetBandgapVoltageTrimValue(DCDC_Type *base, uint32_t trimValue)
+{
+ base->REG1 &= ~DCDC_REG1_VBG_TRIM_MASK;
+ base->REG1 |= DCDC_REG1_VBG_TRIM(trimValue);
+}
+
+/*!
+ * @brief Get the default setting for loop control configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * @code
+ * config->enableCommonHysteresis = false;
+ * config->enableCommonThresholdDetection = false;
+ * config->enableInvertHysteresisSign = false;
+ * config->enableRCThresholdDetection = false;
+ * config->enableRCScaleCircuit = 0U;
+ * config->complementFeedForwardStep = 0U;
+ * @endcode
+ *
+ * @param config Pointer to configuration structure. See to "dcdc_loop_control_config_t"
+ */
+void DCDC_GetDefaultLoopControlConfig(dcdc_loop_control_config_t *config);
+
+/*!
+ * @brief Configure the DCDC loop control.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to configuration structure. See to "dcdc_loop_control_config_t".
+ */
+void DCDC_SetLoopControlConfig(DCDC_Type *base, const dcdc_loop_control_config_t *config);
+
+/*!
+ * @brief Configure for the min power.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to configuration structure. See to "dcdc_min_power_config_t".
+ */
+void DCDC_SetMinPowerConfig(DCDC_Type *base, const dcdc_min_power_config_t *config);
+
+/*!
+ * @brief Set the current bias of low power comparator.
+ *
+ * @param base DCDC peripheral base address.
+ * @param biasVaule The current bias of low power comparator. Refer to "dcdc_comparator_current_bias_t".
+ */
+static inline void DCDC_SetLPComparatorBiasValue(DCDC_Type *base, dcdc_comparator_current_bias_t biasVaule)
+{
+ base->REG1 &= ~DCDC_REG1_LP_CMP_ISRC_SEL_MASK;
+ base->REG1 |= DCDC_REG1_LP_CMP_ISRC_SEL(biasVaule);
+}
+
+#if (defined(FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT) && (FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT == 2))
+/*!
+ * @brief Lock VDD 1P0 target voltage.
+ *
+ * @param base DCDC peripheral base address.
+ */
+static inline void DCDC_LockVdd1p0TargetVoltage(DCDC_Type *base)
+{
+ base->REG3 |= DCDC_REG3_VDD1P0CTRL_DISABLE_STEP_MASK;
+}
+
+/*!
+ * @brief Lock VDD 1P8 target voltage.
+ *
+ * @param base DCDC peripheral base address.
+ */
+static inline void DCDC_LockVdd1p8TargetVoltage(DCDC_Type *base)
+{
+ base->REG3 |= DCDC_REG3_VDD1P8CTRL_DISABLE_STEP_MASK;
+}
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in run mode and low power mode.
+ * @deprecated Do not use this function. It has been superceded by @ref DCDC_AdjustRunTargetVoltage
+ * and @ref DCDC_AdjustLowPowerTargetVoltage
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * @param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ * @param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t VDDRun, uint32_t VDDStandby, dcdc_voltage_output_sel_t sel);
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in run mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * @param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustRunTargetVoltage(DCDC_Type *base, uint32_t VDDRun, dcdc_voltage_output_sel_t sel);
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in low power mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ * @param sel sel DCDC target voltage output selection. See to "_dcdc_voltage_output_sel".
+ */
+void DCDC_AdjustLowPowerTargetVoltage(DCDC_Type *base, uint32_t VDDStandby, dcdc_voltage_output_sel_t sel);
+#else
+
+/*!
+ * @brief Lock target voltage.
+ *
+ * @param base DCDC peripheral base address.
+ */
+static inline void DCDC_LockTargetVoltage(DCDC_Type *base)
+{
+ base->REG3 |= DCDC_REG3_DISABLE_STEP_MASK;
+}
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in run mode and low power mode.
+ * @deprecated Do not use this function. It has been superceded by @ref DCDC_AdjustRunTargetVoltage
+ * and @ref DCDC_AdjustLowPowerTargetVoltage
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * @param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t VDDRun, uint32_t VDDStandby);
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in run mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ */
+void DCDC_AdjustRunTargetVoltage(DCDC_Type *base, uint32_t VDDRun);
+
+/*!
+ * @brief Adjust the target voltage of VDD_SOC in low power mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * @param base DCDC peripheral base address.
+ * @param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustLowPowerTargetVoltage(DCDC_Type *base, uint32_t VDDStandby);
+#endif /* FSL_FEATURE_DCDC_VDD_OUTPUT_COUNT */
+
+/*!
+ * @brief Configure the DCDC internal regulator.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config Pointer to configuration structure. See to "dcdc_internal_regulator_config_t".
+ */
+void DCDC_SetInternalRegulatorConfig(DCDC_Type *base, const dcdc_internal_regulator_config_t *config);
+
+/*!
+ * @brief Enable/Disable to improve the transition from heavy load to light load. It is valid while zero
+ * cross detection is enabled. If ouput exceeds the threshold, DCDC would return CCM from DCM.
+ *
+ * @param base DCDC peripheral base address.
+ * @param enable Enable the feature or not.
+ */
+static inline void DCDC_EnableImproveTransition(DCDC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->REG2 |= DCDC_REG2_DCM_SET_CTRL_MASK;
+ }
+ else
+ {
+ base->REG2 &= ~DCDC_REG2_DCM_SET_CTRL_MASK;
+ }
+}
+
+/* @} */
+
+#if defined(DCDC_REG4_ENABLE_SP_MASK) && DCDC_REG4_ENABLE_SP_MASK
+/*!
+ * @name Setpoint mode APIs
+ */
+
+/*!
+ * @brief Init DCDC module when the control mode selected as setpoint mode.
+ *
+ * @note The function should be invoked in the initial step to config the
+ * DCDC via setpoint control mode.
+ *
+ * @param base DCDC peripheral base address.
+ * @param config The pointer to the structure @ref dcdc_setpoint_config_t.
+ */
+void DCDC_SetPointInit(DCDC_Type *base, const dcdc_setpoint_config_t *config);
+
+/*!
+ * @brief Disable DCDC module when the control mode selected as setpoint mode.
+ *
+ * @param base DCDC peripheral base address.
+ * @param setpointMap. The map of the setpoint to disable the DCDC module.
+ * Should be the OR'ed value of _dcdc_setpoint_map.
+ */
+static inline void DCDC_SetPointDeinit(DCDC_Type *base, uint32_t setpointMap)
+{
+ base->REG4 &= ~setpointMap;
+}
+
+/* @} */
+#endif /* DCDC_REG4_ENABLE_SP_MASK */
+
+/*!
+ * @name Application guideline
+ * @{
+ */
+
+/*!
+ * @brief Boot DCDC into DCM(discontinous conduction mode).
+ *
+ * pwd_zcd=0x0;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale= 0x5;
+ * DCM_set_ctrl=1'b1;
+ *
+ * @param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoDCM(DCDC_Type *base);
+
+/*!
+ * @brief Boot DCDC into CCM(continous conduction mode).
+ *
+ * pwd_zcd=0x1;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale=0x3;
+ *
+ * @param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoCCM(DCDC_Type *base);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* @} */
+
+#endif /* __FSL_DCDC_H__ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.c b/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.c
new file mode 100644
index 0000000000..87cdf38ea2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dcic.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dcic"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for DCIC module.
+ *
+ * @param base DCIC peripheral base address.
+ */
+static uint32_t DCIC_GetInstance(const DCIC_Type *base);
+
+static void DCIC_ResetRegister(DCIC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to dcic clocks for each instance. */
+static const clock_ip_name_t s_dcicClocks[] = DCIC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DCIC_GetInstance(const DCIC_Type *base)
+{
+ static DCIC_Type *const s_dcicBases[] = DCIC_BASE_PTRS;
+
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dcicBases); instance++)
+ {
+ if (s_dcicBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dcicBases));
+
+ return instance;
+}
+
+#define DCIC_DCCIC_RESET_VALUE (DCIC_DCICC_VSYNC_POL_MASK | DCIC_DCICC_HSYNC_POL_MASK | DCIC_DCICC_DE_POL_MASK)
+#define DCIC_DCICIC_RESET_VALUE (DCIC_DCICIC_FI_MASK_MASK | DCIC_DCICIC_EI_MASK_MASK)
+
+static void DCIC_ResetRegister(DCIC_Type *base)
+{
+ uint32_t i;
+
+ base->DCICC = DCIC_DCCIC_RESET_VALUE;
+ base->DCICIC = DCIC_DCICIC_RESET_VALUE;
+
+ /* Reset region registers. */
+ for (i = 0; i < DCIC_REGION_COUNT; i++)
+ {
+ base->REGION[i].DCICRC = 0UL;
+ base->REGION[i].DCICRS = 0UL;
+ base->REGION[i].DCICRRS = 0UL;
+ }
+
+ /* Clear all status. */
+ base->DCICS = (DCIC_DCICS_EI_STAT_MASK | DCIC_DCICS_FI_STAT_MASK | DCIC_DCICS_ROI_MATCH_STAT_MASK);
+}
+
+/*
+ * brief Initializes the DCIC.
+ *
+ * param base DCIC peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void DCIC_Init(DCIC_Type *base, const dcic_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ /* Enable the clock. */
+ (void)CLOCK_EnableClock(s_dcicClocks[DCIC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ DCIC_ResetRegister(base);
+
+ base->DCICC = config->polarityFlags;
+
+ DCIC_EnableMismatchExternalSignal(base, config->enableExternalSignal);
+ DCIC_EnableInterrupts(base, config->enableInterrupts);
+}
+
+/*
+ * brief Disable the DCIC.
+ *
+ * param base DCIC peripheral base address.
+ */
+void DCIC_Deinit(DCIC_Type *base)
+{
+ base->DCICC = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ /* Disable the clock. */
+ (void)CLOCK_DisableClock(s_dcicClocks[DCIC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * Get the default configuration to initialize DCIC.
+ *
+ * The default configuration is:
+ *
+ config->polarityFlags = kDCIC_VsyncActiveLow | kDCIC_HsyncActiveLow |
+ kDCIC_DataEnableActiveLow | kDCIC_DriveDataOnFallingClkEdge;
+ config->enableExternalSignal = false;
+ config->enableInterrupts = 0;
+ *
+ * param config Pointer to the configuration.
+ */
+void DCIC_GetDefaultConfig(dcic_config_t *config)
+{
+ assert(NULL != config);
+
+ config->polarityFlags = (uint8_t)kDCIC_VsyncActiveLow | (uint8_t)kDCIC_HsyncActiveLow |
+ (uint8_t)kDCIC_DataEnableActiveLow | (uint8_t)kDCIC_DriveDataOnFallingClkEdge;
+ config->enableExternalSignal = false;
+ config->enableInterrupts = 0;
+}
+
+/*
+ * brief Enable the region of interest (ROI) with configuration.
+ *
+ * Enable the ROI with configuration. To change the configuration except reference
+ * CRC value, the region should be disabled first by ref DCIC_DisableRegion,
+ * then call this function again. The reference CRC value could be changed by
+ * ref DCIC_SetRegionRefCrc without disabling the region.
+ * If the configuration is locked, only the reference CRC value could be changed,
+ * the region size and position, enable status could not be changed until reset.
+ *
+ * param base DCIC peripheral base address.
+ * param regionIdx Region index, from 0 to (DCIC_REGION_COUNT - 1).
+ * param config Pointer to the configuration.
+ */
+void DCIC_EnableRegion(DCIC_Type *base, uint8_t regionIdx, const dcic_region_config_t *config)
+{
+ assert(regionIdx < DCIC_REGION_COUNT);
+ assert(NULL != config);
+
+ if (regionIdx < DCIC_REGION_COUNT)
+ {
+ base->REGION[regionIdx].DCICRRS = config->refCrc;
+
+ base->REGION[regionIdx].DCICRS = (((uint32_t)config->lowerRightX << DCIC_DCICRS_END_OFFSET_X_SHIFT) |
+ ((uint32_t)config->lowerRightY << DCIC_DCICRS_END_OFFSET_Y_SHIFT));
+
+ base->REGION[regionIdx].DCICRC = (((uint32_t)config->upperLeftX << DCIC_DCICRC_START_OFFSET_X_SHIFT) |
+ ((uint32_t)config->upperLeftY << DCIC_DCICRC_START_OFFSET_Y_SHIFT) |
+ (config->lock ? DCIC_DCICRC_ROI_FREEZE_MASK : 0UL) | DCIC_DCICRC_ROI_EN_MASK);
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.h b/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.h
new file mode 100644
index 0000000000..eb0fa72dea
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcic/fsl_dcic.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_DCIC_H_
+#define _FSL_DCIC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup DCIC
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#ifndef DCIC_REGION_COUNT
+#define DCIC_REGION_COUNT DCIC_DCICRCS_COUNT
+#endif
+
+/*! @brief DCIC driver version. */
+#define FSL_DCIC_DRIVER_VERSION (MAKE_VERSION(2, 0, 3))
+
+/*! @brief CRC32 calculation polynomial. */
+#define DCIC_CRC32_POLYNOMIAL 0x04C11DB7UL
+
+/*! @brief CRC32 calculation initialize value. */
+#define DCIC_CRC32_INIT_VALUE 0UL
+
+/*! @brief ROI CRC32 value mismatch status. */
+#define DCIC_REGION_MISMATCH_STATUS(region) (1UL << (DCIC_DCICS_ROI_MATCH_STAT_SHIFT + (region)))
+
+/*!
+ * @brief DCIC display signal polarity flags
+ * @anchor _DCIC_polarity_flags
+ */
+enum _DCIC_polarity_flags
+{
+ kDCIC_VsyncActiveHigh = 0U, /*!< VSYNC active high. */
+ kDCIC_HsyncActiveHigh = 0U, /*!< HSYNC active high. */
+ kDCIC_DataEnableActiveHigh = 0U, /*!< Data enable line active high. */
+ kDCIC_DriveDataOnFallingClkEdge = 0U, /*!< Output data on rising clock edge, capture data
+ on falling clock edge. */
+
+ kDCIC_VsyncActiveLow = DCIC_DCICC_VSYNC_POL_MASK, /*!< VSYNC active low. */
+ kDCIC_HsyncActiveLow = DCIC_DCICC_HSYNC_POL_MASK, /*!< HSYNC active low. */
+ kDCIC_DataEnableActiveLow = DCIC_DCICC_DE_POL_MASK, /*!< Data enable line active low. */
+ kDCIC_DriveDataOnRisingClkEdge = DCIC_DCICC_CLK_POL_MASK, /*!< Output data on falling clock edge, capture data
+ on rising clock edge. */
+};
+
+/*!
+ * @brief Status flags.
+ * @anchor _DCIC_status_flags
+ */
+enum _DCIC_status_flags
+{
+ kDCIC_FunctionalInterruptStatus = DCIC_DCICS_FI_STAT_MASK, /*!< Asserted when match results ready. */
+ kDCIC_ErrorInterruptStatus = DCIC_DCICS_EI_STAT_MASK, /*!< Asserted when there is a signature mismatch. */
+ kDCIC_Region0MismatchStatus = DCIC_REGION_MISMATCH_STATUS(0U), /*!< Region 0 CRC32 value mismatch. */
+ kDCIC_Region1MismatchStatus = DCIC_REGION_MISMATCH_STATUS(1U), /*!< Region 1 CRC32 value mismatch. */
+ kDCIC_Region2MismatchStatus = DCIC_REGION_MISMATCH_STATUS(2U), /*!< Region 2 CRC32 value mismatch. */
+ kDCIC_Region3MismatchStatus = DCIC_REGION_MISMATCH_STATUS(3U), /*!< Region 3 CRC32 value mismatch. */
+ kDCIC_Region4MismatchStatus = DCIC_REGION_MISMATCH_STATUS(4U), /*!< Region 4 CRC32 value mismatch. */
+ kDCIC_Region5MismatchStatus = DCIC_REGION_MISMATCH_STATUS(5U), /*!< Region 5 CRC32 value mismatch. */
+ kDCIC_Region6MismatchStatus = DCIC_REGION_MISMATCH_STATUS(6U), /*!< Region 6 CRC32 value mismatch. */
+ kDCIC_Region7MismatchStatus = DCIC_REGION_MISMATCH_STATUS(7U), /*!< Region 7 CRC32 value mismatch. */
+ kDCIC_Region8MismatchStatus = DCIC_REGION_MISMATCH_STATUS(8U), /*!< Region 8 CRC32 value mismatch. */
+ kDCIC_Region9MismatchStatus = DCIC_REGION_MISMATCH_STATUS(9U), /*!< Region 9 CRC32 value mismatch. */
+ kDCIC_Region10MismatchStatus = DCIC_REGION_MISMATCH_STATUS(10U), /*!< Region 10 CRC32 value mismatch. */
+ kDCIC_Region11MismatchStatus = DCIC_REGION_MISMATCH_STATUS(11U), /*!< Region 11 CRC32 value mismatch. */
+ kDCIC_Region12MismatchStatus = DCIC_REGION_MISMATCH_STATUS(12U), /*!< Region 12 CRC32 value mismatch. */
+ kDCIC_Region13MismatchStatus = DCIC_REGION_MISMATCH_STATUS(13U), /*!< Region 13 CRC32 value mismatch. */
+ kDCIC_Region14MismatchStatus = DCIC_REGION_MISMATCH_STATUS(14U), /*!< Region 14 CRC32 value mismatch. */
+ kDCIC_Region15MismatchStatus = DCIC_REGION_MISMATCH_STATUS(15U), /*!< Region 15 CRC32 value mismatch. */
+};
+
+/*!
+ * @brief Interrupts.
+ * @anchor _dcic_interrupt_enable
+ */
+enum _dcic_interrupt_enable
+{
+ kDCIC_FunctionalInterruptEnable = DCIC_DCICIC_FI_MASK_MASK, /*!< Interrupt when match results ready. */
+ kDCIC_ErrorInterruptEnable = DCIC_DCICIC_EI_MASK_MASK, /*!< Interrupt when there is a signature mismatch. */
+};
+
+/*!
+ * @brief DCIC configuration.
+ */
+typedef struct _dcic_config
+{
+ bool enableExternalSignal; /*!< Enable the mismatch external signal. When enabled, the mismatch status could
+ be monitored from the extern pin. */
+ uint8_t polarityFlags; /*!< Display signal polarity, logical OR'ed of @ref _DCIC_polarity_flags. */
+ uint32_t enableInterrupts; /*!< Interrupts to enable, should be OR'ed of @ref _dcic_interrupt_enable. */
+} dcic_config_t;
+
+/*!
+ * @brief Region of interest (ROI) configuration.
+ */
+typedef struct _dcic_region_config
+{
+ bool lock; /*!< Lock the region configuration except reference CRC32 value setting. */
+ uint16_t upperLeftX; /*!< X of upper left corner. Range: 0 to 2^13-1. */
+ uint16_t upperLeftY; /*!< Y of upper left corner. Range: 0 to 2^12-1. */
+ uint16_t lowerRightX; /*!< X of lower right corner. Range: 0 to 2^13-1. */
+ uint16_t lowerRightY; /*!< Y of lower right corner. Range: 0 to 2^12-1. */
+ uint32_t refCrc; /*!< Reference CRC32 value. */
+} dcic_region_config_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the DCIC.
+ *
+ * This function resets DCIC registers to default value, then
+ * set the configurations. This function does not start the
+ * DCIC to work, application should call @ref DCIC_DisableRegion
+ * to configure regions, then call @ref DCIC_Enable to start the
+ * DCIC to work.
+ *
+ * @param base DCIC peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void DCIC_Init(DCIC_Type *base, const dcic_config_t *config);
+
+/*!
+ * @brief Deinitialize the DCIC.
+ *
+ * Disable the DCIC functions.
+ *
+ * @param base DCIC peripheral base address.
+ */
+void DCIC_Deinit(DCIC_Type *base);
+
+/*!
+ * @brief Get the default configuration to initialize DCIC.
+ *
+ * The default configuration is:
+ *
+ * @code
+ config->polarityFlags = kDCIC_VsyncActiveLow | kDCIC_HsyncActiveLow |
+ kDCIC_DataEnableActiveLow | kDCIC_DriveDataOnFallingClkEdge;
+ config->enableExternalSignal = false;
+ config->enableInterrupts = 0;
+ @endcode
+ *
+ * @param config Pointer to the configuration.
+ */
+void DCIC_GetDefaultConfig(dcic_config_t *config);
+
+/*!
+ * @brief Enable or disable the DCIC module.
+ *
+ * @param base DCIC peripheral base address.
+ * @param enable Use true to enable, false to disable.
+ */
+static inline void DCIC_Enable(DCIC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DCICC |= DCIC_DCICC_IC_EN_MASK;
+ }
+ else
+ {
+ base->DCICC &= ~DCIC_DCICC_IC_EN_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Get status flags.
+ *
+ * The flag @ref kDCIC_ErrorInterruptStatus is asserted if any region mismatch
+ * flag asserted.
+ *
+ * @brief base DCIC peripheral base address.
+ * @return Masks of asserted status flags, @ref _DCIC_status_flags.
+ */
+static inline uint32_t DCIC_GetStatusFlags(DCIC_Type *base)
+{
+ return base->DCICS;
+}
+
+/*!
+ * @brief Clear status flags.
+ *
+ * The flag @ref kDCIC_ErrorInterruptStatus should be cleared by clearing all
+ * asserted region mismatch flags.
+ *
+ * @brief base DCIC peripheral base address.
+ * @brief mask Mask of status values that would be cleared, @ref _DCIC_status_flags.
+ */
+static inline void DCIC_ClearStatusFlags(DCIC_Type *base, uint32_t mask)
+{
+ base->DCICS = (mask & (DCIC_DCICS_FI_STAT_MASK | DCIC_DCICS_ROI_MATCH_STAT_MASK));
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Lock the interrupt enabled status.
+ *
+ * Once this function is called, the interrupt enabled status could not be changed
+ * until reset.
+ *
+ * @param base DCIC peripheral base address.
+ */
+static inline void DCIC_LockInterruptEnabledStatus(DCIC_Type *base)
+{
+ base->DCICIC |= DCIC_DCICIC_FREEZE_MASK_MASK;
+}
+
+/*!
+ * @brief Enable interrupts.
+ *
+ * @param base DCIC peripheral base address.
+ * @param mask Mask of interrupt events that would be enabled. See to "_dcic_interrupt_enable_t".
+ */
+static inline void DCIC_EnableInterrupts(DCIC_Type *base, uint32_t mask)
+{
+ base->DCICIC &= ~mask;
+}
+
+/*!
+ * @brief Disable interrupts.
+ *
+ * @param base DCIC peripheral base address.
+ * @param mask Mask of interrupt events that would be disabled. See to "_dcic_interrupt_enable_t".
+ */
+static inline void DCIC_DisableInterrupts(DCIC_Type *base, uint32_t mask)
+{
+ base->DCICIC |= mask;
+}
+
+/* @} */
+
+/*!
+ * @name Region
+ * @{
+ */
+
+/*!
+ * @brief Enable the region of interest (ROI) with configuration.
+ *
+ * Enable the ROI with configuration. To change the configuration except reference
+ * CRC value, the region should be disabled first by @ref DCIC_DisableRegion,
+ * then call this function again. The reference CRC value could be changed by
+ * @ref DCIC_SetRegionRefCrc without disabling the region.
+ * If the configuration is locked, only the reference CRC value could be changed,
+ * the region size and position, enable status could not be changed until reset.
+ *
+ * @param base DCIC peripheral base address.
+ * @param regionIdx Region index, from 0 to (DCIC_REGION_COUNT - 1).
+ * @param config Pointer to the configuration.
+ */
+void DCIC_EnableRegion(DCIC_Type *base, uint8_t regionIdx, const dcic_region_config_t *config);
+
+/*!
+ * @brief Disable the region of interest (ROI).
+ *
+ * @param base DCIC peripheral base address.
+ * @param regionIdx Region index, from 0 to (DCIC_REGION_COUNT - 1).
+ */
+static inline void DCIC_DisableRegion(DCIC_Type *base, uint8_t regionIdx)
+{
+ assert(regionIdx < DCIC_REGION_COUNT);
+
+ if (regionIdx < DCIC_REGION_COUNT)
+ {
+ base->REGION[regionIdx].DCICRC &= ~DCIC_DCICRC_ROI_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Set the reference CRC of interest (ROI).
+ *
+ * @param base DCIC peripheral base address.
+ * @param regionIdx Region index, from 0 to (DCIC_REGION_COUNT - 1).
+ * @param crc The reference CRC value.
+ */
+static inline void DCIC_SetRegionRefCrc(DCIC_Type *base, uint8_t regionIdx, uint32_t crc)
+{
+ assert(regionIdx < DCIC_REGION_COUNT);
+
+ if (regionIdx < DCIC_REGION_COUNT)
+ {
+ base->REGION[regionIdx].DCICRRS = crc;
+ }
+}
+
+/*!
+ * @brief Get the DCIC calculated CRC.
+ *
+ * @param base DCIC peripheral base address.
+ * @param regionIdx Region index, from 0 to (DCIC_REGION_COUNT - 1).
+ * @return The calculated CRC value.
+ */
+static inline uint32_t DCIC_GetRegionCalculatedCrc(DCIC_Type *base, uint8_t regionIdx)
+{
+ uint32_t localdcicrcs = 0U;
+
+ assert(regionIdx < DCIC_REGION_COUNT);
+
+ if (regionIdx < DCIC_REGION_COUNT)
+ {
+ localdcicrcs = base->REGION[regionIdx].DCICRCS;
+ }
+
+ return localdcicrcs;
+}
+
+/* @} */
+
+/*!
+ * @name Misc control.
+ * @{
+ */
+
+/*!
+ * @brief Enable or disable output the mismatch external signal.
+ *
+ * The mismatch status can be output to external pins. If enabled:
+ * - If @ref kDCIC_ErrorInterruptStatus asserted, the output signal
+ * frequency is DCIC clock / 16.
+ * - If @ref kDCIC_ErrorInterruptStatus not asserted, the output signal
+ * frequency is DCIC clock / 4.
+ * - If integrity check is disabled, the signal is idle.
+ *
+ * @param base DCIC peripheral base address.
+ * @param enable. Use true to enable, false to disable.
+ */
+static inline void DCIC_EnableMismatchExternalSignal(DCIC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DCICIC |= DCIC_DCICIC_EXT_SIG_EN_MASK;
+ }
+ else
+ {
+ base->DCICIC &= ~DCIC_DCICIC_EXT_SIG_EN_MASK;
+ }
+}
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_DCIC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.c b/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.c
new file mode 100644
index 0000000000..a0b82bae1c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dcp.h"
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+#include "fsl_cache.h"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dcp"
+#endif
+
+/*! Compile time sizeof() check */
+#define BUILD_ASSURE(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused))
+
+#define dcp_memcpy memcpy
+
+/*! Internal states of the HASH creation process */
+typedef enum _dcp_hash_algo_state
+{
+ kDCP_StateHashInit = 1u, /*!< Init state. */
+ kDCP_StateHashUpdate, /*!< Update state. */
+} dcp_hash_algo_state_t;
+
+/*! multiple of 64-byte block represented as byte array of 32-bit words */
+typedef union _dcp_hash_block
+{
+ uint32_t w[DCP_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */
+ uint8_t b[DCP_HASH_BLOCK_SIZE]; /*!< byte array */
+} dcp_hash_block_t;
+
+/*! internal dcp_hash context structure */
+typedef struct _dcp_hash_ctx_internal
+{
+ dcp_hash_block_t blk; /*!< memory buffer. only full blocks are written to DCP during hash updates */
+ size_t blksz; /*!< number of valid bytes in memory buffer */
+ dcp_hash_algo_t algo; /*!< selected algorithm from the set of supported algorithms */
+ dcp_hash_algo_state_t state; /*!< finite machine state of the hash software process */
+ uint32_t fullMessageSize; /*!< track message size */
+ uint32_t ctrl0; /*!< HASH_INIT and HASH_TERM flags */
+ uint32_t runningHash[9]; /*!< running hash. up to SHA-256 plus size, that is 36 bytes. */
+ dcp_handle_t *handle;
+} dcp_hash_ctx_internal_t;
+
+/*!< SHA-1/SHA-2 digest length in bytes */
+enum _dcp_hash_digest_len
+{
+ kDCP_OutLenSha1 = 20u,
+ kDCP_OutLenSha256 = 32u,
+ kDCP_OutLenCrc32 = 4u,
+};
+
+enum _dcp_work_packet_bit_definitions
+{
+ kDCP_CONTROL0_DECR_SEMAPHOR = 1u << 1, /* DECR_SEMAPHOR */
+ kDCP_CONTROL0_ENABLE_HASH = 1u << 6, /* ENABLE_HASH */
+ kDCP_CONTROL0_HASH_INIT = 1u << 12, /* HASH_INIT */
+ kDCP_CONTROL0_HASH_TERM = 1u << 13, /* HASH_TERM */
+ kDCP_CONTROL1_HASH_SELECT_SHA256 = 2u << 16,
+ kDCP_CONTROL1_HASH_SELECT_SHA1 = 0u << 16,
+ kDCP_CONTROL1_HASH_SELECT_CRC32 = 1u << 16,
+};
+
+/*! 64-byte block represented as byte array of 16 32-bit words */
+typedef union _dcp_sha_block
+{
+ uint32_t w[64 / 4]; /*!< array of 32-bit words */
+ uint8_t b[64]; /*!< byte array */
+} dcp_sha_block_t;
+
+#if defined(DCP_HASH_CAVP_COMPATIBLE)
+/* result of sha1 hash for message with zero size */
+static uint8_t s_nullSha1[] = {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
+ 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09};
+/* result of sha256 hash for message with zero size */
+static uint8_t s_nullSha256[] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
+ 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
+ 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
+#endif /* DCP_HASH_CAVP_COMPATIBLE */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+AT_NONCACHEABLE_SECTION_INIT(static dcp_context_t s_dcpContextSwitchingBuffer);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void dcp_reverse_and_copy(uint8_t *src, uint8_t *dest, size_t src_len)
+{
+ for (uint32_t i = 0; i < src_len; i++)
+ {
+ dest[i] = src[src_len - 1U - i];
+ }
+}
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+static inline uint32_t *DCP_FindCacheLine(uint8_t *dcpWorkExt)
+{
+ while (0U != ((uint32_t)dcpWorkExt & ((uint32_t)FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1U)))
+ {
+ dcpWorkExt++;
+ }
+ return (uint32_t *)(uint32_t)dcpWorkExt;
+}
+#endif
+
+static status_t dcp_get_channel_status(DCP_Type *base, dcp_channel_t channel)
+{
+ uint32_t statReg = 0;
+ uint32_t semaReg = 0;
+ status_t status = kStatus_Fail;
+
+ switch (channel)
+ {
+ case kDCP_Channel0:
+ statReg = base->CH0STAT;
+ semaReg = base->CH0SEMA;
+ break;
+
+ case kDCP_Channel1:
+ statReg = base->CH1STAT;
+ semaReg = base->CH1SEMA;
+ break;
+
+ case kDCP_Channel2:
+ statReg = base->CH2STAT;
+ semaReg = base->CH2SEMA;
+ break;
+
+ case kDCP_Channel3:
+ statReg = base->CH3STAT;
+ semaReg = base->CH3SEMA;
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ if (!((0U != (semaReg & DCP_CH0SEMA_VALUE_MASK)) || (0U != (statReg & DCP_CH0STAT_ERROR_CODE_MASK))))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static void dcp_clear_status(DCP_Type *base)
+{
+ volatile uint32_t *dcpStatClrPtr = (volatile uint32_t *)&base->STAT + 2u;
+ *dcpStatClrPtr = 0xFFu;
+
+ while ((base->STAT & 0xffu) != 0U)
+ {
+ }
+}
+
+static void dcp_clear_channel_status(DCP_Type *base, uint32_t mask)
+{
+ volatile uint32_t *chStatClrPtr;
+
+ if (0U != (mask & (uint32_t)kDCP_Channel0))
+ {
+ chStatClrPtr = &base->CH0STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel1))
+ {
+ chStatClrPtr = &base->CH1STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel2))
+ {
+ chStatClrPtr = &base->CH2STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel3))
+ {
+ chStatClrPtr = &base->CH3STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+}
+
+static status_t dcp_aes_set_sram_based_key(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key)
+{
+ base->KEY = DCP_KEY_INDEX(handle->keySlot) | DCP_KEY_SUBWORD(0);
+ /* move the key by 32-bit words */
+ int i = 0;
+ size_t keySize = 16u;
+ while (keySize != 0U)
+ {
+ keySize -= sizeof(uint32_t);
+ base->KEYDATA = ((uint32_t *)(uintptr_t)key)[i];
+ i++;
+ }
+ return kStatus_Success;
+}
+
+/* Disable optimizations for GCC to prevent instruction reordering */
+#if defined(__GNUC__)
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+#endif
+static status_t dcp_schedule_work(DCP_Type *base, dcp_handle_t *handle, dcp_work_packet_t *dcpPacket)
+{
+ status_t status;
+
+ /* check if our channel is active */
+ if ((base->STAT & (uint32_t)handle->channel) != (uint32_t)handle->channel)
+ {
+ /* disable global interrupt */
+ uint32_t currPriMask = DisableGlobalIRQ();
+
+ /* re-check if our channel is still available */
+ if ((base->STAT & (uint32_t)handle->channel) == 0U)
+ {
+ volatile uint32_t *cmdptr = NULL;
+ volatile uint32_t *chsema = NULL;
+
+ switch (handle->channel)
+ {
+ case kDCP_Channel0:
+ cmdptr = &base->CH0CMDPTR;
+ chsema = &base->CH0SEMA;
+ break;
+
+ case kDCP_Channel1:
+ cmdptr = &base->CH1CMDPTR;
+ chsema = &base->CH1SEMA;
+ break;
+
+ case kDCP_Channel2:
+ cmdptr = &base->CH2CMDPTR;
+ chsema = &base->CH2SEMA;
+ break;
+
+ case kDCP_Channel3:
+ cmdptr = &base->CH3CMDPTR;
+ chsema = &base->CH3SEMA;
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ if ((NULL != cmdptr) && (NULL != chsema))
+ {
+ /* set out packet to DCP CMDPTR */
+ *cmdptr = (uint32_t)dcpPacket;
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clean DCACHE before sending DCP packet to engine */
+ DCACHE_CleanByRange((uint32_t)dcpPacket, sizeof(dcp_work_packet_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+
+ /* set the channel semaphore to start the job */
+ *chsema = 1u;
+ }
+
+ status = kStatus_Success;
+ }
+
+ else
+ {
+ status = (int32_t)kStatus_DCP_Again;
+ }
+ /* global interrupt enable */
+ EnableGlobalIRQ(currPriMask);
+ }
+
+ else
+ {
+ return (int32_t)kStatus_DCP_Again;
+ }
+
+ return status;
+}
+#if defined(__GNUC__)
+#pragma GCC pop_options
+#endif
+
+/*!
+ * brief Set AES key to dcp_handle_t struct and optionally to DCP.
+ *
+ * Sets the AES key for encryption/decryption with the dcp_handle_t structure.
+ * The dcp_handle_t input argument specifies keySlot.
+ * If the keySlot is kDCP_OtpKey, the function will check the OTP_KEY_READY bit and will return it's ready to use
+ * status.
+ * For other keySlot selections, the function will copy and hold the key in dcp_handle_t struct.
+ * If the keySlot is one of the four DCP SRAM-based keys (one of kDCP_KeySlot0, kDCP_KeySlot1, kDCP_KeySlot2,
+ * kDCP_KeySlot3),
+ * this function will also load the supplied key to the specified keySlot in DCP.
+ *
+ * param base DCP peripheral base address.
+ * param handle Handle used for the request.
+ * param key 0-mod-4 aligned pointer to AES key.
+ * param keySize AES key size in bytes. Shall equal 16.
+ * return status from set key operation
+ */
+status_t DCP_AES_SetKey(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key, size_t keySize)
+{
+ status_t status = kStatus_Fail;
+
+ if ((kDCP_OtpKey == handle->keySlot) || (kDCP_OtpUniqueKey == handle->keySlot))
+ {
+ /* for AES OTP and unique key, check and return read from fuses status */
+ if ((base->STAT & DCP_STAT_OTP_KEY_READY_MASK) == DCP_STAT_OTP_KEY_READY_MASK)
+ {
+ status = kStatus_Success;
+ }
+ }
+ else
+ {
+ /* only work with aligned key[] */
+ if ((0x3U & (uintptr_t)key) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* keySize must be 16. */
+ if (keySize != 16U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* move the key by 32-bit words */
+ int i = 0;
+ while (keySize != 0U)
+ {
+ keySize -= sizeof(uint32_t);
+ handle->keyWord[i] = ((uint32_t *)(uintptr_t)key)[i];
+ i++;
+ }
+
+ if (kDCP_PayloadKey != handle->keySlot)
+ {
+ /* move the key by 32-bit words to DCP SRAM-based key storage */
+ status = dcp_aes_set_sram_based_key(base, handle, key);
+ }
+ else
+ {
+ /* for PAYLOAD_KEY, just return Ok status now */
+ status = kStatus_Success;
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Encrypts AES on one or multiple 128-bit block(s).
+ *
+ * Encrypts AES.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_EncryptEcbNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Encrypts AES using the ECB block mode.
+ *
+ * Puts AES ECB encrypt work packet to DCP channel.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param plaintext Input plain text to encrypt.
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 =
+ 0x122u | (handle->swapConfig & 0xFC0000u); /* CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->sourceBufferAddress = (uint32_t)plaintext;
+ dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Decrypts AES on one or multiple 128-bit block(s).
+ *
+ * Decrypts AES.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param ciphertext Input plain text to encrypt
+ * param[out] plaintext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_DecryptEcbNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size);
+ } while (completionStatus == (int32_t)(kStatus_DCP_Again));
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Decrypts AES using ECB block mode.
+ *
+ * Puts AES ECB decrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 = 0x22u | (handle->swapConfig & 0xFC0000u); /* ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->sourceBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Encrypts AES using CBC block mode.
+ *
+ * Encrypts AES using CBC block mode.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t iv[16])
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_EncryptCbcNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size, iv);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Encrypts AES using CBC block mode.
+ *
+ * Puts AES CBC encrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request. Specifies jobRing.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t *iv)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 =
+ 0x322u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->control1 = 0x10u; /* CBC */
+ dcpPacket->sourceBufferAddress = (uint32_t)plaintext;
+ dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* In this case payload must contain key & iv in one array. */
+ /* Copy iv into handle right behind the keyWord[] so we can point payload to keyWord[]. */
+ (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Decrypts AES using CBC block mode.
+ *
+ * Decrypts AES using CBC block mode.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t iv[16])
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_DecryptCbcNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size, iv);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != (int32_t)kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Decrypts AES using CBC block mode.
+ *
+ * Puts AES CBC decrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request. Specifies jobRing.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t *iv)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 = 0x222u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->control1 = 0x10u; /* CBC */
+ dcpPacket->sourceBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* in this case payload must contain KEY + IV together */
+ /* copy iv into handle struct so we can point payload directly to keyWord[]. */
+ (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the DCP configuration structure to a default value. The default
+ * values are as follows.
+ * dcpConfig->gatherResidualWrites = true;
+ * dcpConfig->enableContextCaching = true;
+ * dcpConfig->enableContextSwitching = true;
+ * dcpConfig->enableChannnel = kDCP_chEnableAll;
+ * dcpConfig->enableChannelInterrupt = kDCP_chIntDisable;
+ *
+ * param[out] config Pointer to configuration structure.
+ */
+void DCP_GetDefaultConfig(dcp_config_t *config)
+{
+ /* ENABLE_CONTEXT_CACHING is disabled by default as the DCP Hash driver uses
+ * dcp_hash_save_running_hash() and dcp_hash_restore_running_hash() to support
+ * Hash context switch (different messages interleaved) on the same channel.
+ */
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ dcp_config_t userConfig = {
+ true, false, true, (uint8_t)kDCP_chEnableAll, (uint8_t)kDCP_chIntDisable,
+ };
+
+ *config = userConfig;
+}
+
+/*!
+ * brief Enables clock to and enables DCP
+ *
+ * Enable DCP clock and configure DCP.
+ *
+ * param base DCP base address
+ * param config Pointer to configuration structure.
+ */
+void DCP_Init(DCP_Type *base, const dcp_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Dcp);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ base->CTRL = 0xF0800000u; /* reset value */
+ base->CTRL = 0x30800000u; /* default value */
+
+ dcp_clear_status(base);
+ dcp_clear_channel_status(
+ base, (uint32_t)kDCP_Channel0 | (uint32_t)kDCP_Channel1 | (uint32_t)kDCP_Channel2 | (uint32_t)kDCP_Channel3);
+
+ base->CTRL = DCP_CTRL_GATHER_RESIDUAL_WRITES(config->gatherResidualWrites) |
+ DCP_CTRL_ENABLE_CONTEXT_CACHING(config->enableContextCaching) |
+ DCP_CTRL_ENABLE_CONTEXT_SWITCHING(config->enableContextSwitching) |
+ DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(config->enableChannelInterrupt);
+
+ /* enable DCP channels */
+ base->CHANNELCTRL = DCP_CHANNELCTRL_ENABLE_CHANNEL(config->enableChannel);
+
+ /* use context switching buffer */
+ base->CONTEXT = (uint32_t)&s_dcpContextSwitchingBuffer;
+}
+
+/*!
+ * brief Disable DCP clock
+ *
+ * Reset DCP and Disable DCP clock.
+ *
+ * param base DCP base address
+ */
+void DCP_Deinit(DCP_Type *base)
+{
+ base->CTRL = 0xF0800000u; /* reset value */
+ (void)memset(&s_dcpContextSwitchingBuffer, 0, sizeof(s_dcpContextSwitchingBuffer));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Dcp);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Poll and wait on DCP channel.
+ *
+ * Polls the specified DCP channel until current it completes activity.
+ *
+ * param base DCP peripheral base address.
+ * param handle Specifies DCP channel.
+ * return kStatus_Success When data processing completes without error.
+ * return kStatus_Fail When error occurs.
+ */
+status_t DCP_WaitForChannelComplete(DCP_Type *base, dcp_handle_t *handle)
+{
+ /* wait if our channel is still active */
+ while ((base->STAT & (uint32_t)handle->channel) == (uint32_t)handle->channel)
+ {
+ }
+
+ if (dcp_get_channel_status(base, handle->channel) != kStatus_Success)
+ {
+ dcp_clear_status(base);
+ dcp_clear_channel_status(base, (uint32_t)handle->channel);
+ return kStatus_Fail;
+ }
+
+ dcp_clear_status(base);
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of algoritm.
+ *
+ * This function checks the validity of input argument.
+ *
+ * @param algo Tested algorithm value.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_input_alg(dcp_hash_algo_t algo)
+{
+ if ((algo != kDCP_Sha256) && (algo != kDCP_Sha1) && (algo != kDCP_Crc32))
+ {
+ return kStatus_InvalidArgument;
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of input arguments.
+ *
+ * This function checks the validity of input arguments.
+ *
+ * @param base DCP peripheral base address.
+ * @param ctx Memory buffer given by user application where the DCP_HASH_Init/DCP_HASH_Update/DCP_HASH_Finish store
+ * context.
+ * @param algo Tested algorithm value.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_input_args(DCP_Type *base, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
+{
+ /* Check validity of input algorithm */
+ if (kStatus_Success != dcp_hash_check_input_alg(algo))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((NULL == ctx) || (NULL == base))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of internal software context.
+ *
+ * This function checks if the internal context structure looks correct.
+ *
+ * @param ctxInternal Internal context.
+ * @param message Input message address.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_context(dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *message)
+{
+ if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != dcp_hash_check_input_alg(ctxInternal->algo)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Initialize the SHA engine for new hash.
+ *
+ * This function sets kDCP_CONTROL0_HASH_INIT for control0 in work packet to start a new hash.
+ *
+ * @param base SHA peripheral base address.
+ * @param ctxInternal Internal context.
+ */
+static status_t dcp_hash_engine_init(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
+{
+ status_t status;
+
+ status = kStatus_InvalidArgument;
+
+ if ((kDCP_Sha256 == ctxInternal->algo) || (kDCP_Sha1 == ctxInternal->algo) || (kDCP_Crc32 == ctxInternal->algo))
+ {
+ ctxInternal->ctrl0 = (uint32_t)kDCP_CONTROL0_HASH_INIT;
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static status_t dcp_hash_update_non_blocking(
+ DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, dcp_work_packet_t *dcpPacket, const uint8_t *msg, size_t size)
+{
+ dcpPacket->control0 = ctxInternal->ctrl0 | (ctxInternal->handle->swapConfig & 0xFC0000u) |
+ (uint32_t)kDCP_CONTROL0_ENABLE_HASH | (uint32_t)kDCP_CONTROL0_DECR_SEMAPHOR;
+ if (ctxInternal->algo == kDCP_Sha256)
+ {
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA256;
+ }
+ else if (ctxInternal->algo == kDCP_Sha1)
+ {
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA1;
+ }
+ else if (ctxInternal->algo == kDCP_Crc32)
+ {
+ /* In CRC-32 case if size is zero, do not schedule other computing */
+ if (size == 0U)
+ {
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clear DCACHE memory before starting the engine */
+ DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+ return kStatus_Success;
+ }
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_CRC32;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+ dcpPacket->sourceBufferAddress = (uint32_t)msg;
+ dcpPacket->destinationBufferAddress = 0;
+ dcpPacket->bufferSize = size;
+ dcpPacket->payloadPointer = (uint32_t)ctxInternal->runningHash;
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clear DCACHE memory before starting the engine */
+ DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+
+ return dcp_schedule_work(base, ctxInternal->handle, dcpPacket);
+}
+
+static status_t dcp_hash_update(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *msg, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = dcp_hash_update_non_blocking(base, ctxInternal, dcpWork, msg, size);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ completionStatus = DCP_WaitForChannelComplete(base, ctxInternal->handle);
+
+ ctxInternal->ctrl0 = 0; /* clear kDCP_CONTROL0_HASH_INIT and kDCP_CONTROL0_HASH_TERM flags */
+ return (completionStatus);
+}
+
+/*!
+ * @brief Adds message to current hash.
+ *
+ * This function merges the message to fill the internal buffer, empties the internal buffer if
+ * it becomes full, then process all remaining message data.
+ *
+ *
+ * @param base DCP peripheral base address.
+ * @param ctxInternal Internal context.
+ * @param message Input message.
+ * @param messageSize Size of input message in bytes.
+ * @return kStatus_Success.
+ */
+static status_t dcp_hash_process_message_data(DCP_Type *base,
+ dcp_hash_ctx_internal_t *ctxInternal,
+ const uint8_t *message,
+ size_t messageSize)
+{
+ status_t status = kStatus_Fail;
+
+ /* if there is partially filled internal buffer, fill it to full block */
+ if (ctxInternal->blksz > 0U)
+ {
+ size_t toCopy = DCP_HASH_BLOCK_SIZE - ctxInternal->blksz;
+ (void)dcp_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
+ message += toCopy;
+ messageSize -= toCopy;
+
+ /* process full internal block */
+ status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], DCP_HASH_BLOCK_SIZE);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ }
+
+ /* process all full blocks in message[] */
+ uint32_t fullBlocksSize = ((messageSize >> 6) << 6); /* (X / 64) * 64 */
+ if (fullBlocksSize > 0U)
+ {
+ status = dcp_hash_update(base, ctxInternal, message, fullBlocksSize);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ message += fullBlocksSize;
+ messageSize -= fullBlocksSize;
+ }
+
+ /* copy last incomplete message bytes into internal block */
+ (void)dcp_memcpy(&ctxInternal->blk.b[0], message, messageSize);
+ ctxInternal->blksz = messageSize;
+
+ return status;
+}
+
+/*!
+ * @brief Finalize the running hash to make digest.
+ *
+ * This function empties the internal buffer, adds padding bits, and generates final digest.
+ *
+ * @param base SHA peripheral base address.
+ * @param ctxInternal Internal context.
+ * @return kStatus_Success.
+ */
+static status_t dcp_hash_finalize(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
+{
+ status_t status;
+
+ ctxInternal->ctrl0 |= (uint32_t)kDCP_CONTROL0_HASH_TERM;
+ status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], ctxInternal->blksz);
+
+ return status;
+}
+
+static void dcp_hash_save_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
+{
+ uint32_t *srcAddr = NULL;
+
+ switch (ctxInternal->handle->channel)
+ {
+ case kDCP_Channel0:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[43];
+ break;
+
+ case kDCP_Channel1:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[30];
+ break;
+
+ case kDCP_Channel2:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[17];
+ break;
+
+ case kDCP_Channel3:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[4];
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ if (srcAddr != NULL)
+ {
+ DCACHE_InvalidateByRange((uint32_t)srcAddr, sizeof(ctxInternal->runningHash));
+ (void)dcp_memcpy(ctxInternal->runningHash, srcAddr, sizeof(ctxInternal->runningHash));
+ }
+}
+
+static void dcp_hash_restore_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
+{
+ uint32_t *destAddr = NULL;
+
+ switch (ctxInternal->handle->channel)
+ {
+ case kDCP_Channel0:
+ destAddr = &s_dcpContextSwitchingBuffer.x[43];
+ break;
+
+ case kDCP_Channel1:
+ destAddr = &s_dcpContextSwitchingBuffer.x[30];
+ break;
+
+ case kDCP_Channel2:
+ destAddr = &s_dcpContextSwitchingBuffer.x[17];
+ break;
+
+ case kDCP_Channel3:
+ destAddr = &s_dcpContextSwitchingBuffer.x[4];
+ break;
+
+ default:
+ /* No valid channel */
+ break;
+ }
+ if (destAddr != NULL)
+ {
+ (void)dcp_memcpy(destAddr, ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
+ }
+}
+
+/*!
+ * brief Initialize HASH context
+ *
+ * This function initializes the HASH.
+ *
+ * param base DCP peripheral base address
+ * param handle Specifies the DCP channel used for hashing.
+ * param[out] ctx Output hash context
+ * param algo Underlaying algorithm to use for hash computation.
+ * return Status of initialization
+ */
+status_t DCP_HASH_Init(DCP_Type *base, dcp_handle_t *handle, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
+{
+ status_t status;
+
+ dcp_hash_ctx_internal_t *ctxInternal;
+ /* Align structure on DCACHE line*/
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
+#else
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+#endif
+
+ /* compile time check for the correct structure size */
+ BUILD_ASSURE(sizeof(dcp_hash_ctx_t) >= sizeof(dcp_hash_ctx_internal_t), dcp_hash_ctx_t_size);
+ uint32_t i;
+
+ status = dcp_hash_check_input_args(base, ctx, algo);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ /* set algorithm in context struct for later use */
+ ctxInternal->algo = algo;
+ ctxInternal->blksz = 0u;
+
+ const uint32_t j = sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]);
+ for (i = 0; i < j; i++)
+ {
+ ctxInternal->blk.w[i] = 0u;
+ }
+ ctxInternal->state = kDCP_StateHashInit;
+ ctxInternal->fullMessageSize = 0;
+ ctxInternal->handle = handle;
+ return status;
+}
+
+/*!
+ * brief Add data to current HASH
+ *
+ * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
+ * hashed. The functions blocks. If it returns kStatus_Success, the running hash
+ * has been updated (DCP has processed the input data), so the memory at ref input pointer
+ * can be released back to system. The DCP context buffer is updated with the running hash
+ * and with all necessary information to support possible context switch.
+ *
+ * param base DCP peripheral base address
+ * param[in,out] ctx HASH context
+ * param input Input data
+ * param inputSize Size of input data in bytes
+ * return Status of the hash update operation
+ */
+status_t DCP_HASH_Update(DCP_Type *base, dcp_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize)
+{
+ bool isUpdateState;
+ status_t status;
+ dcp_hash_ctx_internal_t *ctxInternal;
+ size_t blockSize;
+
+ /* Align structure on DCACHE line*/
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
+#else
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+#endif
+
+ if (inputSize == 0U)
+ {
+ return kStatus_Success;
+ }
+
+ status = dcp_hash_check_context(ctxInternal, input);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+
+ ctxInternal->fullMessageSize += inputSize;
+ blockSize = DCP_HASH_BLOCK_SIZE;
+ /* if we are still less than DCP_HASH_BLOCK_SIZE bytes, keep only in context */
+ if ((ctxInternal->blksz + inputSize) <= blockSize)
+ {
+ (void)dcp_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize);
+ ctxInternal->blksz += inputSize;
+ return status;
+ }
+ else
+ {
+ isUpdateState = ctxInternal->state == kDCP_StateHashUpdate;
+ if (!isUpdateState)
+ {
+ /* start NEW hash */
+ status = dcp_hash_engine_init(base, ctxInternal);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+ ctxInternal->state = kDCP_StateHashUpdate;
+ }
+ else
+ {
+ dcp_hash_restore_running_hash(ctxInternal);
+ }
+ }
+
+ /* process input data */
+ status = dcp_hash_process_message_data(base, ctxInternal, input, inputSize);
+ dcp_hash_save_running_hash(ctxInternal);
+ return status;
+}
+
+/*!
+ * brief Finalize hashing
+ *
+ * Outputs the final hash (computed by DCP_HASH_Update()) and erases the context.
+ *
+ * param[in,out] ctx Input hash context
+ * param[out] output Output hash data
+ * param[in,out] outputSize Optional parameter (can be passed as NULL). On function entry, it specifies the size of
+ * output[] buffer. On function return, it stores the number of updated output bytes.
+ * return Status of the hash finish operation
+ */
+status_t DCP_HASH_Finish(DCP_Type *base, dcp_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize)
+{
+ size_t algOutSize = 0;
+ status_t status;
+ dcp_hash_ctx_internal_t *ctxInternal;
+
+ /* Align structure on DCACHE line*/
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
+#else
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+#endif
+
+ status = dcp_hash_check_context(ctxInternal, output);
+
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+
+ if (ctxInternal->state == kDCP_StateHashInit)
+ {
+ status = dcp_hash_engine_init(base, ctxInternal);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+ }
+ else
+ {
+ dcp_hash_restore_running_hash(ctxInternal);
+ }
+
+ size_t outSize = 0u;
+
+ /* compute algorithm output length */
+ switch (ctxInternal->algo)
+ {
+ case kDCP_Sha256:
+ outSize = (uint32_t)kDCP_OutLenSha256;
+ break;
+ case kDCP_Sha1:
+ outSize = (uint32_t)kDCP_OutLenSha1;
+ break;
+ case kDCP_Crc32:
+ outSize = (uint32_t)kDCP_OutLenCrc32;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ algOutSize = outSize;
+
+#if defined(DCP_HASH_CAVP_COMPATIBLE)
+ if (ctxInternal->fullMessageSize == 0U)
+ {
+ switch (ctxInternal->algo)
+ {
+ case kDCP_Sha256:
+ (void)dcp_memcpy(&output[0], &s_nullSha256, 32);
+ break;
+ case kDCP_Sha1:
+ (void)dcp_memcpy(&output[0], &s_nullSha1, 20);
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ return kStatus_Success;
+ }
+#endif /* DCP_HASH_CAVP_COMPATIBLE */
+
+ /* flush message last incomplete block, if there is any, and add padding bits */
+ status = dcp_hash_finalize(base, ctxInternal);
+
+ if (outputSize != NULL)
+ {
+ if (algOutSize < *outputSize)
+ {
+ *outputSize = algOutSize;
+ }
+ else
+ {
+ algOutSize = *outputSize;
+ }
+ }
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ DCACHE_InvalidateByRange((uint32_t)ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
+#endif
+ /* Reverse and copy result to output[] */
+ dcp_reverse_and_copy((uint8_t *)ctxInternal->runningHash, &output[0], algOutSize);
+
+ (void)memset(ctx, 0, sizeof(dcp_hash_ctx_t));
+ return status;
+}
+
+/*!
+ * brief Create HASH on given data
+ *
+ * Perform the full SHA or CRC32 in one function call. The function is blocking.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for the request.
+ * param algo Underlaying algorithm to use for hash computation.
+ * param input Input data
+ * param inputSize Size of input data in bytes
+ * param[out] output Output hash data
+ * param[out] outputSize Output parameter storing the size of the output hash in bytes
+ * return Status of the one call hash operation.
+ */
+status_t DCP_HASH(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_hash_algo_t algo,
+ const uint8_t *input,
+ size_t inputSize,
+ uint8_t *output,
+ size_t *outputSize)
+{
+ dcp_hash_ctx_t hashCtx = {0};
+ status_t status;
+
+ status = DCP_HASH_Init(base, handle, &hashCtx, algo);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ status = DCP_HASH_Update(base, &hashCtx, input, inputSize);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ status = DCP_HASH_Finish(base, &hashCtx, output, outputSize);
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.h b/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.h
new file mode 100644
index 0000000000..b31944ddc5
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dcp/fsl_dcp.h
@@ -0,0 +1,580 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_DCP_H_
+#define _FSL_DCP_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*!
+ * @addtogroup dcp_driver
+ * @{
+ */
+/*! @name Driver version */
+/*@{*/
+/*! @brief DCP driver version. Version 2.1.6.
+ *
+ * Current version: 2.1.6
+ *
+ * Change log:
+ *
+ * - Version 2.1.6
+ * - Bug Fix
+ * - MISRA C-2012 issue fix.
+ *
+ * - Version 2.1.5
+ * - Improvements
+ * - Add support for DCACHE.
+ *
+ * - Version 2.1.4
+ * - Bug Fix
+ * - Fix CRC-32 computation issue on the code's block boundary size.
+ *
+ * - Version 2.1.3
+ * - Bug Fix
+ * - MISRA C-2012 issue fixed: rule 10.1, 10.3, 10.4, 11.9, 14.4, 16.4 and 17.7.
+ *
+ * - Version 2.1.2
+ * - Fix sign-compare warning in dcp_reverse_and_copy.
+ *
+ * - Version 2.1.1
+ * - Add DCP status clearing when channel operation is complete
+ *
+ * - 2.1.0
+ * - Add byte/word swap feature for key, input and output data
+ *
+ * - Version 2.0.0
+ * - Initial version
+ */
+#define FSL_DCP_DRIVER_VERSION (MAKE_VERSION(2, 1, 6))
+/*@}*/
+
+/*! @brief DCP status return codes. */
+enum _dcp_status
+{
+ kStatus_DCP_Again = MAKE_STATUS(kStatusGroup_DCP, 0), /*!< Non-blocking function shall be called again. */
+};
+
+/*! @brief DCP channel enable.
+ *
+ */
+typedef enum _dcp_ch_enable
+{
+ kDCP_chDisable = 0U, /*!< DCP channel disable */
+ kDCP_ch0Enable = 1U, /*!< DCP channel 0 enable */
+ kDCP_ch1Enable = 2U, /*!< DCP channel 1 enable */
+ kDCP_ch2Enable = 4U, /*!< DCP channel 2 enable */
+ kDCP_ch3Enable = 8U, /*!< DCP channel 3 enable */
+ kDCP_chEnableAll = 15U, /*!< DCP channel enable all */
+} _dcp_ch_enable_t;
+
+/*! @brief DCP interrupt enable.
+ *
+ */
+typedef enum _dcp_ch_int_enable
+{
+ kDCP_chIntDisable = 0U, /*!< DCP interrupts disable */
+ kDCP_ch0IntEnable = 1U, /*!< DCP channel 0 interrupt enable */
+ kDCP_ch1IntEnable = 2U, /*!< DCP channel 1 interrupt enable */
+ kDCP_ch2IntEnable = 4U, /*!< DCP channel 2 interrupt enable */
+ kDCP_ch3IntEnable = 8U, /*!< DCP channel 3 interrupt enable */
+} _dcp_ch_int_enable_t;
+
+/*! @brief DCP channel selection.
+ *
+ */
+typedef enum _dcp_channel
+{
+ kDCP_Channel0 = (1u << 16), /*!< DCP channel 0. */
+ kDCP_Channel1 = (1u << 17), /*!< DCP channel 1. */
+ kDCP_Channel2 = (1u << 18), /*!< DCP channel 2. */
+ kDCP_Channel3 = (1u << 19), /*!< DCP channel 3. */
+} dcp_channel_t;
+
+/*! @brief DCP key slot selection.
+ *
+ */
+typedef enum _dcp_key_slot
+{
+ kDCP_KeySlot0 = 0U, /*!< DCP key slot 0. */
+ kDCP_KeySlot1 = 1U, /*!< DCP key slot 1. */
+ kDCP_KeySlot2 = 2U, /*!< DCP key slot 2.*/
+ kDCP_KeySlot3 = 3U, /*!< DCP key slot 3. */
+ kDCP_OtpKey = 4U, /*!< DCP OTP key. */
+ kDCP_OtpUniqueKey = 5U, /*!< DCP unique OTP key. */
+ kDCP_PayloadKey = 6U, /*!< DCP payload key. */
+} dcp_key_slot_t;
+
+/*! @brief DCP key, input & output swap options
+ *
+ */
+typedef enum _dcp_swap
+{
+ kDCP_NoSwap = 0x0U,
+ kDCP_KeyByteSwap = 0x40000U,
+ kDCP_KeyWordSwap = 0x80000U,
+ kDCP_InputByteSwap = 0x100000U,
+ kDCP_InputWordSwap = 0x200000U,
+ kDCP_OutputByteSwap = 0x400000U,
+ kDCP_OutputWordSwap = 0x800000U,
+} dcp_swap_t;
+
+/*! @brief DCP's work packet. */
+typedef struct _dcp_work_packet
+{
+ uint32_t nextCmdAddress;
+ uint32_t control0;
+ uint32_t control1;
+ uint32_t sourceBufferAddress;
+ uint32_t destinationBufferAddress;
+ uint32_t bufferSize;
+ uint32_t payloadPointer;
+ uint32_t status;
+} dcp_work_packet_t;
+
+/*! @brief Specify DCP's key resource and DCP channel. */
+typedef struct _dcp_handle
+{
+ dcp_channel_t channel; /*!< Specify DCP channel. */
+ dcp_key_slot_t keySlot; /*!< For operations with key (such as AES encryption/decryption), specify DCP key slot. */
+ uint32_t swapConfig; /*!< For configuration of key, input, output byte/word swap options */
+ uint32_t keyWord[4];
+ uint32_t iv[4];
+} dcp_handle_t;
+
+/*! @brief DCP's context buffer, used by DCP for context switching between channels. */
+typedef struct _dcp_context
+{
+ uint32_t x[208 / sizeof(uint32_t)];
+} dcp_context_t;
+
+/*! @brief DCP's configuration structure. */
+typedef struct _dcp_config
+{
+ bool gatherResidualWrites; /*!< Enable the ragged writes to the unaligned buffers. */
+ bool enableContextCaching; /*!< Enable the caching of contexts between the operations. */
+ bool enableContextSwitching; /*!< Enable automatic context switching for the channels. */
+ uint8_t enableChannel; /*!< DCP channel enable. */
+ uint8_t enableChannelInterrupt; /*!< Per-channel interrupt enable. */
+} dcp_config_t;
+
+/*! @} */
+
+#ifndef DCP_USE_DCACHE
+#define DCP_USE_DCACHE 1
+#endif
+/* 1 - driver supports DCACHE, 0 - drivers does not support DCACHE */
+/* When enable (DCP_USE_DCACHE = 1) Input/output buffers and hash ctx should be in */
+/* non-cached memory or handled properly (Clean & Invalidate DCACHE) */
+
+/*******************************************************************************
+ * AES Definitions
+ *******************************************************************************/
+
+/*!
+ * @addtogroup dcp_driver_aes
+ * @{
+ */
+
+/*! AES block size in bytes */
+#define DCP_AES_BLOCK_SIZE 16
+
+/*!
+ *@}
+ */ /* end of dcp_driver_aes */
+
+/*******************************************************************************
+ * HASH Definitions
+ ******************************************************************************/
+/*!
+ * @addtogroup dcp_driver_hash
+ * @{
+ */
+
+/* DCP cannot correctly compute hash for message with zero size. When enabled, driver bypases DCP and returns correct
+ * hash value. If you are sure, that the driver will never be called with zero sized message, you can disable this
+ * feature to reduce code size */
+#define DCP_HASH_CAVP_COMPATIBLE
+
+/*! @brief Supported cryptographic block cipher functions for HASH creation */
+typedef enum _dcp_hash_algo_t
+{
+ kDCP_Sha1, /*!< SHA_1 */
+ kDCP_Sha256, /*!< SHA_256 */
+ kDCP_Crc32, /*!< CRC_32 */
+} dcp_hash_algo_t;
+
+/*! @brief DCP HASH Context size. */
+#define DCP_SHA_BLOCK_SIZE 128U /*!< internal buffer block size */
+#define DCP_HASH_BLOCK_SIZE DCP_SHA_BLOCK_SIZE /*!< DCP hash block size */
+
+/*! @brief DCP HASH Context size. */
+#define DCP_HASH_CTX_SIZE 64
+
+/*! @brief Storage type used to save hash context. */
+typedef struct _dcp_hash_ctx_t
+{
+ uint32_t x[DCP_HASH_CTX_SIZE];
+} dcp_hash_ctx_t;
+
+/*!
+ *@}
+ */ /* end of dcp_driver_hash */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @addtogroup dcp_driver
+ * @{
+ */
+
+/*!
+ * @brief Enables clock to and enables DCP
+ *
+ * Enable DCP clock and configure DCP.
+ *
+ * @param base DCP base address
+ * @param config Pointer to configuration structure.
+ */
+void DCP_Init(DCP_Type *base, const dcp_config_t *config);
+
+/*!
+ * @brief Disable DCP clock
+ *
+ * Reset DCP and Disable DCP clock.
+ *
+ * @param base DCP base address
+ */
+void DCP_Deinit(DCP_Type *base);
+
+/*!
+ * @brief Gets the default configuration structure.
+ *
+ * This function initializes the DCP configuration structure to a default value. The default
+ * values are as follows.
+ * dcpConfig->gatherResidualWrites = true;
+ * dcpConfig->enableContextCaching = true;
+ * dcpConfig->enableContextSwitching = true;
+ * dcpConfig->enableChannnel = kDCP_chEnableAll;
+ * dcpConfig->enableChannelInterrupt = kDCP_chIntDisable;
+ *
+ * @param[out] config Pointer to configuration structure.
+ */
+void DCP_GetDefaultConfig(dcp_config_t *config);
+
+/*!
+ * @brief Poll and wait on DCP channel.
+ *
+ * Polls the specified DCP channel until current it completes activity.
+ *
+ * @param base DCP peripheral base address.
+ * @param handle Specifies DCP channel.
+ * @return kStatus_Success When data processing completes without error.
+ * @return kStatus_Fail When error occurs.
+ */
+status_t DCP_WaitForChannelComplete(DCP_Type *base, dcp_handle_t *handle);
+
+/*!
+ *@}
+ */ /* end of dcp_driver */
+
+/*******************************************************************************
+ * AES API
+ ******************************************************************************/
+
+/*!
+ * @addtogroup dcp_driver_aes
+ * @{
+ */
+
+/*!
+ * @brief Set AES key to dcp_handle_t struct and optionally to DCP.
+ *
+ * Sets the AES key for encryption/decryption with the dcp_handle_t structure.
+ * The dcp_handle_t input argument specifies keySlot.
+ * If the keySlot is kDCP_OtpKey, the function will check the OTP_KEY_READY bit and will return it's ready to use
+ * status.
+ * For other keySlot selections, the function will copy and hold the key in dcp_handle_t struct.
+ * If the keySlot is one of the four DCP SRAM-based keys (one of kDCP_KeySlot0, kDCP_KeySlot1, kDCP_KeySlot2,
+ * kDCP_KeySlot3),
+ * this function will also load the supplied key to the specified keySlot in DCP.
+ *
+ * @param base DCP peripheral base address.
+ * @param handle Handle used for the request.
+ * @param key 0-mod-4 aligned pointer to AES key.
+ * @param keySize AES key size in bytes. Shall equal 16.
+ * @return status from set key operation
+ */
+status_t DCP_AES_SetKey(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key, size_t keySize);
+
+/*!
+ * @brief Encrypts AES on one or multiple 128-bit block(s).
+ *
+ * Encrypts AES.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param plaintext Input plain text to encrypt
+ * @param[out] ciphertext Output cipher text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size);
+
+/*!
+ * @brief Decrypts AES on one or multiple 128-bit block(s).
+ *
+ * Decrypts AES.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param ciphertext Input plain text to encrypt
+ * @param[out] plaintext Output cipher text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size);
+
+/*!
+ * @brief Encrypts AES using CBC block mode.
+ *
+ * Encrypts AES using CBC block mode.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param plaintext Input plain text to encrypt
+ * @param[out] ciphertext Output cipher text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @param iv Input initial vector to combine with the first input block.
+ * @return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t iv[16]);
+
+/*!
+ * @brief Decrypts AES using CBC block mode.
+ *
+ * Decrypts AES using CBC block mode.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param ciphertext Input cipher text to decrypt
+ * @param[out] plaintext Output plain text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @param iv Input initial vector to combine with the first input block.
+ * @return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t iv[16]);
+
+/*!
+ *@}
+ */ /* end of dcp_driver_aes */
+
+/*!
+ * @addtogroup dcp_nonblocking_driver_aes
+ * @{
+ */
+/*!
+ * @brief Encrypts AES using the ECB block mode.
+ *
+ * Puts AES ECB encrypt work packet to DCP channel.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param[out] dcpPacket Memory for the DCP work packet.
+ * @param plaintext Input plain text to encrypt.
+ * @param[out] ciphertext Output cipher text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @return kStatus_Success The work packet has been scheduled at DCP channel.
+ * @return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size);
+
+/*!
+ * @brief Decrypts AES using ECB block mode.
+ *
+ * Puts AES ECB decrypt dcpPacket to DCP input job ring.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request.
+ * @param[out] dcpPacket Memory for the DCP work packet.
+ * @param ciphertext Input cipher text to decrypt
+ * @param[out] plaintext Output plain text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @return kStatus_Success The work packet has been scheduled at DCP channel.
+ * @return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size);
+
+/*!
+ * @brief Encrypts AES using CBC block mode.
+ *
+ * Puts AES CBC encrypt dcpPacket to DCP input job ring.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request. Specifies jobRing.
+ * @param[out] dcpPacket Memory for the DCP work packet.
+ * @param plaintext Input plain text to encrypt
+ * @param[out] ciphertext Output cipher text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @param iv Input initial vector to combine with the first input block.
+ * @return kStatus_Success The work packet has been scheduled at DCP channel.
+ * @return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t *iv);
+
+/*!
+ * @brief Decrypts AES using CBC block mode.
+ *
+ * Puts AES CBC decrypt dcpPacket to DCP input job ring.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for this request. Specifies jobRing.
+ * @param[out] dcpPacket Memory for the DCP work packet.
+ * @param ciphertext Input cipher text to decrypt
+ * @param[out] plaintext Output plain text
+ * @param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * @param iv Input initial vector to combine with the first input block.
+ * @return kStatus_Success The work packet has been scheduled at DCP channel.
+ * @return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t *iv);
+
+/*!
+ *@}
+ */ /* end of dcp_nonblocking_driver_aes */
+
+/*******************************************************************************
+ * HASH API
+ ******************************************************************************/
+
+/*!
+ * @addtogroup dcp_driver_hash
+ * @{
+ */
+/*!
+ * @brief Initialize HASH context
+ *
+ * This function initializes the HASH.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Specifies the DCP channel used for hashing.
+ * @param[out] ctx Output hash context
+ * @param algo Underlaying algorithm to use for hash computation.
+ * @return Status of initialization
+ */
+status_t DCP_HASH_Init(DCP_Type *base, dcp_handle_t *handle, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo);
+
+/*!
+ * @brief Add data to current HASH
+ *
+ * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
+ * hashed. The functions blocks. If it returns kStatus_Success, the running hash
+ * has been updated (DCP has processed the input data), so the memory at the input pointer
+ * can be released back to system. The DCP context buffer is updated with the running hash
+ * and with all necessary information to support possible context switch.
+ *
+ * @param base DCP peripheral base address
+ * @param[in,out] ctx HASH context
+ * @param input Input data
+ * @param inputSize Size of input data in bytes
+ * @return Status of the hash update operation
+ */
+status_t DCP_HASH_Update(DCP_Type *base, dcp_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize);
+
+/*!
+ * @brief Finalize hashing
+ *
+ * Outputs the final hash (computed by DCP_HASH_Update()) and erases the context.
+ *
+ * @param base DCP peripheral base address
+ * @param[in,out] ctx Input hash context
+ * @param[out] output Output hash data
+ * @param[in,out] outputSize Optional parameter (can be passed as NULL). On function entry, it specifies the size of
+ * output[] buffer. On function return, it stores the number of updated output bytes.
+ * @return Status of the hash finish operation
+ */
+status_t DCP_HASH_Finish(DCP_Type *base, dcp_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize);
+
+/*!
+ * @brief Create HASH on given data
+ *
+ * Perform the full SHA or CRC32 in one function call. The function is blocking.
+ *
+ * @param base DCP peripheral base address
+ * @param handle Handle used for the request.
+ * @param algo Underlaying algorithm to use for hash computation.
+ * @param input Input data
+ * @param inputSize Size of input data in bytes
+ * @param[out] output Output hash data
+ * @param[out] outputSize Output parameter storing the size of the output hash in bytes
+ * @return Status of the one call hash operation.
+ */
+status_t DCP_HASH(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_hash_algo_t algo,
+ const uint8_t *input,
+ size_t inputSize,
+ uint8_t *output,
+ size_t *outputSize);
+
+/*!
+ *@}
+ */ /* end of dcp_driver_hash */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _FSL_DCP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.c b/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.c
new file mode 100644
index 0000000000..8bfbe6c367
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dmamux.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dmamux"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for DMAMUX.
+ *
+ * @param base DMAMUX peripheral base address.
+ */
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map DMAMUX instance number to base pointer. */
+static DMAMUX_Type *const s_dmamuxBases[] = DMAMUX_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map DMAMUX instance number to clock name. */
+static const clock_ip_name_t s_dmamuxClockName[] = DMAMUX_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dmamuxBases); instance++)
+ {
+ if (s_dmamuxBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dmamuxBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the DMAMUX peripheral.
+ *
+ * This function ungates the DMAMUX clock.
+ *
+ * param base DMAMUX peripheral base address.
+ *
+ */
+void DMAMUX_Init(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitializes the DMAMUX peripheral.
+ *
+ * This function gates the DMAMUX clock.
+ *
+ * param base DMAMUX peripheral base address.
+ */
+void DMAMUX_Deinit(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.h b/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.h
new file mode 100644
index 0000000000..2f627c2451
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/dmamux/fsl_dmamux.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_DMAMUX_H_
+#define _FSL_DMAMUX_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup dmamux
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief DMAMUX driver version 2.0.5. */
+#define FSL_DMAMUX_DRIVER_VERSION (MAKE_VERSION(2, 0, 5))
+/*@}*/
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name DMAMUX Initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the DMAMUX peripheral.
+ *
+ * This function ungates the DMAMUX clock.
+ *
+ * @param base DMAMUX peripheral base address.
+ *
+ */
+void DMAMUX_Init(DMAMUX_Type *base);
+
+/*!
+ * @brief Deinitializes the DMAMUX peripheral.
+ *
+ * This function gates the DMAMUX clock.
+ *
+ * @param base DMAMUX peripheral base address.
+ */
+void DMAMUX_Deinit(DMAMUX_Type *base);
+
+/* @} */
+/*!
+ * @name DMAMUX Channel Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables the DMAMUX channel.
+ *
+ * This function enables the DMAMUX channel.
+ *
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ */
+static inline void DMAMUX_EnableChannel(DMAMUX_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->CHCFG[channel] |= DMAMUX_CHCFG_ENBL_MASK;
+}
+
+/*!
+ * @brief Disables the DMAMUX channel.
+ *
+ * This function disables the DMAMUX channel.
+ *
+ * @note The user must disable the DMAMUX channel before configuring it.
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ */
+static inline void DMAMUX_DisableChannel(DMAMUX_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+#if defined FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH && (FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH == 32U)
+ base->CHCFG[channel] &= ~DMAMUX_CHCFG_ENBL_MASK;
+#else
+ base->CHCFG[channel] &= ~(uint8_t)DMAMUX_CHCFG_ENBL_MASK;
+#endif
+}
+
+/*!
+ * @brief Configures the DMAMUX channel source.
+ *
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ * @param source Channel source, which is used to trigger the DMA transfer.
+ */
+static inline void DMAMUX_SetSource(DMAMUX_Type *base, uint32_t channel, uint32_t source)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+#if defined FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH && (FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH == 32U)
+ base->CHCFG[channel] = ((base->CHCFG[channel] & ~DMAMUX_CHCFG_SOURCE_MASK) | DMAMUX_CHCFG_SOURCE(source));
+#else
+ base->CHCFG[channel] = (uint8_t)((base->CHCFG[channel] & ~DMAMUX_CHCFG_SOURCE_MASK) | DMAMUX_CHCFG_SOURCE(source));
+#endif
+}
+
+#if defined(FSL_FEATURE_DMAMUX_HAS_TRIG) && FSL_FEATURE_DMAMUX_HAS_TRIG > 0U
+/*!
+ * @brief Enables the DMAMUX period trigger.
+ *
+ * This function enables the DMAMUX period trigger feature.
+ *
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ */
+static inline void DMAMUX_EnablePeriodTrigger(DMAMUX_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->CHCFG[channel] |= DMAMUX_CHCFG_TRIG_MASK;
+}
+
+/*!
+ * @brief Disables the DMAMUX period trigger.
+ *
+ * This function disables the DMAMUX period trigger.
+ *
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ */
+static inline void DMAMUX_DisablePeriodTrigger(DMAMUX_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+#if defined FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH && (FSL_FEATURE_DMAMUX_CHCFG_REGISTER_WIDTH == 32U)
+ base->CHCFG[channel] &= ~DMAMUX_CHCFG_TRIG_MASK;
+#else
+ base->CHCFG[channel] &= ~(uint8_t)DMAMUX_CHCFG_TRIG_MASK;
+#endif
+}
+#endif /* FSL_FEATURE_DMAMUX_HAS_TRIG */
+
+#if (defined(FSL_FEATURE_DMAMUX_HAS_A_ON) && FSL_FEATURE_DMAMUX_HAS_A_ON)
+/*!
+ * @brief Enables the DMA channel to be always ON.
+ *
+ * This function enables the DMAMUX channel always ON feature.
+ *
+ * @param base DMAMUX peripheral base address.
+ * @param channel DMAMUX channel number.
+ * @param enable Switcher of the always ON feature. "true" means enabled, "false" means disabled.
+ */
+static inline void DMAMUX_EnableAlwaysOn(DMAMUX_Type *base, uint32_t channel, bool enable)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ if (enable)
+ {
+ base->CHCFG[channel] |= DMAMUX_CHCFG_A_ON_MASK;
+ }
+ else
+ {
+ base->CHCFG[channel] &= ~DMAMUX_CHCFG_A_ON_MASK;
+ }
+}
+#endif /* FSL_FEATURE_DMAMUX_HAS_A_ON */
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/* @} */
+
+#endif /* _FSL_DMAMUX_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.c
new file mode 100644
index 0000000000..269d62c7ff
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.c
@@ -0,0 +1,2858 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_edma.h"
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#include "fsl_memory.h"
+#endif
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.edma"
+#endif
+
+#define EDMA_TRANSFER_ENABLED_MASK 0x80U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance offset.
+ *
+ * @param instance EDMA peripheral instance number.
+ */
+static uint32_t EDMA_GetInstanceOffset(uint32_t instance);
+
+/*!
+ * @brief Map transfer width.
+ *
+ * @param width transfer width.
+ */
+static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map EDMA instance number to base pointer. */
+static DMA_Type *const s_edmaBases[] = DMA_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map EDMA instance number to clock name. */
+static const clock_ip_name_t s_edmaClockName[] = EDMA_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Array to map EDMA instance number to IRQ number. */
+static const IRQn_Type s_edmaIRQNumber[][FSL_FEATURE_EDMA_MODULE_CHANNEL] = DMA_CHN_IRQS;
+
+/*! @brief Pointers to transfer handle for each EDMA channel. */
+static edma_handle_t *s_EDMAHandle[FSL_FEATURE_EDMA_MODULE_CHANNEL * FSL_FEATURE_SOC_EDMA_COUNT];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t EDMA_GetInstance(DMA_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_edmaBases); instance++)
+ {
+ if (s_edmaBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_edmaBases));
+
+ return instance;
+}
+
+/*!
+ * brief Push content of TCD structure into hardware TCD register.
+ *
+ * param base EDMA peripheral base address.
+ * param channel EDMA channel number.
+ * param tcd Point to TCD structure.
+ */
+void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ /* Push tcd into hardware TCD register */
+ base->TCD[channel].SADDR = tcd->SADDR;
+ base->TCD[channel].SOFF = tcd->SOFF;
+ base->TCD[channel].ATTR = tcd->ATTR;
+ base->TCD[channel].NBYTES_MLNO = tcd->NBYTES;
+ base->TCD[channel].SLAST = (int32_t)tcd->SLAST;
+ base->TCD[channel].DADDR = tcd->DADDR;
+ base->TCD[channel].DOFF = tcd->DOFF;
+ base->TCD[channel].CITER_ELINKNO = tcd->CITER;
+ base->TCD[channel].DLAST_SGA = (int32_t)tcd->DLAST_SGA;
+ /* Clear DONE bit first, otherwise ESG cannot be set */
+ base->TCD[channel].CSR = 0;
+ base->TCD[channel].CSR = tcd->CSR;
+ base->TCD[channel].BITER_ELINKNO = tcd->BITER;
+}
+
+/*!
+ * brief Initializes the eDMA peripheral.
+ *
+ * This function ungates the eDMA clock and configures the eDMA peripheral according
+ * to the configuration structure.
+ *
+ * param base eDMA peripheral base address.
+ * param config A pointer to the configuration structure, see "edma_config_t".
+ * note This function enables the minor loop map feature.
+ */
+void EDMA_Init(DMA_Type *base, const edma_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate EDMA peripheral clock */
+ CLOCK_EnableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* clear all the enabled request, status to make sure EDMA status is in normal condition */
+ base->ERQ = 0U;
+ base->INT = 0xFFFFFFFFU;
+ base->ERR = 0xFFFFFFFFU;
+ /* Configure EDMA peripheral according to the configuration structure. */
+ tmpreg = base->CR;
+ tmpreg &= ~(DMA_CR_ERCA_MASK | DMA_CR_HOE_MASK | DMA_CR_CLM_MASK | DMA_CR_EDBG_MASK);
+ tmpreg |= (DMA_CR_ERCA(config->enableRoundRobinArbitration) | DMA_CR_HOE(config->enableHaltOnError) |
+ DMA_CR_CLM(config->enableContinuousLinkMode) | DMA_CR_EDBG(config->enableDebugMode) | DMA_CR_EMLM(1U));
+ base->CR = tmpreg;
+}
+
+/*!
+ * brief Deinitializes the eDMA peripheral.
+ *
+ * This function gates the eDMA clock.
+ *
+ * param base eDMA peripheral base address.
+ */
+void EDMA_Deinit(DMA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate EDMA peripheral clock */
+ CLOCK_DisableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the eDMA default configuration structure.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * code
+ * config.enableContinuousLinkMode = false;
+ * config.enableHaltOnError = true;
+ * config.enableRoundRobinArbitration = false;
+ * config.enableDebugMode = false;
+ * endcode
+ *
+ * param config A pointer to the eDMA configuration structure.
+ */
+void EDMA_GetDefaultConfig(edma_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableRoundRobinArbitration = false;
+ config->enableHaltOnError = true;
+ config->enableContinuousLinkMode = false;
+ config->enableDebugMode = false;
+}
+
+/*!
+ * brief Sets all TCD registers to default values.
+ *
+ * This function sets TCD registers for this channel to default values.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * note This function must not be called while the channel transfer is ongoing
+ * or it causes unpredictable results.
+ * note This function enables the auto stop request feature.
+ */
+void EDMA_ResetChannel(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdReset((edma_tcd_t *)(uint32_t)&base->TCD[channel]);
+}
+
+/*!
+ * brief Configures the eDMA transfer attribute.
+ *
+ * This function configures the transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the TCD address.
+ * Example:
+ * code
+ * edma_transfer_t config;
+ * edma_tcd_t tcd;
+ * config.srcAddr = ..;
+ * config.destAddr = ..;
+ * ...
+ * EDMA_SetTransferConfig(DMA0, channel, &config, &stcd);
+ * endcode
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param config Pointer to eDMA transfer configuration structure.
+ * param nextTcd Point to TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * note If nextTcd is not NULL, it means scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the eDMA_ResetChannel.
+ */
+void EDMA_SetTransferConfig(DMA_Type *base, uint32_t channel, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0U);
+
+/* If there is address offset, convert the address */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ nextTcd = (edma_tcd_t *)(MEMORY_ConvertMemoryMapAddress((uint32_t)nextTcd, kMEMORY_Local2DMA));
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ EDMA_TcdSetTransferConfig((edma_tcd_t *)(uint32_t)&base->TCD[channel], config, nextTcd);
+}
+
+/*!
+ * brief Configures the eDMA minor offset feature.
+ *
+ * The minor offset means that the signed-extended value is added to the source address or destination
+ * address after each minor loop.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_SetMinorOffsetConfig(DMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+ tmpreg = base->TCD[channel].NBYTES_MLOFFYES;
+ tmpreg &= ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ base->TCD[channel].NBYTES_MLOFFYES = tmpreg;
+}
+
+/*!
+ * brief Configures the eDMA channel TCD major offset feature.
+ *
+ * Adjustment value added to the source address at the completion of the major iteration count
+ *
+ * param base eDMA peripheral base address.
+ * param channel edma channel number.
+ * param sourceOffset source address offset.
+ * param destOffset destination address offset.
+ */
+void EDMA_SetMajorOffsetConfig(DMA_Type *base, uint32_t channel, int32_t sourceOffset, int32_t destOffset)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ base->TCD[channel].SLAST = sourceOffset;
+ base->TCD[channel].DLAST_SGA = destOffset;
+}
+
+/*!
+ * brief Configures the eDMA channel preemption feature.
+ *
+ * This function configures the channel preemption attribute and the priority of the channel.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number
+ * param config A pointer to the channel preemption configuration structure.
+ */
+void EDMA_SetChannelPreemptionConfig(DMA_Type *base, uint32_t channel, const edma_channel_Preemption_config_t *config)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+
+ bool tmpEnablePreemptAbility = config->enablePreemptAbility;
+ bool tmpEnableChannelPreemption = config->enableChannelPreemption;
+ uint8_t tmpChannelPriority = config->channelPriority;
+ volatile uint8_t *tmpReg = &base->DCHPRI3;
+
+ ((volatile uint8_t *)tmpReg)[DMA_DCHPRI_INDEX(channel)] =
+ (DMA_DCHPRI0_DPA((true == tmpEnablePreemptAbility ? 0U : 1U)) |
+ DMA_DCHPRI0_ECP((true == tmpEnableChannelPreemption ? 1U : 0U)) | DMA_DCHPRI0_CHPRI(tmpChannelPriority));
+}
+
+/*!
+ * brief Sets the channel link for the eDMA transfer.
+ *
+ * This function configures either the minor link or the major link mode. The minor link means that the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param linkType A channel link type, which can be one of the following:
+ * arg kEDMA_LinkNone
+ * arg kEDMA_MinorLink
+ * arg kEDMA_MajorLink
+ * param linkedChannel The linked channel number.
+ * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ */
+void EDMA_SetChannelLink(DMA_Type *base, uint32_t channel, edma_channel_link_type_t linkType, uint32_t linkedChannel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdSetChannelLink((edma_tcd_t *)(uint32_t)&base->TCD[channel], linkType, linkedChannel);
+}
+
+/*!
+ * brief Sets the bandwidth for the eDMA transfer.
+ *
+ * Because the eDMA processes the minor loop, it continuously generates read/write sequences
+ * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
+ * each read/write access to control the bus request bandwidth seen by the crossbar switch.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param bandWidth A bandwidth setting, which can be one of the following:
+ * arg kEDMABandwidthStallNone
+ * arg kEDMABandwidthStall4Cycle
+ * arg kEDMABandwidthStall8Cycle
+ */
+void EDMA_SetBandWidth(DMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ base->TCD[channel].CSR = (uint16_t)((base->TCD[channel].CSR & (~DMA_CSR_BWC_MASK)) | DMA_CSR_BWC(bandWidth));
+}
+
+/*!
+ * brief Sets the source modulo and the destination modulo for the eDMA transfer.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param srcModulo A source modulo value.
+ * param destModulo A destination modulo value.
+ */
+void EDMA_SetModulo(DMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint16_t tmpreg;
+
+ tmpreg = base->TCD[channel].ATTR & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ base->TCD[channel].ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+/*!
+ * brief Enables the interrupt source for the eDMA transfer.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Enable error interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
+ {
+ base->EEI |= ((uint32_t)0x1U << channel);
+ }
+
+ /* Enable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Disables the interrupt source for the eDMA transfer.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of the interrupt source to be set. Use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Disable error interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
+ {
+ base->EEI &= (~((uint32_t)0x1U << channel));
+ }
+
+ /* Disable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ base->TCD[channel].CSR &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ base->TCD[channel].CSR &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Sets all fields to default values for the TCD structure.
+ *
+ * This function sets all fields for this TCD structure to default value.
+ *
+ * param tcd Pointer to the TCD structure.
+ * note This function enables the auto stop request feature.
+ */
+void EDMA_TcdReset(edma_tcd_t *tcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ /* Reset channel TCD */
+ tcd->SADDR = 0U;
+ tcd->SOFF = 0U;
+ tcd->ATTR = 0U;
+ tcd->NBYTES = 0U;
+ tcd->SLAST = 0U;
+ tcd->DADDR = 0U;
+ tcd->DOFF = 0U;
+ tcd->CITER = 0U;
+ tcd->DLAST_SGA = 0U;
+ /* Enable auto disable request feature */
+ tcd->CSR = DMA_CSR_DREQ(1U);
+ tcd->BITER = 0U;
+}
+
+/*!
+ * brief Configures the eDMA TCD transfer attribute.
+ *
+ * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
+ * The TCD is used in the scatter-gather mode.
+ * This function configures the TCD transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the next TCD address.
+ * Example:
+ * code
+ * edma_transfer_t config = {
+ * ...
+ * }
+ * edma_tcd_t tcd __aligned(32);
+ * edma_tcd_t nextTcd __aligned(32);
+ * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
+ * endcode
+ *
+ * param tcd Pointer to the TCD structure.
+ * param config Pointer to eDMA transfer configuration structure.
+ * param nextTcd Pointer to the next TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * note TCD address should be 32 bytes aligned or it causes an eDMA error.
+ * note If the nextTcd is not NULL, the scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the EDMA_TcdReset.
+ */
+void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0U);
+ assert((config->srcAddr % (1UL << (uint32_t)config->srcTransferSize)) == 0U);
+ assert((config->destAddr % (1UL << (uint32_t)config->destTransferSize)) == 0U);
+
+ /* source address */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ tcd->SADDR = MEMORY_ConvertMemoryMapAddress(config->srcAddr, kMEMORY_Local2DMA);
+ /* destination address */
+ tcd->DADDR = MEMORY_ConvertMemoryMapAddress(config->destAddr, kMEMORY_Local2DMA);
+#else
+ tcd->SADDR = config->srcAddr;
+ /* destination address */
+ tcd->DADDR = config->destAddr;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ /* Source data and destination data transfer size */
+ tcd->ATTR = DMA_ATTR_SSIZE(config->srcTransferSize) | DMA_ATTR_DSIZE(config->destTransferSize);
+ /* Source address signed offset */
+ tcd->SOFF = (uint16_t)config->srcOffset;
+ /* Destination address signed offset */
+ tcd->DOFF = (uint16_t)config->destOffset;
+ /* Minor byte transfer count */
+ tcd->NBYTES = config->minorLoopBytes;
+ /* Current major iteration count */
+ tcd->CITER = (uint16_t)config->majorLoopCounts;
+ /* Starting major iteration count */
+ tcd->BITER = (uint16_t)config->majorLoopCounts;
+ /* Enable scatter/gather processing */
+ if (nextTcd != NULL)
+ {
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ tcd->DLAST_SGA = MEMORY_ConvertMemoryMapAddress((uint32_t)nextTcd, kMEMORY_Local2DMA);
+#else
+ tcd->DLAST_SGA = (uint32_t)nextTcd;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ /*
+ Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
+ user must call EDMA_TcdReset or EDMA_ResetChannel which will set
+ DREQ, so must use "|" or "&" rather than "=".
+
+ Clear the DREQ bit because scatter gather has been enabled, so the
+ previous transfer is not the last transfer, and channel request should
+ be enabled at the next transfer(the next TCD).
+ */
+ tcd->CSR = (tcd->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ }
+}
+
+/*!
+ * brief Configures the eDMA TCD minor offset feature.
+ *
+ * A minor offset is a signed-extended value added to the source address or a destination
+ * address after each minor loop.
+ *
+ * param tcd A point to the TCD structure.
+ * param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ uint32_t tmpreg;
+
+ tmpreg = tcd->NBYTES &
+ ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ tcd->NBYTES = tmpreg;
+}
+
+/*!
+ * brief Configures the eDMA TCD major offset feature.
+ *
+ * Adjustment value added to the source address at the completion of the major iteration count
+ *
+ * param tcd A point to the TCD structure.
+ * param sourceOffset source address offset.
+ * param destOffset destination address offset.
+ */
+void EDMA_TcdSetMajorOffsetConfig(edma_tcd_t *tcd, int32_t sourceOffset, int32_t destOffset)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ tcd->SLAST = (uint32_t)sourceOffset;
+ tcd->DLAST_SGA = (uint32_t)destOffset;
+}
+
+/*!
+ * brief Sets the channel link for the eDMA TCD.
+ *
+ * This function configures either a minor link or a major link. The minor link means the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ * param tcd Point to the TCD structure.
+ * param linkType Channel link type, it can be one of:
+ * arg kEDMA_LinkNone
+ * arg kEDMA_MinorLink
+ * arg kEDMA_MajorLink
+ * param linkedChannel The linked channel number.
+ */
+void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t linkType, uint32_t linkedChannel)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+ assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ if (linkType == kEDMA_MinorLink) /* Minor link config */
+ {
+ uint16_t tmpreg;
+
+ /* Enable minor link */
+ tcd->CITER |= DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER |= DMA_BITER_ELINKYES_ELINK_MASK;
+ /* Set linked channel */
+ tmpreg = tcd->CITER & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_CITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->CITER = tmpreg;
+ tmpreg = tcd->BITER & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_BITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->BITER = tmpreg;
+ }
+ else if (linkType == kEDMA_MajorLink) /* Major link config */
+ {
+ uint16_t tmpreg;
+
+ /* Enable major link */
+ tcd->CSR |= DMA_CSR_MAJORELINK_MASK;
+ /* Set major linked channel */
+ tmpreg = tcd->CSR & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
+ tcd->CSR = tmpreg | DMA_CSR_MAJORLINKCH(linkedChannel);
+ }
+ else /* Link none */
+ {
+ tcd->CITER &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
+ tcd->CSR &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
+ }
+}
+
+/*!
+ * brief Sets the source modulo and the destination modulo for the eDMA TCD.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * param tcd A pointer to the TCD structure.
+ * param srcModulo A source modulo value.
+ * param destModulo A destination modulo value.
+ */
+void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ uint16_t tmpreg;
+
+ tmpreg = tcd->ATTR & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ tcd->ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+/*!
+ * brief Enables the interrupt source for the eDMA TCD.
+ *
+ * param tcd Point to the TCD structure.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Enable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ tcd->CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ tcd->CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Disables the interrupt source for the eDMA TCD.
+ *
+ * param tcd Point to the TCD structure.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Disable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ tcd->CSR &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ tcd->CSR &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Gets the remaining major loop count from the eDMA current channel TCD.
+ *
+ * This function checks the TCD (Task Control Descriptor) status for a specified
+ * eDMA channel and returns the number of major loop count that has not finished.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * return Major loop count which has not been transferred yet for the current TCD.
+ * note 1. This function can only be used to get unfinished major loop count of transfer without
+ * the next TCD, or it might be inaccuracy.
+ * 2. The unfinished/remaining transfer bytes cannot be obtained directly from registers while
+ * the channel is running.
+ * Because to calculate the remaining bytes, the initial NBYTES configured in DMA_TCDn_NBYTES_MLNO
+ * register is needed while the eDMA IP does not support getting it while a channel is active.
+ * In another word, the NBYTES value reading is always the actual (decrementing) NBYTES value the dma_engine
+ * is working with while a channel is running.
+ * Consequently, to get the remaining transfer bytes, a software-saved initial value of NBYTES (for example
+ * copied before enabling the channel) is needed. The formula to calculate it is shown below:
+ * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
+ */
+uint32_t EDMA_GetRemainingMajorLoopCount(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t remainingCount = 0;
+
+ if (0U != (DMA_CSR_DONE_MASK & base->TCD[channel].CSR))
+ {
+ remainingCount = 0;
+ }
+ else
+ {
+ /* Calculate the unfinished bytes */
+ if (0U != (base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_ELINK_MASK))
+ {
+ remainingCount = (((uint32_t)base->TCD[channel].CITER_ELINKYES & DMA_CITER_ELINKYES_CITER_MASK) >>
+ DMA_CITER_ELINKYES_CITER_SHIFT);
+ }
+ else
+ {
+ remainingCount = (((uint32_t)base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) >>
+ DMA_CITER_ELINKNO_CITER_SHIFT);
+ }
+ }
+
+ return remainingCount;
+}
+
+/*!
+ * brief Gets the eDMA channel status flags.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * return The mask of channel status flags. Users need to use the
+ * _edma_channel_status_flags type to decode the return variables.
+ */
+uint32_t EDMA_GetChannelStatusFlags(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t retval = 0;
+
+ /* Get DONE bit flag */
+ retval |= (((uint32_t)base->TCD[channel].CSR & DMA_CSR_DONE_MASK) >> DMA_CSR_DONE_SHIFT);
+ /* Get ERROR bit flag */
+ retval |= ((((uint32_t)base->ERR >> channel) & 0x1U) << 1U);
+ /* Get INT bit flag */
+ retval |= ((((uint32_t)base->INT >> channel) & 0x1U) << 2U);
+
+ return retval;
+}
+
+/*!
+ * brief Clears the eDMA channel status flags.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of channel status to be cleared. Users need to use
+ * the defined _edma_channel_status_flags type.
+ */
+void EDMA_ClearChannelStatusFlags(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Clear DONE bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_DoneFlag))
+ {
+ base->CDNE = (uint8_t)channel;
+ }
+ /* Clear ERROR bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorFlag))
+ {
+ base->CERR = (uint8_t)channel;
+ }
+ /* Clear INT bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_InterruptFlag))
+ {
+ base->CINT = (uint8_t)channel;
+ }
+}
+
+static uint32_t EDMA_GetInstanceOffset(uint32_t instance)
+{
+ static uint8_t startInstanceNum;
+
+#if defined(DMA0)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA0);
+#elif defined(DMA1)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA1);
+#elif defined(DMA2)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA2);
+#elif defined(DMA3)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA3);
+#endif
+
+ assert(startInstanceNum <= instance);
+
+ return instance - startInstanceNum;
+}
+
+/*!
+ * brief Creates the eDMA handle.
+ *
+ * This function is called if using the transactional API for eDMA. This function
+ * initializes the internal state of the eDMA handle.
+ *
+ * param handle eDMA handle pointer. The eDMA handle stores callback function and
+ * parameters.
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ */
+void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel)
+{
+ assert(handle != NULL);
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t edmaInstance;
+ uint32_t channelIndex;
+ edma_tcd_t *tcdRegs;
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->base = base;
+ handle->channel = (uint8_t)channel;
+
+ /* Get the DMA instance number */
+ edmaInstance = EDMA_GetInstance(base);
+ channelIndex = (EDMA_GetInstanceOffset(edmaInstance) * (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL) + channel;
+ s_EDMAHandle[channelIndex] = handle;
+
+ /* Enable NVIC interrupt */
+ (void)EnableIRQ(s_edmaIRQNumber[edmaInstance][channel]);
+
+ /*
+ Reset TCD registers to zero. Unlike the EDMA_TcdReset(DREQ will be set),
+ CSR will be 0. Because in order to suit EDMA busy check mechanism in
+ EDMA_SubmitTransfer, CSR must be set 0.
+ */
+ tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+ tcdRegs->SADDR = 0;
+ tcdRegs->SOFF = 0;
+ tcdRegs->ATTR = 0;
+ tcdRegs->NBYTES = 0;
+ tcdRegs->SLAST = 0;
+ tcdRegs->DADDR = 0;
+ tcdRegs->DOFF = 0;
+ tcdRegs->CITER = 0;
+ tcdRegs->DLAST_SGA = 0;
+ tcdRegs->CSR = 0;
+ tcdRegs->BITER = 0;
+}
+
+/*!
+ * brief Installs the TCDs memory pool into the eDMA handle.
+ *
+ * This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
+ * while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
+ * (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
+ * Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
+ *
+ * param handle eDMA handle pointer.
+ * param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
+ * param tcdSize The number of TCD slots.
+ */
+void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize)
+{
+ assert(handle != NULL);
+ assert(((uint32_t)tcdPool & 0x1FU) == 0U);
+
+ /* Initialize tcd queue attribute. */
+ /* header should initial as 1, since that it is used to point to the next TCD to be loaded into TCD memory,
+ * In EDMA driver IRQ handler, header will be used to calculate how many tcd has done, for example,
+ * If application submit 4 transfer request, A->B->C->D,
+ * when A finshed, the header is 0, C is the next TCD to be load, since B is already loaded,
+ * according to EDMA driver IRQ handler, tcdDone = C - A - header = 2 - header = 2, but actually only 1 TCD done,
+ * so the issue will be the wrong TCD done count will pass to application in first TCD interrupt.
+ * During first submit, the header should be assigned to 1, since 0 is current one and 1 is next TCD to be loaded,
+ * but software cannot know which submission is the first one, so assign 1 to header here.
+ */
+ handle->header = 1;
+ handle->tcdUsed = 0;
+ handle->tcdSize = (int8_t)tcdSize;
+ handle->flags = 0;
+ handle->tcdPool = tcdPool;
+}
+
+/*!
+ * brief Installs a callback function for the eDMA transfer.
+ *
+ * This callback is called in the eDMA IRQ handler. Use the callback to do something after
+ * the current major loop transfer completes. This function will be called every time one tcd finished transfer.
+ *
+ * param handle eDMA handle pointer.
+ * param callback eDMA callback function pointer.
+ * param userData A parameter for the callback function.
+ */
+void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData)
+{
+ assert(handle != NULL);
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width)
+{
+ edma_transfer_size_t transferSize = kEDMA_TransferSize1Bytes;
+
+ /* map width to register value */
+ switch (width)
+ {
+ /* width 8bit */
+ case 1U:
+ transferSize = kEDMA_TransferSize1Bytes;
+ break;
+ /* width 16bit */
+ case 2U:
+ transferSize = kEDMA_TransferSize2Bytes;
+ break;
+ /* width 32bit */
+ case 4U:
+ transferSize = kEDMA_TransferSize4Bytes;
+ break;
+#if (defined(FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER)
+ /* width 64bit */
+ case 8U:
+ transferSize = kEDMA_TransferSize8Bytes;
+ break;
+#endif
+#if (defined(FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER)
+ /* width 128bit */
+ case 16U:
+ transferSize = kEDMA_TransferSize16Bytes;
+ break;
+#endif
+ /* width 256bit */
+ case 32U:
+ transferSize = kEDMA_TransferSize32Bytes;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ return transferSize;
+}
+
+/*!
+ * brief Prepares the eDMA transfer structure configurations.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * param config The user configuration structure of type edma_transfer_t.
+ * param srcAddr eDMA transfer source address.
+ * param srcWidth eDMA transfer source address width(bytes).
+ * param srcOffset source address offset.
+ * param destAddr eDMA transfer destination address.
+ * param destWidth eDMA transfer destination address width(bytes).
+ * param destOffset destination address offset.
+ * param bytesEachRequest eDMA transfer bytes per channel request.
+ * param transferBytes eDMA transfer bytes to be transferred.
+ * note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransferConfig(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ int16_t srcOffset,
+ void *destAddr,
+ uint32_t destWidth,
+ int16_t destOffset,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes)
+{
+ assert(config != NULL);
+ assert(srcAddr != NULL);
+ assert(destAddr != NULL);
+ assert((srcWidth != 0U) && (srcWidth <= 32U) && ((srcWidth & (srcWidth - 1U)) == 0U));
+ assert((destWidth != 0U) && (destWidth <= 32U) && ((destWidth & (destWidth - 1U)) == 0U));
+ assert((transferBytes % bytesEachRequest) == 0U);
+ assert((((uint32_t)(uint32_t *)srcAddr) % srcWidth) == 0U);
+ assert((((uint32_t)(uint32_t *)destAddr) % destWidth) == 0U);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ config->srcAddr = MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)srcAddr, kMEMORY_Local2DMA);
+ config->destAddr = MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)destAddr, kMEMORY_Local2DMA);
+#else
+ config->destAddr = (uint32_t)(uint32_t *)destAddr;
+ config->srcAddr = (uint32_t)(uint32_t *)srcAddr;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ config->minorLoopBytes = bytesEachRequest;
+ config->majorLoopCounts = transferBytes / bytesEachRequest;
+ config->srcTransferSize = EDMA_TransferWidthMapping(srcWidth);
+ config->destTransferSize = EDMA_TransferWidthMapping(destWidth);
+ config->destOffset = destOffset;
+ config->srcOffset = srcOffset;
+}
+
+/*!
+ * brief Prepares the eDMA transfer structure.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * param config The user configuration structure of type edma_transfer_t.
+ * param srcAddr eDMA transfer source address.
+ * param srcWidth eDMA transfer source address width(bytes).
+ * param destAddr eDMA transfer destination address.
+ * param destWidth eDMA transfer destination address width(bytes).
+ * param bytesEachRequest eDMA transfer bytes per channel request.
+ * param transferBytes eDMA transfer bytes to be transferred.
+ * param transferType eDMA transfer type.
+ * note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransfer(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ void *destAddr,
+ uint32_t destWidth,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes,
+ edma_transfer_type_t transferType)
+{
+ assert(config != NULL);
+
+ int16_t srcOffset = 0, destOffset = 0;
+
+ switch (transferType)
+ {
+ case kEDMA_MemoryToMemory:
+ destOffset = (int16_t)destWidth;
+ srcOffset = (int16_t)srcWidth;
+ break;
+ case kEDMA_MemoryToPeripheral:
+ destOffset = 0;
+ srcOffset = (int16_t)srcWidth;
+ break;
+ case kEDMA_PeripheralToMemory:
+ destOffset = (int16_t)destWidth;
+ srcOffset = 0;
+ break;
+ case kEDMA_PeripheralToPeripheral:
+ destOffset = 0;
+ srcOffset = 0;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ EDMA_PrepareTransferConfig(config, srcAddr, srcWidth, srcOffset, destAddr, destWidth, destOffset, bytesEachRequest,
+ transferBytes);
+}
+
+/*!
+ * brief Submits the eDMA transfer request.
+ *
+ * This function submits the eDMA transfer request according to the transfer configuration structure.
+ * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
+ * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
+ *
+ * param handle eDMA handle pointer.
+ * param config Pointer to eDMA transfer configuration structure.
+ * retval kStatus_EDMA_Success It means submit transfer request succeed.
+ * retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
+ * retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
+ */
+status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+
+ if (handle->tcdPool == NULL)
+ {
+ /*
+ * Check if EDMA channel is busy:
+ * 1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
+ * 2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
+ * then channel is busy
+ *
+ * There is one case can not be covered in below condition:
+ * When transfer request is submitted, but no request from peripheral, that is to say channel sevice doesn't
+ * begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
+ * ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
+ * application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
+ */
+ if (((handle->base->TCD[handle->channel].CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
+ (((handle->base->TCD[handle->channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) !=
+ (handle->base->TCD[handle->channel].BITER_ELINKNO & DMA_BITER_ELINKNO_BITER_MASK))))
+ {
+ return kStatus_EDMA_Busy;
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->base, handle->channel, config, NULL);
+ /* Enable auto disable request feature */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_DREQ_MASK;
+ /* Enable major interrupt */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+
+ return kStatus_Success;
+ }
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ uint16_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+ int8_t tmpTcdUsed;
+ int8_t tmpTcdSize;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ tmpTcdUsed = handle->tcdUsed;
+ tmpTcdSize = handle->tcdSize;
+ if (tmpTcdUsed >= tmpTcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 1;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = currentTcd != 0 ? currentTcd - 1 : (handle->tcdSize - 1);
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ handle->tcdPool[currentTcd].DLAST_SGA =
+ MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA);
+#else
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = handle->tcdPool[previousTcd].CSR | ((uint16_t)DMA_CSR_ESG_MASK);
+ csr &= ~((uint16_t)DMA_CSR_DREQ_MASK);
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD block in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ if (tcdRegs->DLAST_SGA ==
+ MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[currentTcd], kMEMORY_Local2DMA))
+#else
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ {
+ /* Clear the DREQ bits for the dynamic scatter gather */
+ tcdRegs->CSR |= DMA_CSR_DREQ_MASK;
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = tcdRegs->CSR | DMA_CSR_ESG_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has not finished, so TCD dynamic
+ link succeed.
+ */
+ if (0U != (tcdRegs->CSR & DMA_CSR_ESG_MASK))
+ {
+ tcdRegs->CSR &= ~(uint16_t)DMA_CSR_DREQ_MASK;
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ if (tcdRegs->DLAST_SGA ==
+ MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA))
+#else
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0UL)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if (0U != (handle->flags & EDMA_TRANSFER_ENABLED_MASK))
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief eDMA starts transfer.
+ *
+ * This function enables the channel request. Users can call this function after submitting the transfer request
+ * or before submitting the transfer request.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_StartTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+ uint32_t tmpCSR = 0;
+
+ if (handle->tcdPool == NULL)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+
+ handle->flags |= EDMA_TRANSFER_ENABLED_MASK;
+
+ /* Check if there was at least one descriptor submitted since reset (TCD in registers is valid) */
+ if (tcdRegs->DLAST_SGA != 0U)
+ {
+ primask = DisableGlobalIRQ();
+ /* Check if channel request is actually disable. */
+ if ((handle->base->ERQ & ((uint32_t)1U << handle->channel)) == 0U)
+ {
+ /* Check if transfer is paused. */
+ tmpCSR = tcdRegs->CSR;
+ if ((0U == (tmpCSR & DMA_CSR_DONE_MASK)) || (0U != (tmpCSR & DMA_CSR_ESG_MASK)))
+ {
+ /*
+ Re-enable channel request must be as soon as possible, so must put it into
+ critical section to avoid task switching or interrupt service routine.
+ */
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ }
+ EnableGlobalIRQ(primask);
+ }
+ }
+}
+
+/*!
+ * brief eDMA stops transfer.
+ *
+ * This function disables the channel request to pause the transfer. Users can call EDMA_StartTransfer()
+ * again to resume the transfer.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_StopTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ handle->flags &= (~(uint8_t)EDMA_TRANSFER_ENABLED_MASK);
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+}
+
+/*!
+ * brief eDMA aborts transfer.
+ *
+ * This function disables the channel request and clear transfer status bits.
+ * Users can submit another transfer after calling this API.
+ *
+ * param handle DMA handle pointer.
+ */
+void EDMA_AbortTransfer(edma_handle_t *handle)
+{
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+ /*
+ Clear CSR to release channel. Because if the given channel started transfer,
+ CSR will be not zero. Because if it is the last transfer, DREQ will be set.
+ If not, ESG will be set.
+ */
+ handle->base->TCD[handle->channel].CSR = 0;
+ /* Cancel all next TCD transfer. */
+ handle->base->TCD[handle->channel].DLAST_SGA = 0;
+ /* clear the CITER and BITER to make sure the TCD register in a correct state for next calling of
+ * EDMA_SubmitTransfer */
+ handle->base->TCD[handle->channel].CITER_ELINKNO = 0;
+ handle->base->TCD[handle->channel].BITER_ELINKNO = 0;
+
+ /* Handle the tcd */
+ if (handle->tcdPool != NULL)
+ {
+ handle->header = 1;
+ handle->tail = 0;
+ handle->tcdUsed = 0;
+ }
+}
+
+/*!
+ * brief eDMA IRQ handler for the current major loop transfer completion.
+ *
+ * This function clears the channel major interrupt flag and calls
+ * the callback function if it is not NULL.
+ *
+ * Note:
+ * For the case using TCD queue, when the major iteration count is exhausted, additional operations are performed.
+ * These include the final address adjustments and reloading of the BITER field into the CITER.
+ * Assertion of an optional interrupt request also occurs at this time, as does a possible fetch of a new TCD from
+ * memory using the scatter/gather address pointer included in the descriptor (if scatter/gather is enabled).
+ *
+ * For instance, when the time interrupt of TCD[0] happens, the TCD[1] has already been loaded into the eDMA engine.
+ * As sga and sga_index are calculated based on the DLAST_SGA bitfield lies in the TCD_CSR register, the sga_index
+ * in this case should be 2 (DLAST_SGA of TCD[1] stores the address of TCD[2]). Thus, the "tcdUsed" updated should be
+ * (tcdUsed - 2U) which indicates the number of TCDs can be loaded in the memory pool (because TCD[0] and TCD[1] have
+ * been loaded into the eDMA engine at this point already.).
+ *
+ * For the last two continuous ISRs in a scatter/gather process, they both load the last TCD (The last ISR does not
+ * load a new TCD) from the memory pool to the eDMA engine when major loop completes.
+ * Therefore, ensure that the header and tcdUsed updated are identical for them.
+ * tcdUsed are both 0 in this case as no TCD to be loaded.
+ *
+ * See the "eDMA basic data flow" in the eDMA Functional description section of the Reference Manual for
+ * further details.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_HandleIRQ(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ bool transfer_done;
+
+ /* Clear EDMA interrupt flag */
+ handle->base->CINT = handle->channel;
+ /* Check if transfer is already finished. */
+ transfer_done = ((handle->base->TCD[handle->channel].CSR & DMA_CSR_DONE_MASK) != 0U);
+
+ if (handle->tcdPool == NULL)
+ {
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(handle, handle->userData, transfer_done, 0);
+ }
+ }
+ else /* Use the TCD queue. Please refer to the API descriptions in the eDMA header file for detailed information. */
+ {
+ uint32_t sga = (uint32_t)handle->base->TCD[handle->channel].DLAST_SGA;
+ uint32_t sga_index;
+ int32_t tcds_done;
+ uint8_t new_header;
+ bool esg = ((handle->base->TCD[handle->channel].CSR & DMA_CSR_ESG_MASK) != 0U);
+
+ /* Get the offset of the next transfer TCD blocks to be loaded into the eDMA engine. */
+#if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ sga -= MEMORY_ConvertMemoryMapAddress((uint32_t)handle->tcdPool, kMEMORY_Local2DMA);
+#else
+ sga -= (uint32_t)handle->tcdPool;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ /* Get the index of the next transfer TCD blocks to be loaded into the eDMA engine. */
+ sga_index = sga / sizeof(edma_tcd_t);
+ /* Adjust header positions. */
+ if (transfer_done)
+ {
+ /* New header shall point to the next TCD to be loaded (current one is already finished) */
+ new_header = (uint8_t)sga_index;
+ }
+ else
+ {
+ /* New header shall point to this descriptor currently loaded (not finished yet) */
+ new_header = sga_index != 0U ? (uint8_t)sga_index - 1U : (uint8_t)handle->tcdSize - 1U;
+ }
+ /* Calculate the number of finished TCDs */
+ if (new_header == (uint8_t)handle->header)
+ {
+ int8_t tmpTcdUsed = handle->tcdUsed;
+ int8_t tmpTcdSize = handle->tcdSize;
+
+ /* check esg here for the case that application submit only one request, once the request complete:
+ * new_header(1) = handle->header(1)
+ * tcdUsed(1) != tcdSize(>1)
+ * As the application submit only once, so scatter gather must not enabled, then tcds_done should be 1
+ */
+ if ((tmpTcdUsed == tmpTcdSize) || (!esg))
+ {
+ tcds_done = handle->tcdUsed;
+ }
+ else
+ {
+ /* No TCD in the memory are going to be loaded or internal error occurs. */
+ tcds_done = 0;
+ }
+ }
+ else
+ {
+ tcds_done = (int32_t)new_header - (int32_t)handle->header;
+ if (tcds_done < 0)
+ {
+ tcds_done += handle->tcdSize;
+ }
+ /*
+ * While code run to here, it means a TCD transfer Done and a new TCD has loaded to the hardware
+ * so clear DONE here to allow submit scatter gather transfer request in the callback to avoid TCD
+ * overwritten.
+ */
+ if (transfer_done)
+ {
+ handle->base->CDNE = handle->channel;
+ }
+ }
+ /* Advance header which points to the TCD to be loaded into the eDMA engine from memory. */
+ handle->header = (int8_t)new_header;
+ /* Release TCD blocks. tcdUsed is the TCD number which can be used/loaded in the memory pool. */
+ handle->tcdUsed -= (int8_t)tcds_done;
+ /* Invoke callback function. */
+ if (NULL != handle->callback)
+ {
+ (handle->callback)(handle, handle->userData, transfer_done, tcds_done);
+ }
+
+ /*
+ * 1.clear the DONE bit here is meaningful for below cases:
+ * A new TCD has been loaded to EDMA already:
+ * need to clear the DONE bit in the IRQ handler to avoid TCD in EDMA been overwritten
+ * if peripheral request isn't coming before next transfer request.
+ * 2. Don't clear DONE bit for below case,
+ * for the case that transfer request submitted in the privious edma callback, this is a case that doesn't
+ * need scatter gather, so keep DONE bit during the next transfer request submission will re-install the TCD and
+ * the DONE bit will be cleared together with TCD re-installation.
+ */
+ if (transfer_done)
+ {
+ if ((handle->base->TCD[handle->channel].CSR & DMA_CSR_ESG_MASK) != 0U)
+ {
+ handle->base->CDNE = handle->channel;
+ }
+ }
+ }
+}
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 4)
+/* 8 channels (Shared): kl28 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 8U)
+
+#if defined(DMA0)
+void DMA0_04_DriverIRQHandler(void);
+void DMA0_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_15_DriverIRQHandler(void);
+void DMA0_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_26_DriverIRQHandler(void);
+void DMA0_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_37_DriverIRQHandler(void);
+void DMA0_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA1)
+
+#if defined(DMA0)
+void DMA1_04_DriverIRQHandler(void);
+void DMA1_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_15_DriverIRQHandler(void);
+void DMA1_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_26_DriverIRQHandler(void);
+void DMA1_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_37_DriverIRQHandler(void);
+void DMA1_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+void DMA1_04_DriverIRQHandler(void);
+void DMA1_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_15_DriverIRQHandler(void);
+void DMA1_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_26_DriverIRQHandler(void);
+void DMA1_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_37_DriverIRQHandler(void);
+void DMA1_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif /* 8 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 8)
+/* 16 channels (Shared): K32H844P */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 16U)
+
+void DMA0_08_DriverIRQHandler(void);
+void DMA0_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_19_DriverIRQHandler(void);
+void DMA0_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_210_DriverIRQHandler(void);
+void DMA0_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_311_DriverIRQHandler(void);
+void DMA0_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_412_DriverIRQHandler(void);
+void DMA0_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_513_DriverIRQHandler(void);
+void DMA0_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_614_DriverIRQHandler(void);
+void DMA0_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_715_DriverIRQHandler(void);
+void DMA0_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if defined(DMA1)
+void DMA1_08_DriverIRQHandler(void);
+void DMA1_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_19_DriverIRQHandler(void);
+void DMA1_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_210_DriverIRQHandler(void);
+void DMA1_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_311_DriverIRQHandler(void);
+void DMA1_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_412_DriverIRQHandler(void);
+void DMA1_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_513_DriverIRQHandler(void);
+void DMA1_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_614_DriverIRQHandler(void);
+void DMA1_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_715_DriverIRQHandler(void);
+void DMA1_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif /* 16 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 16)
+/* 32 channels (Shared): k80 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U
+#if defined(DMA0)
+void DMA0_DMA16_DriverIRQHandler(void);
+void DMA0_DMA16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_DMA17_DriverIRQHandler(void);
+void DMA1_DMA17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA2_DMA18_DriverIRQHandler(void);
+void DMA2_DMA18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA3_DMA19_DriverIRQHandler(void);
+void DMA3_DMA19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA4_DMA20_DriverIRQHandler(void);
+void DMA4_DMA20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA5_DMA21_DriverIRQHandler(void);
+void DMA5_DMA21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA6_DMA22_DriverIRQHandler(void);
+void DMA6_DMA22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA7_DMA23_DriverIRQHandler(void);
+void DMA7_DMA23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA8_DMA24_DriverIRQHandler(void);
+void DMA8_DMA24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA9_DMA25_DriverIRQHandler(void);
+void DMA9_DMA25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA10_DMA26_DriverIRQHandler(void);
+void DMA10_DMA26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA11_DMA27_DriverIRQHandler(void);
+void DMA11_DMA27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA12_DMA28_DriverIRQHandler(void);
+void DMA12_DMA28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA13_DMA29_DriverIRQHandler(void);
+void DMA13_DMA29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA14_DMA30_DriverIRQHandler(void);
+void DMA14_DMA30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA15_DMA31_DriverIRQHandler(void);
+void DMA15_DMA31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+void DMA0_DMA16_DriverIRQHandler(void);
+void DMA0_DMA16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_DMA17_DriverIRQHandler(void);
+void DMA1_DMA17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA2_DMA18_DriverIRQHandler(void);
+void DMA2_DMA18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA3_DMA19_DriverIRQHandler(void);
+void DMA3_DMA19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA4_DMA20_DriverIRQHandler(void);
+void DMA4_DMA20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA5_DMA21_DriverIRQHandler(void);
+void DMA5_DMA21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA6_DMA22_DriverIRQHandler(void);
+void DMA6_DMA22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA7_DMA23_DriverIRQHandler(void);
+void DMA7_DMA23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA8_DMA24_DriverIRQHandler(void);
+void DMA8_DMA24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA9_DMA25_DriverIRQHandler(void);
+void DMA9_DMA25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA10_DMA26_DriverIRQHandler(void);
+void DMA10_DMA26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA11_DMA27_DriverIRQHandler(void);
+void DMA11_DMA27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA12_DMA28_DriverIRQHandler(void);
+void DMA12_DMA28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA13_DMA29_DriverIRQHandler(void);
+void DMA13_DMA29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA14_DMA30_DriverIRQHandler(void);
+void DMA14_DMA30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA15_DMA31_DriverIRQHandler(void);
+void DMA15_DMA31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#endif
+#endif /* 32 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 4)
+/* 32 channels (Shared): MCIMX7U5_M4 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U)
+
+void DMA0_0_4_DriverIRQHandler(void);
+void DMA0_0_4_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_1_5_DriverIRQHandler(void);
+void DMA0_1_5_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_2_6_DriverIRQHandler(void);
+void DMA0_2_6_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_3_7_DriverIRQHandler(void);
+void DMA0_3_7_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_8_12_DriverIRQHandler(void);
+void DMA0_8_12_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_9_13_DriverIRQHandler(void);
+void DMA0_9_13_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_10_14_DriverIRQHandler(void);
+void DMA0_10_14_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_11_15_DriverIRQHandler(void);
+void DMA0_11_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_16_20_DriverIRQHandler(void);
+void DMA0_16_20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_17_21_DriverIRQHandler(void);
+void DMA0_17_21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_18_22_DriverIRQHandler(void);
+void DMA0_18_22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_19_23_DriverIRQHandler(void);
+void DMA0_19_23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_24_28_DriverIRQHandler(void);
+void DMA0_24_28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_25_29_DriverIRQHandler(void);
+void DMA0_25_29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_26_30_DriverIRQHandler(void);
+void DMA0_26_30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_27_31_DriverIRQHandler(void);
+void DMA0_27_31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* 32 channels (Shared): MCIMX7U5 */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 0)
+/* 4 channels (No Shared): kv10 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 0)
+
+void DMA0_DriverIRQHandler(void);
+void DMA0_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_DriverIRQHandler(void);
+void DMA1_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA2_DriverIRQHandler(void);
+void DMA2_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA3_DriverIRQHandler(void);
+void DMA3_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+/* 8 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 4U)
+
+void DMA4_DriverIRQHandler(void);
+void DMA4_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA5_DriverIRQHandler(void);
+void DMA5_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA6_DriverIRQHandler(void);
+void DMA6_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA7_DriverIRQHandler(void);
+void DMA7_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 8 */
+
+/* 16 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 8U)
+
+void DMA8_DriverIRQHandler(void);
+void DMA8_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA9_DriverIRQHandler(void);
+void DMA9_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA10_DriverIRQHandler(void);
+void DMA10_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA11_DriverIRQHandler(void);
+void DMA11_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA12_DriverIRQHandler(void);
+void DMA12_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA13_DriverIRQHandler(void);
+void DMA13_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA14_DriverIRQHandler(void);
+void DMA14_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA15_DriverIRQHandler(void);
+void DMA15_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 16 */
+
+/* 32 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 16U)
+
+void DMA16_DriverIRQHandler(void);
+void DMA16_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA17_DriverIRQHandler(void);
+void DMA17_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA18_DriverIRQHandler(void);
+void DMA18_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA19_DriverIRQHandler(void);
+void DMA19_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA20_DriverIRQHandler(void);
+void DMA20_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA21_DriverIRQHandler(void);
+void DMA21_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA22_DriverIRQHandler(void);
+void DMA22_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA23_DriverIRQHandler(void);
+void DMA23_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA24_DriverIRQHandler(void);
+void DMA24_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA25_DriverIRQHandler(void);
+void DMA25_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA26_DriverIRQHandler(void);
+void DMA26_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA27_DriverIRQHandler(void);
+void DMA27_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA28_DriverIRQHandler(void);
+void DMA28_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA29_DriverIRQHandler(void);
+void DMA29_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA30_DriverIRQHandler(void);
+void DMA30_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA31_DriverIRQHandler(void);
+void DMA31_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 32 */
+
+#endif /* 4/8/16/32 channels (No Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.h
new file mode 100644
index 0000000000..3d31f88365
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/edma/fsl_edma.h
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_EDMA_H_
+#define _FSL_EDMA_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup edma
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief eDMA driver version */
+#define FSL_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 3)) /*!< Version 2.4.3. */
+/*@}*/
+
+/*! @brief Compute the offset unit from DCHPRI3 */
+#define DMA_DCHPRI_INDEX(channel) (((channel) & ~0x03U) | (3U - ((channel)&0x03U)))
+
+/*! @brief eDMA transfer configuration */
+typedef enum _edma_transfer_size
+{
+ kEDMA_TransferSize1Bytes = 0x0U, /*!< Source/Destination data transfer size is 1 byte every time */
+ kEDMA_TransferSize2Bytes = 0x1U, /*!< Source/Destination data transfer size is 2 bytes every time */
+ kEDMA_TransferSize4Bytes = 0x2U, /*!< Source/Destination data transfer size is 4 bytes every time */
+ kEDMA_TransferSize8Bytes = 0x3U, /*!< Source/Destination data transfer size is 8 bytes every time */
+ kEDMA_TransferSize16Bytes = 0x4U, /*!< Source/Destination data transfer size is 16 bytes every time */
+ kEDMA_TransferSize32Bytes = 0x5U, /*!< Source/Destination data transfer size is 32 bytes every time */
+} edma_transfer_size_t;
+
+/*! @brief eDMA modulo configuration */
+typedef enum _edma_modulo
+{
+ kEDMA_ModuloDisable = 0x0U, /*!< Disable modulo */
+ kEDMA_Modulo2bytes, /*!< Circular buffer size is 2 bytes. */
+ kEDMA_Modulo4bytes, /*!< Circular buffer size is 4 bytes. */
+ kEDMA_Modulo8bytes, /*!< Circular buffer size is 8 bytes. */
+ kEDMA_Modulo16bytes, /*!< Circular buffer size is 16 bytes. */
+ kEDMA_Modulo32bytes, /*!< Circular buffer size is 32 bytes. */
+ kEDMA_Modulo64bytes, /*!< Circular buffer size is 64 bytes. */
+ kEDMA_Modulo128bytes, /*!< Circular buffer size is 128 bytes. */
+ kEDMA_Modulo256bytes, /*!< Circular buffer size is 256 bytes. */
+ kEDMA_Modulo512bytes, /*!< Circular buffer size is 512 bytes. */
+ kEDMA_Modulo1Kbytes, /*!< Circular buffer size is 1 K bytes. */
+ kEDMA_Modulo2Kbytes, /*!< Circular buffer size is 2 K bytes. */
+ kEDMA_Modulo4Kbytes, /*!< Circular buffer size is 4 K bytes. */
+ kEDMA_Modulo8Kbytes, /*!< Circular buffer size is 8 K bytes. */
+ kEDMA_Modulo16Kbytes, /*!< Circular buffer size is 16 K bytes. */
+ kEDMA_Modulo32Kbytes, /*!< Circular buffer size is 32 K bytes. */
+ kEDMA_Modulo64Kbytes, /*!< Circular buffer size is 64 K bytes. */
+ kEDMA_Modulo128Kbytes, /*!< Circular buffer size is 128 K bytes. */
+ kEDMA_Modulo256Kbytes, /*!< Circular buffer size is 256 K bytes. */
+ kEDMA_Modulo512Kbytes, /*!< Circular buffer size is 512 K bytes. */
+ kEDMA_Modulo1Mbytes, /*!< Circular buffer size is 1 M bytes. */
+ kEDMA_Modulo2Mbytes, /*!< Circular buffer size is 2 M bytes. */
+ kEDMA_Modulo4Mbytes, /*!< Circular buffer size is 4 M bytes. */
+ kEDMA_Modulo8Mbytes, /*!< Circular buffer size is 8 M bytes. */
+ kEDMA_Modulo16Mbytes, /*!< Circular buffer size is 16 M bytes. */
+ kEDMA_Modulo32Mbytes, /*!< Circular buffer size is 32 M bytes. */
+ kEDMA_Modulo64Mbytes, /*!< Circular buffer size is 64 M bytes. */
+ kEDMA_Modulo128Mbytes, /*!< Circular buffer size is 128 M bytes. */
+ kEDMA_Modulo256Mbytes, /*!< Circular buffer size is 256 M bytes. */
+ kEDMA_Modulo512Mbytes, /*!< Circular buffer size is 512 M bytes. */
+ kEDMA_Modulo1Gbytes, /*!< Circular buffer size is 1 G bytes. */
+ kEDMA_Modulo2Gbytes, /*!< Circular buffer size is 2 G bytes. */
+} edma_modulo_t;
+
+/*! @brief Bandwidth control */
+typedef enum _edma_bandwidth
+{
+ kEDMA_BandwidthStallNone = 0x0U, /*!< No eDMA engine stalls. */
+ kEDMA_BandwidthStall4Cycle = 0x2U, /*!< eDMA engine stalls for 4 cycles after each read/write. */
+ kEDMA_BandwidthStall8Cycle = 0x3U, /*!< eDMA engine stalls for 8 cycles after each read/write. */
+} edma_bandwidth_t;
+
+/*! @brief Channel link type */
+typedef enum _edma_channel_link_type
+{
+ kEDMA_LinkNone = 0x0U, /*!< No channel link */
+ kEDMA_MinorLink, /*!< Channel link after each minor loop */
+ kEDMA_MajorLink, /*!< Channel link while major loop count exhausted */
+} edma_channel_link_type_t;
+
+/*!@brief _edma_channel_status_flags eDMA channel status flags. */
+enum
+{
+ kEDMA_DoneFlag = 0x1U, /*!< DONE flag, set while transfer finished, CITER value exhausted*/
+ kEDMA_ErrorFlag = 0x2U, /*!< eDMA error flag, an error occurred in a transfer */
+ kEDMA_InterruptFlag = 0x4U, /*!< eDMA interrupt flag, set while an interrupt occurred of this channel */
+};
+
+/*! @brief _edma_error_status_flags eDMA channel error status flags. */
+enum
+{
+ kEDMA_DestinationBusErrorFlag = DMA_ES_DBE_MASK, /*!< Bus error on destination address */
+ kEDMA_SourceBusErrorFlag = DMA_ES_SBE_MASK, /*!< Bus error on the source address */
+ kEDMA_ScatterGatherErrorFlag = DMA_ES_SGE_MASK, /*!< Error on the Scatter/Gather address, not 32byte aligned. */
+ kEDMA_NbytesErrorFlag = DMA_ES_NCE_MASK, /*!< NBYTES/CITER configuration error */
+ kEDMA_DestinationOffsetErrorFlag = DMA_ES_DOE_MASK, /*!< Destination offset not aligned with destination size */
+ kEDMA_DestinationAddressErrorFlag = DMA_ES_DAE_MASK, /*!< Destination address not aligned with destination size */
+ kEDMA_SourceOffsetErrorFlag = DMA_ES_SOE_MASK, /*!< Source offset not aligned with source size */
+ kEDMA_SourceAddressErrorFlag = DMA_ES_SAE_MASK, /*!< Source address not aligned with source size*/
+ kEDMA_ErrorChannelFlag = DMA_ES_ERRCHN_MASK, /*!< Error channel number of the cancelled channel number */
+ kEDMA_ChannelPriorityErrorFlag = DMA_ES_CPE_MASK, /*!< Channel priority is not unique. */
+ kEDMA_TransferCanceledFlag = DMA_ES_ECX_MASK, /*!< Transfer cancelled */
+#if defined(FSL_FEATURE_EDMA_CHANNEL_GROUP_COUNT) && (FSL_FEATURE_EDMA_CHANNEL_GROUP_COUNT > 1)
+ kEDMA_GroupPriorityErrorFlag = DMA_ES_GPE_MASK, /*!< Group priority is not unique. */
+#endif
+ kEDMA_ValidFlag = (int)DMA_ES_VLD_MASK, /*!< No error occurred, this bit is 0. Otherwise, it is 1. */
+};
+
+/*! @brief eDMA interrupt source */
+typedef enum _edma_interrupt_enable
+{
+ kEDMA_ErrorInterruptEnable = 0x1U, /*!< Enable interrupt while channel error occurs. */
+ kEDMA_MajorInterruptEnable = DMA_CSR_INTMAJOR_MASK, /*!< Enable interrupt while major count exhausted. */
+ kEDMA_HalfInterruptEnable = DMA_CSR_INTHALF_MASK, /*!< Enable interrupt while major count to half value. */
+} edma_interrupt_enable_t;
+
+/*! @brief eDMA transfer type */
+typedef enum _edma_transfer_type
+{
+ kEDMA_MemoryToMemory = 0x0U, /*!< Transfer from memory to memory */
+ kEDMA_PeripheralToMemory, /*!< Transfer from peripheral to memory */
+ kEDMA_MemoryToPeripheral, /*!< Transfer from memory to peripheral */
+ kEDMA_PeripheralToPeripheral, /*!< Transfer from Peripheral to peripheral */
+} edma_transfer_type_t;
+
+/*! @brief _edma_transfer_status eDMA transfer status */
+enum
+{
+ kStatus_EDMA_QueueFull = MAKE_STATUS(kStatusGroup_EDMA, 0), /*!< TCD queue is full. */
+ kStatus_EDMA_Busy = MAKE_STATUS(kStatusGroup_EDMA, 1), /*!< Channel is busy and can't handle the
+ transfer request. */
+};
+
+/*! @brief eDMA global configuration structure.*/
+typedef struct _edma_config
+{
+ bool enableContinuousLinkMode; /*!< Enable (true) continuous link mode. Upon minor loop completion, the channel
+ activates again if that channel has a minor loop channel link enabled and
+ the link channel is itself. */
+ bool enableHaltOnError; /*!< Enable (true) transfer halt on error. Any error causes the HALT bit to set.
+ Subsequently, all service requests are ignored until the HALT bit is cleared.*/
+ bool enableRoundRobinArbitration; /*!< Enable (true) round robin channel arbitration method or fixed priority
+ arbitration is used for channel selection */
+ bool enableDebugMode; /*!< Enable(true) eDMA debug mode. When in debug mode, the eDMA stalls the start of
+ a new channel. Executing channels are allowed to complete. */
+} edma_config_t;
+
+/*!
+ * @brief eDMA transfer configuration
+ *
+ * This structure configures the source/destination transfer attribute.
+ */
+typedef struct _edma_transfer_config
+{
+ uint32_t srcAddr; /*!< Source data address. */
+ uint32_t destAddr; /*!< Destination data address. */
+ edma_transfer_size_t srcTransferSize; /*!< Source data transfer size. */
+ edma_transfer_size_t destTransferSize; /*!< Destination data transfer size. */
+ int16_t srcOffset; /*!< Sign-extended offset applied to the current source address to
+ form the next-state value as each source read is completed. */
+ int16_t destOffset; /*!< Sign-extended offset applied to the current destination address to
+ form the next-state value as each destination write is completed. */
+ uint32_t minorLoopBytes; /*!< Bytes to transfer in a minor loop*/
+ uint32_t majorLoopCounts; /*!< Major loop iteration count. */
+} edma_transfer_config_t;
+
+/*! @brief eDMA channel priority configuration */
+typedef struct _edma_channel_Preemption_config
+{
+ bool enableChannelPreemption; /*!< If true: a channel can be suspended by other channel with higher priority */
+ bool enablePreemptAbility; /*!< If true: a channel can suspend other channel with low priority */
+ uint8_t channelPriority; /*!< Channel priority */
+} edma_channel_Preemption_config_t;
+
+/*! @brief eDMA minor offset configuration */
+typedef struct _edma_minor_offset_config
+{
+ bool enableSrcMinorOffset; /*!< Enable(true) or Disable(false) source minor loop offset. */
+ bool enableDestMinorOffset; /*!< Enable(true) or Disable(false) destination minor loop offset. */
+ uint32_t minorOffset; /*!< Offset for a minor loop mapping. */
+} edma_minor_offset_config_t;
+
+/*!
+ * @brief eDMA TCD.
+ *
+ * This structure is same as TCD register which is described in reference manual,
+ * and is used to configure the scatter/gather feature as a next hardware TCD.
+ */
+typedef struct _edma_tcd
+{
+ __IO uint32_t SADDR; /*!< SADDR register, used to save source address */
+ __IO uint16_t SOFF; /*!< SOFF register, save offset bytes every transfer */
+ __IO uint16_t ATTR; /*!< ATTR register, source/destination transfer size and modulo */
+ __IO uint32_t NBYTES; /*!< Nbytes register, minor loop length in bytes */
+ __IO uint32_t SLAST; /*!< SLAST register */
+ __IO uint32_t DADDR; /*!< DADDR register, used for destination address */
+ __IO uint16_t DOFF; /*!< DOFF register, used for destination offset */
+ __IO uint16_t CITER; /*!< CITER register, current minor loop numbers, for unfinished minor loop.*/
+ __IO uint32_t DLAST_SGA; /*!< DLASTSGA register, next tcd address used in scatter-gather mode */
+ __IO uint16_t CSR; /*!< CSR register, for TCD control status */
+ __IO uint16_t BITER; /*!< BITER register, begin minor loop count. */
+} edma_tcd_t;
+
+/*! @brief Callback for eDMA */
+struct _edma_handle;
+
+/*! @brief Define callback function for eDMA.
+ *
+ * This callback function is called in the EDMA interrupt handle.
+ * In normal mode, run into callback function means the transfer users need is done.
+ * In scatter gather mode, run into callback function means a transfer control block (tcd) is finished. Not
+ * all transfer finished, users can get the finished tcd numbers using interface EDMA_GetUnusedTCDNumber.
+ *
+ * @param handle EDMA handle pointer, users shall not touch the values inside.
+ * @param userData The callback user parameter pointer. Users can use this parameter to involve things users need to
+ * change in EDMA callback function.
+ * @param transferDone If the current loaded transfer done. In normal mode it means if all transfer done. In scatter
+ * gather mode, this parameter shows is the current transfer block in EDMA register is done. As the
+ * load of core is different, it will be different if the new tcd loaded into EDMA registers while
+ * this callback called. If true, it always means new tcd still not loaded into registers, while
+ * false means new tcd already loaded into registers.
+ * @param tcds How many tcds are done from the last callback. This parameter only used in scatter gather mode. It
+ * tells user how many tcds are finished between the last callback and this.
+ */
+typedef void (*edma_callback)(struct _edma_handle *handle, void *userData, bool transferDone, uint32_t tcds);
+
+/*! @brief eDMA transfer handle structure */
+typedef struct _edma_handle
+{
+ edma_callback callback; /*!< Callback function for major count exhausted. */
+ void *userData; /*!< Callback function parameter. */
+ DMA_Type *base; /*!< eDMA peripheral base address. */
+ edma_tcd_t *tcdPool; /*!< Pointer to memory stored TCDs. */
+ uint8_t channel; /*!< eDMA channel number. */
+ volatile int8_t header; /*!< The first TCD index. Should point to the next TCD to be loaded into the eDMA engine. */
+ volatile int8_t tail; /*!< The last TCD index. Should point to the next TCD to be stored into the memory pool. */
+ volatile int8_t tcdUsed; /*!< The number of used TCD slots. Should reflect the number of TCDs can be used/loaded in
+ the memory. */
+ volatile int8_t tcdSize; /*!< The total number of TCD slots in the queue. */
+ uint8_t flags; /*!< The status of the current channel. */
+} edma_handle_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name eDMA initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the eDMA peripheral.
+ *
+ * This function ungates the eDMA clock and configures the eDMA peripheral according
+ * to the configuration structure.
+ *
+ * @param base eDMA peripheral base address.
+ * @param config A pointer to the configuration structure, see "edma_config_t".
+ * @note This function enables the minor loop map feature.
+ */
+void EDMA_Init(DMA_Type *base, const edma_config_t *config);
+
+/*!
+ * @brief Deinitializes the eDMA peripheral.
+ *
+ * This function gates the eDMA clock.
+ *
+ * @param base eDMA peripheral base address.
+ */
+void EDMA_Deinit(DMA_Type *base);
+
+/*!
+ * @brief Push content of TCD structure into hardware TCD register.
+ *
+ * @param base EDMA peripheral base address.
+ * @param channel EDMA channel number.
+ * @param tcd Point to TCD structure.
+ */
+void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd);
+
+/*!
+ * @brief Gets the eDMA default configuration structure.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * @code
+ * config.enableContinuousLinkMode = false;
+ * config.enableHaltOnError = true;
+ * config.enableRoundRobinArbitration = false;
+ * config.enableDebugMode = false;
+ * @endcode
+ *
+ * @param config A pointer to the eDMA configuration structure.
+ */
+void EDMA_GetDefaultConfig(edma_config_t *config);
+
+/*!
+ * @brief Enable/Disable continuous channel link mode.
+ *
+ * @note Do not use continuous link mode with a channel linking to itself if there is only one minor loop
+ * iteration per service request, for example, if the channel's NBYTES value is the same as either
+ * the source or destination size. The same data transfer profile can be achieved by simply
+ * increasing the NBYTES value, which provides more efficient, faster processing.
+ *
+ * @param base EDMA peripheral base address.
+ * @param enable true is enable, false is disable.
+ */
+static inline void EDMA_EnableContinuousChannelLinkMode(DMA_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR |= DMA_CR_CLM_MASK;
+ }
+ else
+ {
+ base->CR &= ~DMA_CR_CLM_MASK;
+ }
+}
+
+/*!
+ * @brief Enable/Disable minor loop mapping.
+ *
+ * The TCDn.word2 is redefined to include individual enable fields, an offset field, and the
+ * NBYTES field.
+ *
+ * @param base EDMA peripheral base address.
+ * @param enable true is enable, false is disable.
+ */
+static inline void EDMA_EnableMinorLoopMapping(DMA_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR |= DMA_CR_EMLM_MASK;
+ }
+ else
+ {
+ base->CR &= ~DMA_CR_EMLM_MASK;
+ }
+}
+
+/* @} */
+/*!
+ * @name eDMA Channel Operation
+ * @{
+ */
+
+/*!
+ * @brief Sets all TCD registers to default values.
+ *
+ * This function sets TCD registers for this channel to default values.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @note This function must not be called while the channel transfer is ongoing
+ * or it causes unpredictable results.
+ * @note This function enables the auto stop request feature.
+ */
+void EDMA_ResetChannel(DMA_Type *base, uint32_t channel);
+
+/*!
+ * @brief Configures the eDMA transfer attribute.
+ *
+ * This function configures the transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the TCD address.
+ * Example:
+ * @code
+ * edma_transfer_t config;
+ * edma_tcd_t tcd;
+ * config.srcAddr = ..;
+ * config.destAddr = ..;
+ * ...
+ * EDMA_SetTransferConfig(DMA0, channel, &config, &stcd);
+ * @endcode
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param config Pointer to eDMA transfer configuration structure.
+ * @param nextTcd Point to TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * @note If nextTcd is not NULL, it means scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the eDMA_ResetChannel.
+ */
+void EDMA_SetTransferConfig(DMA_Type *base,
+ uint32_t channel,
+ const edma_transfer_config_t *config,
+ edma_tcd_t *nextTcd);
+
+/*!
+ * @brief Configures the eDMA minor offset feature.
+ *
+ * The minor offset means that the signed-extended value is added to the source address or destination
+ * address after each minor loop.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_SetMinorOffsetConfig(DMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config);
+
+/*!
+ * @brief Configures the eDMA channel preemption feature.
+ *
+ * This function configures the channel preemption attribute and the priority of the channel.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number
+ * @param config A pointer to the channel preemption configuration structure.
+ */
+void EDMA_SetChannelPreemptionConfig(DMA_Type *base, uint32_t channel, const edma_channel_Preemption_config_t *config);
+
+/*!
+ * @brief Sets the channel link for the eDMA transfer.
+ *
+ * This function configures either the minor link or the major link mode. The minor link means that the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param linkType A channel link type, which can be one of the following:
+ * @arg kEDMA_LinkNone
+ * @arg kEDMA_MinorLink
+ * @arg kEDMA_MajorLink
+ * @param linkedChannel The linked channel number.
+ * @note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ */
+void EDMA_SetChannelLink(DMA_Type *base, uint32_t channel, edma_channel_link_type_t linkType, uint32_t linkedChannel);
+
+/*!
+ * @brief Sets the bandwidth for the eDMA transfer.
+ *
+ * Because the eDMA processes the minor loop, it continuously generates read/write sequences
+ * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
+ * each read/write access to control the bus request bandwidth seen by the crossbar switch.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param bandWidth A bandwidth setting, which can be one of the following:
+ * @arg kEDMABandwidthStallNone
+ * @arg kEDMABandwidthStall4Cycle
+ * @arg kEDMABandwidthStall8Cycle
+ */
+void EDMA_SetBandWidth(DMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth);
+
+/*!
+ * @brief Sets the source modulo and the destination modulo for the eDMA transfer.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param srcModulo A source modulo value.
+ * @param destModulo A destination modulo value.
+ */
+void EDMA_SetModulo(DMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo);
+
+#if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT
+/*!
+ * @brief Enables an async request for the eDMA transfer.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param enable The command to enable (true) or disable (false).
+ */
+static inline void EDMA_EnableAsyncRequest(DMA_Type *base, uint32_t channel, bool enable)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->EARS &= ~((uint32_t)1U << channel);
+ base->EARS |= ((uint32_t)(true == enable ? 1U : 0U) << channel);
+}
+#endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */
+
+/*!
+ * @brief Enables an auto stop request for the eDMA transfer.
+ *
+ * If enabling the auto stop request, the eDMA hardware automatically disables the hardware channel request.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param enable The command to enable (true) or disable (false).
+ */
+static inline void EDMA_EnableAutoStopRequest(DMA_Type *base, uint32_t channel, bool enable)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->TCD[channel].CSR =
+ (uint16_t)((base->TCD[channel].CSR & (~DMA_CSR_DREQ_MASK)) | DMA_CSR_DREQ((true == enable ? 1U : 0U)));
+}
+
+/*!
+ * @brief Enables the interrupt source for the eDMA transfer.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask);
+
+/*!
+ * @brief Disables the interrupt source for the eDMA transfer.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param mask The mask of the interrupt source to be set. Use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask);
+
+/*!
+ * @brief Configures the eDMA channel TCD major offset feature.
+ *
+ * Adjustment value added to the source address at the completion of the major iteration count
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel edma channel number.
+ * @param sourceOffset source address offset will be applied to source address after major loop done.
+ * @param destOffset destination address offset will be applied to source address after major loop done.
+ */
+void EDMA_SetMajorOffsetConfig(DMA_Type *base, uint32_t channel, int32_t sourceOffset, int32_t destOffset);
+
+/* @} */
+/*!
+ * @name eDMA TCD Operation
+ * @{
+ */
+
+/*!
+ * @brief Sets all fields to default values for the TCD structure.
+ *
+ * This function sets all fields for this TCD structure to default value.
+ *
+ * @param tcd Pointer to the TCD structure.
+ * @note This function enables the auto stop request feature.
+ */
+void EDMA_TcdReset(edma_tcd_t *tcd);
+
+/*!
+ * @brief Configures the eDMA TCD transfer attribute.
+ *
+ * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
+ * The TCD is used in the scatter-gather mode.
+ * This function configures the TCD transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the next TCD address.
+ * Example:
+ * @code
+ * edma_transfer_t config = {
+ * ...
+ * }
+ * edma_tcd_t tcd __aligned(32);
+ * edma_tcd_t nextTcd __aligned(32);
+ * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
+ * @endcode
+ *
+ * @param tcd Pointer to the TCD structure.
+ * @param config Pointer to eDMA transfer configuration structure.
+ * @param nextTcd Pointer to the next TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * @note TCD address should be 32 bytes aligned or it causes an eDMA error.
+ * @note If the nextTcd is not NULL, the scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the EDMA_TcdReset.
+ */
+void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd);
+
+/*!
+ * @brief Configures the eDMA TCD minor offset feature.
+ *
+ * A minor offset is a signed-extended value added to the source address or a destination
+ * address after each minor loop.
+ *
+ * @param tcd A point to the TCD structure.
+ * @param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config);
+
+/*!
+ * @brief Sets the channel link for the eDMA TCD.
+ *
+ * This function configures either a minor link or a major link. The minor link means the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * @note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ * @param tcd Point to the TCD structure.
+ * @param linkType Channel link type, it can be one of:
+ * @arg kEDMA_LinkNone
+ * @arg kEDMA_MinorLink
+ * @arg kEDMA_MajorLink
+ * @param linkedChannel The linked channel number.
+ */
+void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t linkType, uint32_t linkedChannel);
+
+/*!
+ * @brief Sets the bandwidth for the eDMA TCD.
+ *
+ * Because the eDMA processes the minor loop, it continuously generates read/write sequences
+ * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
+ * each read/write access to control the bus request bandwidth seen by the crossbar switch.
+ * @param tcd A pointer to the TCD structure.
+ * @param bandWidth A bandwidth setting, which can be one of the following:
+ * @arg kEDMABandwidthStallNone
+ * @arg kEDMABandwidthStall4Cycle
+ * @arg kEDMABandwidthStall8Cycle
+ */
+static inline void EDMA_TcdSetBandWidth(edma_tcd_t *tcd, edma_bandwidth_t bandWidth)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ tcd->CSR = (uint16_t)((tcd->CSR & (~DMA_CSR_BWC_MASK)) | DMA_CSR_BWC(bandWidth));
+}
+
+/*!
+ * @brief Sets the source modulo and the destination modulo for the eDMA TCD.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * @param tcd A pointer to the TCD structure.
+ * @param srcModulo A source modulo value.
+ * @param destModulo A destination modulo value.
+ */
+void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo);
+
+/*!
+ * @brief Sets the auto stop request for the eDMA TCD.
+ *
+ * If enabling the auto stop request, the eDMA hardware automatically disables the hardware channel request.
+ *
+ * @param tcd A pointer to the TCD structure.
+ * @param enable The command to enable (true) or disable (false).
+ */
+static inline void EDMA_TcdEnableAutoStopRequest(edma_tcd_t *tcd, bool enable)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ tcd->CSR = (uint16_t)((tcd->CSR & (~DMA_CSR_DREQ_MASK)) | DMA_CSR_DREQ((true == enable ? 1U : 0U)));
+}
+
+/*!
+ * @brief Enables the interrupt source for the eDMA TCD.
+ *
+ * @param tcd Point to the TCD structure.
+ * @param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask);
+
+/*!
+ * @brief Disables the interrupt source for the eDMA TCD.
+ *
+ * @param tcd Point to the TCD structure.
+ * @param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask);
+
+/*!
+ * @brief Configures the eDMA TCD major offset feature.
+ *
+ * Adjustment value added to the source address at the completion of the major iteration count
+ *
+ * @param tcd A point to the TCD structure.
+ * @param sourceOffset source address offset wiil be applied to source address after major loop done.
+ * @param destOffset destination address offset will be applied to source address after major loop done.
+ */
+void EDMA_TcdSetMajorOffsetConfig(edma_tcd_t *tcd, int32_t sourceOffset, int32_t destOffset);
+
+/*! @} */
+/*!
+ * @name eDMA Channel Transfer Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables the eDMA hardware channel request.
+ *
+ * This function enables the hardware channel request.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ */
+static inline void EDMA_EnableChannelRequest(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->SERQ = DMA_SERQ_SERQ(channel);
+}
+
+/*!
+ * @brief Disables the eDMA hardware channel request.
+ *
+ * This function disables the hardware channel request.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ */
+static inline void EDMA_DisableChannelRequest(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->CERQ = DMA_CERQ_CERQ(channel);
+}
+
+/*!
+ * @brief Starts the eDMA transfer by using the software trigger.
+ *
+ * This function starts a minor loop transfer.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ */
+static inline void EDMA_TriggerChannelStart(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_DMAMUX_MODULE_CHANNEL);
+
+ base->SSRT = DMA_SSRT_SSRT(channel);
+}
+
+/*! @} */
+/*!
+ * @name eDMA Channel Status Operation
+ * @{
+ */
+
+/*!
+ * @brief Gets the remaining major loop count from the eDMA current channel TCD.
+ *
+ * This function checks the TCD (Task Control Descriptor) status for a specified
+ * eDMA channel and returns the number of major loop count that has not finished.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @return Major loop count which has not been transferred yet for the current TCD.
+ * @note 1. This function can only be used to get unfinished major loop count of transfer without
+ * the next TCD, or it might be inaccuracy.
+ * 2. The unfinished/remaining transfer bytes cannot be obtained directly from registers while
+ * the channel is running.
+ * Because to calculate the remaining bytes, the initial NBYTES configured in DMA_TCDn_NBYTES_MLNO
+ * register is needed while the eDMA IP does not support getting it while a channel is active.
+ * In another word, the NBYTES value reading is always the actual (decrementing) NBYTES value the dma_engine
+ * is working with while a channel is running.
+ * Consequently, to get the remaining transfer bytes, a software-saved initial value of NBYTES (for example
+ * copied before enabling the channel) is needed. The formula to calculate it is shown below:
+ * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
+ */
+uint32_t EDMA_GetRemainingMajorLoopCount(DMA_Type *base, uint32_t channel);
+
+/*!
+ * @brief Gets the eDMA channel error status flags.
+ *
+ * @param base eDMA peripheral base address.
+ * @return The mask of error status flags. Users need to use the
+ * _edma_error_status_flags type to decode the return variables.
+ */
+static inline uint32_t EDMA_GetErrorStatusFlags(DMA_Type *base)
+{
+ return base->ES;
+}
+
+/*!
+ * @brief Gets the eDMA channel status flags.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @return The mask of channel status flags. Users need to use the
+ * _edma_channel_status_flags type to decode the return variables.
+ */
+uint32_t EDMA_GetChannelStatusFlags(DMA_Type *base, uint32_t channel);
+
+/*!
+ * @brief Clears the eDMA channel status flags.
+ *
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ * @param mask The mask of channel status to be cleared. Users need to use
+ * the defined _edma_channel_status_flags type.
+ */
+void EDMA_ClearChannelStatusFlags(DMA_Type *base, uint32_t channel, uint32_t mask);
+
+/*! @} */
+/*!
+ * @name eDMA Transactional Operation
+ */
+
+/*!
+ * @brief Creates the eDMA handle.
+ *
+ * This function is called if using the transactional API for eDMA. This function
+ * initializes the internal state of the eDMA handle.
+ *
+ * @param handle eDMA handle pointer. The eDMA handle stores callback function and
+ * parameters.
+ * @param base eDMA peripheral base address.
+ * @param channel eDMA channel number.
+ */
+void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel);
+
+/*!
+ * @brief Installs the TCDs memory pool into the eDMA handle.
+ *
+ * This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
+ * while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
+ * (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
+ * Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
+ *
+ * @param handle eDMA handle pointer.
+ * @param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
+ * @param tcdSize The number of TCD slots.
+ */
+void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize);
+
+/*!
+ * @brief Installs a callback function for the eDMA transfer.
+ *
+ * This callback is called in the eDMA IRQ handler. Use the callback to do something after
+ * the current major loop transfer completes. This function will be called every time one tcd finished transfer.
+ *
+ * @param handle eDMA handle pointer.
+ * @param callback eDMA callback function pointer.
+ * @param userData A parameter for the callback function.
+ */
+void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData);
+
+/*!
+ * @brief Prepares the eDMA transfer structure configurations.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * @param config The user configuration structure of type edma_transfer_t.
+ * @param srcAddr eDMA transfer source address.
+ * @param srcWidth eDMA transfer source address width(bytes).
+ * @param srcOffset source address offset.
+ * @param destAddr eDMA transfer destination address.
+ * @param destWidth eDMA transfer destination address width(bytes).
+ * @param destOffset destination address offset.
+ * @param bytesEachRequest eDMA transfer bytes per channel request.
+ * @param transferBytes eDMA transfer bytes to be transferred.
+ * @note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransferConfig(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ int16_t srcOffset,
+ void *destAddr,
+ uint32_t destWidth,
+ int16_t destOffset,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes);
+
+/*!
+ * @brief Prepares the eDMA transfer structure.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * @param config The user configuration structure of type edma_transfer_t.
+ * @param srcAddr eDMA transfer source address.
+ * @param srcWidth eDMA transfer source address width(bytes).
+ * @param destAddr eDMA transfer destination address.
+ * @param destWidth eDMA transfer destination address width(bytes).
+ * @param bytesEachRequest eDMA transfer bytes per channel request.
+ * @param transferBytes eDMA transfer bytes to be transferred.
+ * @param transferType eDMA transfer type.
+ * @note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransfer(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ void *destAddr,
+ uint32_t destWidth,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes,
+ edma_transfer_type_t transferType);
+
+/*!
+ * @brief Submits the eDMA transfer request.
+ *
+ * This function submits the eDMA transfer request according to the transfer configuration structure.
+ * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
+ * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
+ *
+ * @param handle eDMA handle pointer.
+ * @param config Pointer to eDMA transfer configuration structure.
+ * @retval kStatus_EDMA_Success It means submit transfer request succeed.
+ * @retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
+ * @retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
+ */
+status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config);
+
+/*!
+ * @brief eDMA starts transfer.
+ *
+ * This function enables the channel request. Users can call this function after submitting the transfer request
+ * or before submitting the transfer request.
+ *
+ * @param handle eDMA handle pointer.
+ */
+void EDMA_StartTransfer(edma_handle_t *handle);
+
+/*!
+ * @brief eDMA stops transfer.
+ *
+ * This function disables the channel request to pause the transfer. Users can call EDMA_StartTransfer()
+ * again to resume the transfer.
+ *
+ * @param handle eDMA handle pointer.
+ */
+void EDMA_StopTransfer(edma_handle_t *handle);
+
+/*!
+ * @brief eDMA aborts transfer.
+ *
+ * This function disables the channel request and clear transfer status bits.
+ * Users can submit another transfer after calling this API.
+ *
+ * @param handle DMA handle pointer.
+ */
+void EDMA_AbortTransfer(edma_handle_t *handle);
+
+/*!
+ * @brief Get unused TCD slot number.
+ *
+ * This function gets current tcd index which is run. If the TCD pool pointer is NULL, it will return 0.
+ *
+ * @param handle DMA handle pointer.
+ * @return The unused tcd slot number.
+ */
+static inline uint32_t EDMA_GetUnusedTCDNumber(edma_handle_t *handle)
+{
+ int8_t tmpTcdSize = handle->tcdSize;
+ int8_t tmpTcdUsed = handle->tcdUsed;
+ return ((uint32_t)tmpTcdSize - (uint32_t)tmpTcdUsed);
+}
+
+/*!
+ * @brief Get the next tcd address.
+ *
+ * This function gets the next tcd address. If this is last TCD, return 0.
+ *
+ * @param handle DMA handle pointer.
+ * @return The next TCD address.
+ */
+static inline uint32_t EDMA_GetNextTCDAddress(edma_handle_t *handle)
+{
+ return (uint32_t)(handle->base->TCD[handle->channel].DLAST_SGA);
+}
+
+/*!
+ * @brief eDMA IRQ handler for the current major loop transfer completion.
+ *
+ * This function clears the channel major interrupt flag and calls
+ * the callback function if it is not NULL.
+ *
+ * Note:
+ * For the case using TCD queue, when the major iteration count is exhausted, additional operations are performed.
+ * These include the final address adjustments and reloading of the BITER field into the CITER.
+ * Assertion of an optional interrupt request also occurs at this time, as does a possible fetch of a new TCD from
+ * memory using the scatter/gather address pointer included in the descriptor (if scatter/gather is enabled).
+ *
+ * For instance, when the time interrupt of TCD[0] happens, the TCD[1] has already been loaded into the eDMA engine.
+ * As sga and sga_index are calculated based on the DLAST_SGA bitfield lies in the TCD_CSR register, the sga_index
+ * in this case should be 2 (DLAST_SGA of TCD[1] stores the address of TCD[2]). Thus, the "tcdUsed" updated should be
+ * (tcdUsed - 2U) which indicates the number of TCDs can be loaded in the memory pool (because TCD[0] and TCD[1] have
+ * been loaded into the eDMA engine at this point already.).
+ *
+ * For the last two continuous ISRs in a scatter/gather process, they both load the last TCD (The last ISR does not
+ * load a new TCD) from the memory pool to the eDMA engine when major loop completes.
+ * Therefore, ensure that the header and tcdUsed updated are identical for them.
+ * tcdUsed are both 0 in this case as no TCD to be loaded.
+ *
+ * See the "eDMA basic data flow" in the eDMA Functional description section of the Reference Manual for
+ * further details.
+ *
+ * @param handle eDMA handle pointer.
+ */
+void EDMA_HandleIRQ(edma_handle_t *handle);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/* @} */
+
+#endif /*_FSL_EDMA_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.c b/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.c
new file mode 100644
index 0000000000..47b715b0b4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_elcdif.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.elcdif"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for ELCDIF module.
+ *
+ * @param base ELCDIF peripheral base address
+ */
+static uint32_t ELCDIF_GetInstance(const LCDIF_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to eLCDIF apb_clk for each instance. */
+static const clock_ip_name_t s_elcdifApbClocks[] = LCDIF_CLOCKS;
+#if defined(LCDIF_PERIPH_CLOCKS)
+/*! @brief Pointers to eLCDIF pix_clk for each instance. */
+static const clock_ip_name_t s_elcdifPixClocks[] = LCDIF_PERIPH_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief The control register value to select different pixel format. */
+static const elcdif_pixel_format_reg_t s_pixelFormatReg[] = {
+ /* kELCDIF_PixelFormatRAW8 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(1U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+ /* kELCDIF_PixelFormatRGB565 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(0U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+ /* kELCDIF_PixelFormatRGB666 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(3U) | LCDIF_CTRL_DATA_FORMAT_24_BIT(1U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
+ /* kELCDIF_PixelFormatXRGB8888 */
+ {/* Register CTRL. 24-bit. */
+ LCDIF_CTRL_WORD_LENGTH(3U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
+ /* kELCDIF_PixelFormatRGB888 */
+ {/* Register CTRL. 24-bit. */
+ LCDIF_CTRL_WORD_LENGTH(3U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+};
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t ELCDIF_GetInstance(const LCDIF_Type *base)
+{
+ static LCDIF_Type *const s_elcdifBases[] = LCDIF_BASE_PTRS;
+
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_elcdifBases); instance++)
+ {
+ if (s_elcdifBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_elcdifBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the eLCDIF to work in RGB mode (DOTCLK mode).
+ *
+ * This function ungates the eLCDIF clock and configures the eLCDIF peripheral according
+ * to the configuration structure.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_RgbModeInit(LCDIF_Type *base, const elcdif_rgb_mode_config_t *config)
+{
+ assert(NULL != config);
+ assert((uint32_t)config->pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = ELCDIF_GetInstance(base);
+ /* Enable the clock. */
+ (void)CLOCK_EnableClock(s_elcdifApbClocks[instance]);
+#if defined(LCDIF_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_elcdifPixClocks[instance]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset. */
+ ELCDIF_Reset(base);
+
+ base->CTRL = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl | (uint32_t)(config->dataBus) |
+ LCDIF_CTRL_DOTCLK_MODE_MASK | /* RGB mode. */
+ LCDIF_CTRL_BYPASS_COUNT_MASK | /* Keep RUN bit set. */
+ LCDIF_CTRL_MASTER_MASK;
+
+ base->CTRL1 = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl1;
+
+ base->CTRL2 = (base->CTRL2 & ~LCDIF_CTRL2_OUTSTANDING_REQS_MASK) | (LCDIF_CTRL2_OUTSTANDING_REQS(4));
+
+ base->TRANSFER_COUNT = ((uint32_t)config->panelHeight << LCDIF_TRANSFER_COUNT_V_COUNT_SHIFT) |
+ ((uint32_t)config->panelWidth << LCDIF_TRANSFER_COUNT_H_COUNT_SHIFT);
+
+ base->VDCTRL0 = LCDIF_VDCTRL0_ENABLE_PRESENT_MASK | /* Data enable signal. */
+ LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT_MASK | /* VSYNC period in the unit of display clock. */
+ LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT_MASK | /* VSYNC pulse width in the unit of display clock. */
+ (uint32_t)config->polarityFlags | (uint32_t)config->vsw;
+
+ base->VDCTRL1 =
+ (uint32_t)config->vsw + (uint32_t)config->panelHeight + (uint32_t)config->vfp + (uint32_t)config->vbp;
+ base->VDCTRL2 =
+ ((uint32_t)config->hsw << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_SHIFT) |
+ ((uint32_t)config->hfp + (uint32_t)config->hbp + (uint32_t)config->panelWidth + (uint32_t)config->hsw)
+ << LCDIF_VDCTRL2_HSYNC_PERIOD_SHIFT;
+
+ base->VDCTRL3 = (((uint32_t)config->hbp + config->hsw) << LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_SHIFT) |
+ (((uint32_t)config->vbp + config->vsw) << LCDIF_VDCTRL3_VERTICAL_WAIT_CNT_SHIFT);
+
+ base->VDCTRL4 = LCDIF_VDCTRL4_SYNC_SIGNALS_ON_MASK |
+ ((uint32_t)config->panelWidth << LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT_SHIFT);
+
+ base->CUR_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
+ base->NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
+}
+
+/*!
+ * brief Gets the eLCDIF default configuration structure for RGB (DOTCLK) mode.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * code
+ config->panelWidth = 480U;
+ config->panelHeight = 272U;
+ config->hsw = 41;
+ config->hfp = 4;
+ config->hbp = 8;
+ config->vsw = 10;
+ config->vfp = 4;
+ config->vbp = 2;
+ config->polarityFlags = kELCDIF_VsyncActiveLow |
+ kELCDIF_HsyncActiveLow |
+ kELCDIF_DataEnableActiveLow |
+ kELCDIF_DriveDataOnFallingClkEdge;
+ config->bufferAddr = 0U;
+ config->pixelFormat = kELCDIF_PixelFormatRGB888;
+ config->dataBus = kELCDIF_DataBus24Bit;
+ code
+ *
+ * param config Pointer to the eLCDIF configuration structure.
+ */
+void ELCDIF_RgbModeGetDefaultConfig(elcdif_rgb_mode_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->panelWidth = 480U;
+ config->panelHeight = 272U;
+ config->hsw = 41;
+ config->hfp = 4;
+ config->hbp = 8;
+ config->vsw = 10;
+ config->vfp = 4;
+ config->vbp = 2;
+ config->polarityFlags = (uint32_t)kELCDIF_VsyncActiveLow | (uint32_t)kELCDIF_HsyncActiveLow |
+ (uint32_t)kELCDIF_DataEnableActiveLow | (uint32_t)kELCDIF_DriveDataOnFallingClkEdge;
+ config->bufferAddr = 0U;
+ config->pixelFormat = kELCDIF_PixelFormatRGB888;
+ config->dataBus = kELCDIF_DataBus24Bit;
+}
+
+/*!
+ * brief Set the pixel format in RGB (DOTCLK) mode.
+ *
+ * param base eLCDIF peripheral base address.
+ * param pixelFormat The pixel format.
+ */
+void ELCDIF_RgbModeSetPixelFormat(LCDIF_Type *base, elcdif_pixel_format_t pixelFormat)
+{
+ assert((uint32_t)pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
+
+ base->CTRL = (base->CTRL & ~(LCDIF_CTRL_WORD_LENGTH_MASK | LCDIF_CTRL_DATA_FORMAT_24_BIT_MASK |
+ LCDIF_CTRL_DATA_FORMAT_18_BIT_MASK | LCDIF_CTRL_DATA_FORMAT_16_BIT_MASK)) |
+ s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl;
+
+ base->CTRL1 = s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl1;
+}
+
+/*!
+ * brief Deinitializes the eLCDIF peripheral.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Deinit(LCDIF_Type *base)
+{
+ ELCDIF_Reset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = ELCDIF_GetInstance(base);
+/* Disable the clock. */
+#if defined(LCDIF_PERIPH_CLOCKS)
+ (void)CLOCK_DisableClock(s_elcdifPixClocks[instance]);
+#endif
+ (void)CLOCK_DisableClock(s_elcdifApbClocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Stop display in RGB (DOTCLK) mode and wait until finished.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_RgbModeStop(LCDIF_Type *base)
+{
+ base->CTRL_CLR = LCDIF_CTRL_DOTCLK_MODE_MASK;
+
+ /* Wait for data transfer finished. */
+ while (0U != (base->CTRL & LCDIF_CTRL_DOTCLK_MODE_MASK))
+ {
+ }
+}
+
+/*!
+ * brief Reset the eLCDIF peripheral.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Reset(LCDIF_Type *base)
+{
+ /*
+ * ELCDIF reset workflow:
+ *
+ * 1. Ungate clock.
+ * 2. Trigger the software reset.
+ * 3. The software reset finished when clk_gate bit is set.
+ * 4. Ungate the clock.
+ * 5. Release the reset.
+ */
+
+ /* Ungate clock. */
+ base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
+
+ /*
+ * If already in reset state, release the reset.
+ * If not, trigger reset.
+ */
+ if (0U == (base->CTRL & LCDIF_CTRL_SFTRST_MASK))
+ {
+ /* Trigger reset. */
+ base->CTRL_SET = LCDIF_CTRL_SFTRST_MASK;
+
+ /* Reset is not finished until CLK_GATE is set. */
+ while (0U == (base->CTRL & LCDIF_CTRL_CLKGATE_MASK))
+ {
+ }
+
+ /* Ungate the clock. */
+ base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
+ }
+
+ /* Release the reset. */
+ base->CTRL_CLR = LCDIF_CTRL_SFTRST_MASK;
+}
+
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+/*!
+ * brief Set the configuration for alpha surface buffer.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBufferConfig(LCDIF_Type *base, const elcdif_as_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->AS_CTRL = (base->AS_CTRL & ~LCDIF_AS_CTRL_FORMAT_MASK) | LCDIF_AS_CTRL_FORMAT(config->pixelFormat);
+ base->AS_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
+ base->AS_NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
+}
+
+/*!
+ * brief Set the alpha surface blending configuration.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBlendConfig(LCDIF_Type *base, const elcdif_as_blend_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ reg = base->AS_CTRL;
+ reg &= ~(LCDIF_AS_CTRL_ALPHA_INVERT_MASK | LCDIF_AS_CTRL_ROP_MASK | LCDIF_AS_CTRL_ALPHA_MASK |
+ LCDIF_AS_CTRL_ALPHA_CTRL_MASK);
+ reg |= (LCDIF_AS_CTRL_ROP(config->ropMode) | LCDIF_AS_CTRL_ALPHA(config->alpha) |
+ LCDIF_AS_CTRL_ALPHA_CTRL(config->alphaMode));
+
+ if (config->invertAlpha)
+ {
+ reg |= LCDIF_AS_CTRL_ALPHA_INVERT_MASK;
+ }
+
+ base->AS_CTRL = reg;
+}
+#endif /* FSL_FEATURE_LCDIF_HAS_NO_AS */
+
+#if (defined(FSL_FEATURE_LCDIF_HAS_LUT) && (0 != FSL_FEATURE_LCDIF_HAS_LUT))
+/*!
+ * brief Load the LUT value.
+ *
+ * This function loads the LUT value to the specific LUT memory, user can
+ * specify the start entry index.
+ *
+ * param base eLCDIF peripheral base address.
+ * param lut Which LUT to load.
+ * param startIndex The start index of the LUT entry to update.
+ * param lutData The LUT data to load.
+ * param count Count of p lutData.
+ * retval kStatus_Success Initialization success.
+ * retval kStatus_InvalidArgument Wrong argument.
+ */
+status_t ELCDIF_UpdateLut(
+ LCDIF_Type *base, elcdif_lut_t lut, uint16_t startIndex, const uint32_t *lutData, uint16_t count)
+{
+ volatile uint32_t *regLutAddr;
+ volatile uint32_t *regLutData;
+ uint32_t i;
+ status_t status;
+
+ /* Only has 256 entries. */
+ if ((startIndex + count) > ELCDIF_LUT_ENTRY_NUM)
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ if (kELCDIF_Lut0 == lut)
+ {
+ regLutAddr = &(base->LUT0_ADDR);
+ regLutData = &(base->LUT0_DATA);
+ }
+ else
+ {
+ regLutAddr = &(base->LUT1_ADDR);
+ regLutData = &(base->LUT1_DATA);
+ }
+
+ *regLutAddr = startIndex;
+
+ for (i = 0; i < count; i++)
+ {
+ *regLutData = lutData[i];
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_LCDIF_HAS_LUT */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.h b/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.h
new file mode 100644
index 0000000000..8b56d676b8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/elcdif/fsl_elcdif.h
@@ -0,0 +1,767 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ELCDIF_H_
+#define _FSL_ELCDIF_H_
+
+#include "fsl_common.h"
+
+#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && (0 != FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET))
+#include "fsl_memory.h"
+#endif
+
+/*!
+ * @addtogroup elcdif
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief eLCDIF driver version */
+#define FSL_ELCDIF_DRIVER_VERSION (MAKE_VERSION(2, 0, 5))
+/*@}*/
+
+/* All IRQ flags in CTRL1 register. */
+#define ELCDIF_CTRL1_IRQ_MASK \
+ (LCDIF_CTRL1_BM_ERROR_IRQ_MASK | LCDIF_CTRL1_OVERFLOW_IRQ_MASK | LCDIF_CTRL1_UNDERFLOW_IRQ_MASK | \
+ LCDIF_CTRL1_CUR_FRAME_DONE_IRQ_MASK | LCDIF_CTRL1_VSYNC_EDGE_IRQ_MASK)
+
+/* All IRQ enable control bits in CTRL1 register. */
+#define ELCDIF_CTRL1_IRQ_EN_MASK \
+ (LCDIF_CTRL1_BM_ERROR_IRQ_EN_MASK | LCDIF_CTRL1_OVERFLOW_IRQ_EN_MASK | LCDIF_CTRL1_UNDERFLOW_IRQ_EN_MASK | \
+ LCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN_MASK | LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN_MASK)
+
+/* All IRQ flags in AS_CTRL register. */
+#if defined(LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_MASK)
+#define ELCDIF_AS_CTRL_IRQ_MASK (LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_MASK)
+#else
+#define ELCDIF_AS_CTRL_IRQ_MASK 0U
+#endif
+
+/* All IRQ enable control bits in AS_CTRL register. */
+#if defined(LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_EN_MASK)
+#define ELCDIF_AS_CTRL_IRQ_EN_MASK (LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_EN_MASK)
+#else
+#define ELCDIF_AS_CTRL_IRQ_EN_MASK 0U
+#endif
+
+#if ((0 != (ELCDIF_CTRL1_IRQ_MASK & ELCDIF_AS_CTRL_IRQ_MASK)) || \
+ (0 != (ELCDIF_AS_CTRL_IRQ_MASK & ELCDIF_AS_CTRL_IRQ_EN_MASK)))
+#error Interrupt bits overlap, need to update the interrupt functions.
+#endif
+
+#if defined(LCDIF_CTRL_ENABLE_PXP_HANDSHAKE_MASK)
+#define FSL_FEATURE_LCDIF_HAS_PXP_HANDSHAKE 1
+#else
+#define FSL_FEATURE_LCDIF_HAS_PXP_HANDSHAKE 0
+#endif
+
+#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && (0 != FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET))
+#define ELCDIF_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
+#else
+#define ELCDIF_ADDR_CPU_2_IP(addr) (addr)
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+/* LUT memory entery number. */
+#define ELCDIF_LUT_ENTRY_NUM 256U
+
+/*!
+ * @brief eLCDIF signal polarity flags
+ */
+enum _elcdif_polarity_flags
+{
+ kELCDIF_VsyncActiveLow = 0U, /*!< VSYNC active low. */
+ kELCDIF_HsyncActiveLow = 0U, /*!< HSYNC active low. */
+ kELCDIF_DataEnableActiveLow = 0U, /*!< Data enable line active low. */
+ kELCDIF_DriveDataOnFallingClkEdge = 0U, /*!< Drive data on falling clock edge, capture data
+ on rising clock edge. */
+
+ kELCDIF_VsyncActiveHigh = LCDIF_VDCTRL0_VSYNC_POL_MASK, /*!< VSYNC active high. */
+ kELCDIF_HsyncActiveHigh = LCDIF_VDCTRL0_HSYNC_POL_MASK, /*!< HSYNC active high. */
+ kELCDIF_DataEnableActiveHigh = LCDIF_VDCTRL0_ENABLE_POL_MASK, /*!< Data enable line active high. */
+ kELCDIF_DriveDataOnRisingClkEdge = LCDIF_VDCTRL0_DOTCLK_POL_MASK, /*!< Drive data on falling
+ clock edge, capture data
+ on rising clock edge. */
+};
+
+/*!
+ * @brief The eLCDIF interrupts to enable.
+ */
+enum _elcdif_interrupt_enable
+{
+ kELCDIF_BusMasterErrorInterruptEnable = LCDIF_CTRL1_BM_ERROR_IRQ_EN_MASK, /*!< Bus master error interrupt. */
+ kELCDIF_TxFifoOverflowInterruptEnable = LCDIF_CTRL1_OVERFLOW_IRQ_EN_MASK, /*!< TXFIFO overflow interrupt. */
+ kELCDIF_TxFifoUnderflowInterruptEnable = LCDIF_CTRL1_UNDERFLOW_IRQ_EN_MASK, /*!< TXFIFO underflow interrupt. */
+ kELCDIF_CurFrameDoneInterruptEnable =
+ LCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN_MASK, /*!< Interrupt when hardware enters vertical blanking state. */
+ kELCDIF_VsyncEdgeInterruptEnable =
+ LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN_MASK, /*!< Interrupt when hardware encounters VSYNC edge. */
+#if defined(LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_EN_MASK)
+ kELCDIF_SciSyncOnInterruptEnable =
+ LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_EN_MASK, /*!< Interrupt when eLCDIF lock with CSI input. */
+#endif
+};
+
+/*!
+ * @brief The eLCDIF interrupt status flags.
+ */
+enum _elcdif_interrupt_flags
+{
+ kELCDIF_BusMasterError = LCDIF_CTRL1_BM_ERROR_IRQ_MASK, /*!< Bus master error interrupt. */
+ kELCDIF_TxFifoOverflow = LCDIF_CTRL1_OVERFLOW_IRQ_MASK, /*!< TXFIFO overflow interrupt. */
+ kELCDIF_TxFifoUnderflow = LCDIF_CTRL1_UNDERFLOW_IRQ_MASK, /*!< TXFIFO underflow interrupt. */
+ kELCDIF_CurFrameDone =
+ LCDIF_CTRL1_CUR_FRAME_DONE_IRQ_MASK, /*!< Interrupt when hardware enters vertical blanking state. */
+ kELCDIF_VsyncEdge = LCDIF_CTRL1_VSYNC_EDGE_IRQ_MASK, /*!< Interrupt when hardware encounters VSYNC edge. */
+#if defined(LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_MASK)
+ kELCDIF_SciSyncOn = LCDIF_AS_CTRL_CSI_SYNC_ON_IRQ_MASK, /*!< Interrupt when eLCDIF lock with CSI input. */
+#endif
+};
+
+/*!
+ * @brief eLCDIF status flags
+ */
+enum _elcdif_status_flags
+{
+ kELCDIF_LFifoFull = LCDIF_STAT_LFIFO_FULL_MASK, /*!< LFIFO full. */
+ kELCDIF_LFifoEmpty = LCDIF_STAT_LFIFO_EMPTY_MASK, /*!< LFIFO empty. */
+ kELCDIF_TxFifoFull = LCDIF_STAT_TXFIFO_FULL_MASK, /*!< TXFIFO full. */
+ kELCDIF_TxFifoEmpty = LCDIF_STAT_TXFIFO_EMPTY_MASK, /*!< TXFIFO empty. */
+#if defined(LCDIF_STAT_BUSY_MASK)
+ kELCDIF_LcdControllerBusy = LCDIF_STAT_BUSY_MASK, /*!< The external LCD controller busy signal. */
+#endif
+#if defined(LCDIF_STAT_DVI_CURRENT_FIELD_MASK)
+ kELCDIF_CurDviField2 = LCDIF_STAT_DVI_CURRENT_FIELD_MASK, /*!< Current DVI filed, if set, then current filed is 2,
+ otherwise current filed is 1. */
+#endif
+};
+
+/*!
+ * @brief The pixel format.
+ *
+ * This enumerator should be defined together with the array s_pixelFormatReg.
+ * To support new pixel format, enhance this enumerator and s_pixelFormatReg.
+ */
+typedef enum _elcdif_pixel_format
+{
+ kELCDIF_PixelFormatRAW8 = 0, /*!< RAW 8 bit, four data use 32 bits. */
+ kELCDIF_PixelFormatRGB565 = 1, /*!< RGB565, two pixel use 32 bits. */
+ kELCDIF_PixelFormatRGB666 = 2, /*!< RGB666 unpacked, one pixel uses 32 bits, high byte unused,
+ upper 2 bits of other bytes unused. */
+ kELCDIF_PixelFormatXRGB8888 = 3, /*!< XRGB8888 unpacked, one pixel uses 32 bits, high byte unused. */
+ kELCDIF_PixelFormatRGB888 = 4, /*!< RGB888 packed, one pixel uses 24 bits. */
+} elcdif_pixel_format_t;
+
+/*! @brief The LCD data bus type. */
+typedef enum _elcdif_lcd_data_bus
+{
+ kELCDIF_DataBus8Bit = LCDIF_CTRL_LCD_DATABUS_WIDTH(1), /*!< 8-bit data bus. */
+ kELCDIF_DataBus16Bit = LCDIF_CTRL_LCD_DATABUS_WIDTH(0), /*!< 16-bit data bus, support RGB565. */
+ kELCDIF_DataBus18Bit = LCDIF_CTRL_LCD_DATABUS_WIDTH(2), /*!< 18-bit data bus, support RGB666. */
+ kELCDIF_DataBus24Bit = LCDIF_CTRL_LCD_DATABUS_WIDTH(3), /*!< 24-bit data bus, support RGB888. */
+} elcdif_lcd_data_bus_t;
+
+/*!
+ * @brief The register value when using different pixel format.
+ *
+ * These register bits control the pixel format:
+ * - CTRL[DATA_FORMAT_24_BIT]
+ * - CTRL[DATA_FORMAT_18_BIT]
+ * - CTRL[DATA_FORMAT_16_BIT]
+ * - CTRL[WORD_LENGTH]
+ * - CTRL1[BYTE_PACKING_FORMAT]
+ */
+typedef struct _elcdif_pixel_format_reg
+{
+ uint32_t regCtrl; /*!< Value of register CTRL. */
+ uint32_t regCtrl1; /*!< Value of register CTRL1. */
+} elcdif_pixel_format_reg_t;
+
+/*!
+ * @brief eLCDIF configure structure for RGB mode (DOTCLK mode).
+ */
+typedef struct _elcdif_rgb_mode_config
+{
+ uint16_t panelWidth; /*!< Display panel width, pixels per line. */
+ uint16_t panelHeight; /*!< Display panel height, how many lines per panel. */
+ uint8_t hsw; /*!< HSYNC pulse width. */
+ uint8_t hfp; /*!< Horizontal front porch. */
+ uint8_t hbp; /*!< Horizontal back porch. */
+ uint8_t vsw; /*!< VSYNC pulse width. */
+ uint8_t vfp; /*!< Vrtical front porch. */
+ uint8_t vbp; /*!< Vertical back porch. */
+ uint32_t polarityFlags; /*!< OR'ed value of @ref _elcdif_polarity_flags, used to contol the signal polarity. */
+ uint32_t bufferAddr; /*!< Frame buffer address. */
+ elcdif_pixel_format_t pixelFormat; /*!< Pixel format. */
+ elcdif_lcd_data_bus_t dataBus; /*!< LCD data bus. */
+} elcdif_rgb_mode_config_t;
+
+/*!
+ * @brief eLCDIF alpha surface pixel format.
+ */
+typedef enum _elcdif_as_pixel_format
+{
+ kELCDIF_AsPixelFormatARGB8888 = 0x0, /*!< 32-bit pixels with alpha. */
+ kELCDIF_AsPixelFormatRGB888 = 0x4, /*!< 32-bit pixels without alpha (unpacked 24-bit format) */
+ kELCDIF_AsPixelFormatARGB1555 = 0x8, /*!< 16-bit pixels with alpha. */
+ kELCDIF_AsPixelFormatARGB4444 = 0x9, /*!< 16-bit pixels with alpha. */
+ kELCDIF_AsPixelFormatRGB555 = 0xC, /*!< 16-bit pixels without alpha. */
+ kELCDIF_AsPixelFormatRGB444 = 0xD, /*!< 16-bit pixels without alpha. */
+ kELCDIF_AsPixelFormatRGB565 = 0xE, /*!< 16-bit pixels without alpha. */
+} elcdif_as_pixel_format_t;
+
+/*!
+ * @brief eLCDIF alpha surface buffer configuration.
+ */
+typedef struct _elcdif_as_buffer_config
+{
+ uint32_t bufferAddr; /*!< Buffer address. */
+ elcdif_as_pixel_format_t pixelFormat; /*!< Pixel format. */
+} elcdif_as_buffer_config_t;
+
+/*!
+ * @brief eLCDIF alpha mode during blending.
+ */
+typedef enum _elcdif_alpha_mode
+{
+ kELCDIF_AlphaEmbedded, /*!< The alpha surface pixel alpha value will be used for blend. */
+ kELCDIF_AlphaOverride, /*!< The user defined alpha value will be used for blend directly. */
+ kELCDIF_AlphaMultiply, /*!< The alpha surface pixel alpha value scaled the user defined
+ alpha value will be used for blend, for example, pixel alpha set
+ set to 200, user defined alpha set to 100, then the reault alpha
+ is 200 * 100 / 255. */
+ kELCDIF_AlphaRop /*!< Raster operation. */
+} elcdif_alpha_mode_t;
+
+/*!
+ * @brief eLCDIF ROP mode during blending.
+ *
+ * Explanation:
+ * - AS: Alpha surface
+ * - PS: Process surface
+ * - nAS: Alpha surface NOT value
+ * - nPS: Process surface NOT value
+ */
+typedef enum _elcdif_rop_mode
+{
+ kELCDIF_RopMaskAs = 0x0, /*!< AS AND PS. */
+ kELCDIF_RopMaskNotAs = 0x1, /*!< nAS AND PS. */
+ kELCDIF_RopMaskAsNot = 0x2, /*!< AS AND nPS. */
+ kELCDIF_RopMergeAs = 0x3, /*!< AS OR PS. */
+ kELCDIF_RopMergeNotAs = 0x4, /*!< nAS OR PS. */
+ kELCDIF_RopMergeAsNot = 0x5, /*!< AS OR nPS. */
+ kELCDIF_RopNotCopyAs = 0x6, /*!< nAS. */
+ kELCDIF_RopNot = 0x7, /*!< nPS. */
+ kELCDIF_RopNotMaskAs = 0x8, /*!< AS NAND PS. */
+ kELCDIF_RopNotMergeAs = 0x9, /*!< AS NOR PS. */
+ kELCDIF_RopXorAs = 0xA, /*!< AS XOR PS. */
+ kELCDIF_RopNotXorAs = 0xB /*!< AS XNOR PS. */
+} elcdif_rop_mode_t;
+
+/*!
+ * @brief eLCDIF alpha surface blending configuration.
+ */
+typedef struct _elcdif_as_blend_config
+{
+ uint8_t alpha; /*!< User defined alpha value, only used when @ref alphaMode is @ref kELCDIF_AlphaOverride or @ref
+ kELCDIF_AlphaRop. */
+ bool invertAlpha; /*!< Set true to invert the alpha. */
+ elcdif_alpha_mode_t alphaMode; /*!< Alpha mode. */
+ elcdif_rop_mode_t ropMode; /*!< ROP mode, only valid when @ref alphaMode is @ref kELCDIF_AlphaRop. */
+} elcdif_as_blend_config_t;
+
+/*!
+ * @brief eLCDIF LUT
+ *
+ * The Lookup Table (LUT) is used to expand the 8 bits pixel to 24 bits pixel
+ * before output to external displayer.
+ *
+ * There are two 256x24 bits LUT memory in LCDIF, the LSB of frame buffer address
+ * determins which memory to use.
+ */
+typedef enum _elcdif_lut
+{
+ kELCDIF_Lut0 = 0, /*!< LUT 0. */
+ kELCDIF_Lut1, /*!< LUT 1. */
+} elcdif_lut_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name eLCDIF initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the eLCDIF to work in RGB mode (DOTCLK mode).
+ *
+ * This function ungates the eLCDIF clock and configures the eLCDIF peripheral according
+ * to the configuration structure.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void ELCDIF_RgbModeInit(LCDIF_Type *base, const elcdif_rgb_mode_config_t *config);
+
+/*!
+ * @brief Gets the eLCDIF default configuration structure for RGB (DOTCLK) mode.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * @code
+ config->panelWidth = 480U;
+ config->panelHeight = 272U;
+ config->hsw = 41;
+ config->hfp = 4;
+ config->hbp = 8;
+ config->vsw = 10;
+ config->vfp = 4;
+ config->vbp = 2;
+ config->polarityFlags = kELCDIF_VsyncActiveLow |
+ kELCDIF_HsyncActiveLow |
+ kELCDIF_DataEnableActiveLow |
+ kELCDIF_DriveDataOnFallingClkEdge;
+ config->bufferAddr = 0U;
+ config->pixelFormat = kELCDIF_PixelFormatRGB888;
+ config->dataBus = kELCDIF_DataBus24Bit;
+ @endcode
+ *
+ * @param config Pointer to the eLCDIF configuration structure.
+ */
+void ELCDIF_RgbModeGetDefaultConfig(elcdif_rgb_mode_config_t *config);
+
+/*!
+ * @brief Deinitializes the eLCDIF peripheral.
+ *
+ * @param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Deinit(LCDIF_Type *base);
+
+/* @} */
+
+/*!
+ * @name Module operation
+ * @{
+ */
+
+/*!
+ * @brief Set the pixel format in RGB (DOTCLK) mode.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param pixelFormat The pixel format.
+ */
+void ELCDIF_RgbModeSetPixelFormat(LCDIF_Type *base, elcdif_pixel_format_t pixelFormat);
+
+/*!
+ * @brief Start to display in RGB (DOTCLK) mode.
+ *
+ * @param base eLCDIF peripheral base address.
+ */
+static inline void ELCDIF_RgbModeStart(LCDIF_Type *base)
+{
+ base->CTRL_SET = LCDIF_CTRL_RUN_MASK | LCDIF_CTRL_DOTCLK_MODE_MASK;
+}
+
+/*!
+ * @brief Stop display in RGB (DOTCLK) mode and wait until finished.
+ *
+ * @param base eLCDIF peripheral base address.
+ */
+void ELCDIF_RgbModeStop(LCDIF_Type *base);
+
+/*!
+ * @brief Set the next frame buffer address to display.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param bufferAddr The frame buffer address to set.
+ */
+static inline void ELCDIF_SetNextBufferAddr(LCDIF_Type *base, uint32_t bufferAddr)
+{
+ base->NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(bufferAddr);
+}
+
+/*!
+ * @brief Reset the eLCDIF peripheral.
+ *
+ * @param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Reset(LCDIF_Type *base);
+
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_RESET_PIN) && (0 != FSL_FEATURE_LCDIF_HAS_NO_RESET_PIN))
+/*!
+ * @brief Pull up or down the reset pin for the externel LCD controller.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param pullUp True to pull up reset pin, false to pull down.
+ */
+static inline void ELCDIF_PullUpResetPin(LCDIF_Type *base, bool pullUp)
+{
+ if (pullUp)
+ {
+ base->CTRL1_SET = LCDIF_CTRL1_RESET_MASK;
+ }
+ else
+ {
+ base->CTRL1_CLR = LCDIF_CTRL1_RESET_MASK;
+ }
+}
+#endif
+
+#if (defined(FSL_FEATURE_LCDIF_HAS_PXP_HANDSHAKE) && (0 != FSL_FEATURE_LCDIF_HAS_PXP_HANDSHAKE))
+/*!
+ * @brief Enable or disable the hand shake with PXP.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void ELCDIF_EnablePxpHandShake(LCDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_SET = LCDIF_CTRL_ENABLE_PXP_HANDSHAKE_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = LCDIF_CTRL_ENABLE_PXP_HANDSHAKE_MASK;
+ }
+}
+#endif
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Get the CRC value of the frame sent out.
+ *
+ * When a frame is sent complete (the interrupt @ref kELCDIF_CurFrameDone assert), this function
+ * can be used to get the CRC value of the frame sent.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @return The CRC value.
+ *
+ * @note The CRC value is dependent on the LCD_DATABUS_WIDTH.
+ */
+static inline uint32_t ELCDIF_GetCrcValue(const LCDIF_Type *base)
+{
+ return base->CRC_STAT;
+}
+
+/*!
+ * @brief Get the bus master error virtual address.
+ *
+ * When bus master error occurs (the interrupt kELCDIF_BusMasterError assert), this function
+ * can get the virtual address at which the AXI master received an error
+ * response from the slave.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @return The error virtual address.
+ */
+static inline uint32_t ELCDIF_GetBusMasterErrorAddr(const LCDIF_Type *base)
+{
+ return base->BM_ERROR_STAT;
+}
+
+/*!
+ * @brief Get the eLCDIF status.
+ *
+ * The status flags are returned as a mask value, application could check the
+ * corresponding bit. Example:
+ *
+ * @code
+ uint32_t statusFlags;
+ statusFlags = ELCDIF_GetStatus(LCDIF);
+
+ if (kELCDIF_LFifoFull & statusFlags)
+ {
+ }
+
+ if (kELCDIF_TxFifoEmpty & statusFlags)
+ {
+ }
+ @endcode
+ *
+ * @param base eLCDIF peripheral base address.
+ * @return The mask value of status flags, it is OR'ed value of @ref _elcdif_status_flags.
+ */
+static inline uint32_t ELCDIF_GetStatus(const LCDIF_Type *base)
+{
+ return base->STAT & (LCDIF_STAT_LFIFO_FULL_MASK | LCDIF_STAT_LFIFO_EMPTY_MASK | LCDIF_STAT_TXFIFO_FULL_MASK |
+ LCDIF_STAT_TXFIFO_EMPTY_MASK
+#if defined(LCDIF_STAT_BUSY_MASK)
+ | LCDIF_STAT_BUSY_MASK
+#endif
+#if defined(LCDIF_STAT_DVI_CURRENT_FIELD_MASK)
+ | LCDIF_STAT_DVI_CURRENT_FIELD_MASK
+#endif
+ );
+}
+
+/*!
+ * @brief Get current count in Latency buffer (LFIFO).
+ *
+ * @param base eLCDIF peripheral base address.
+ * @return The LFIFO current count
+ */
+static inline uint32_t ELCDIF_GetLFifoCount(const LCDIF_Type *base)
+{
+ return (base->STAT & LCDIF_STAT_LFIFO_COUNT_MASK) >> LCDIF_STAT_LFIFO_COUNT_SHIFT;
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables eLCDIF interrupt requests.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param mask interrupt source, OR'ed value of _elcdif_interrupt_enable.
+ */
+static inline void ELCDIF_EnableInterrupts(LCDIF_Type *base, uint32_t mask)
+{
+ base->CTRL1_SET = (mask & ELCDIF_CTRL1_IRQ_EN_MASK);
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+ base->AS_CTRL |= (mask & ELCDIF_AS_CTRL_IRQ_EN_MASK);
+#endif
+}
+
+/*!
+ * @brief Disables eLCDIF interrupt requests.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param mask interrupt source, OR'ed value of _elcdif_interrupt_enable.
+ */
+static inline void ELCDIF_DisableInterrupts(LCDIF_Type *base, uint32_t mask)
+{
+ base->CTRL1_CLR = (mask & ELCDIF_CTRL1_IRQ_EN_MASK);
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+ base->AS_CTRL &= ~(mask & ELCDIF_AS_CTRL_IRQ_EN_MASK);
+#endif
+}
+
+/*!
+ * @brief Get eLCDIF interrupt peding status.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @return Interrupt pending status, OR'ed value of _elcdif_interrupt_flags.
+ */
+static inline uint32_t ELCDIF_GetInterruptStatus(const LCDIF_Type *base)
+{
+ uint32_t flags;
+
+ flags = (base->CTRL1 & ELCDIF_CTRL1_IRQ_MASK);
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+ flags |= (base->AS_CTRL & ELCDIF_AS_CTRL_IRQ_MASK);
+#endif
+
+ return flags;
+}
+
+/*!
+ * @brief Clear eLCDIF interrupt peding status.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param mask of the flags to clear, OR'ed value of _elcdif_interrupt_flags.
+ */
+static inline void ELCDIF_ClearInterruptStatus(LCDIF_Type *base, uint32_t mask)
+{
+ base->CTRL1_CLR = (mask & ELCDIF_CTRL1_IRQ_MASK);
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+ base->AS_CTRL &= ~(mask & ELCDIF_AS_CTRL_IRQ_MASK);
+#endif
+}
+
+/* @} */
+
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && (0 != FSL_FEATURE_LCDIF_HAS_NO_AS))
+/*!
+ * @name Alpha surface
+ * @{
+ */
+
+/*!
+ * @brief Set the configuration for alpha surface buffer.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBufferConfig(LCDIF_Type *base, const elcdif_as_buffer_config_t *config);
+
+/*!
+ * @brief Set the alpha surface blending configuration.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBlendConfig(LCDIF_Type *base, const elcdif_as_blend_config_t *config);
+
+/*!
+ * @brief Set the next alpha surface buffer address.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param bufferAddr Alpha surface buffer address.
+ */
+static inline void ELCDIF_SetNextAlphaSurfaceBufferAddr(LCDIF_Type *base, uint32_t bufferAddr)
+{
+ base->AS_NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(bufferAddr);
+}
+
+/*!
+ * @brief Set the overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the @p colorKeyLow to @p colorKeyHigh range, it will use the process surface
+ * pixel value for that location.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param colorKeyLow Color key low range.
+ * @param colorKeyHigh Color key high range.
+ *
+ * @note Colorkey operations are higher priority than alpha or ROP operations
+ */
+static inline void ELCDIF_SetOverlayColorKey(LCDIF_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ base->AS_CLRKEYLOW = colorKeyLow;
+ base->AS_CLRKEYHIGH = colorKeyHigh;
+}
+
+/*!
+ * @brief Enable or disable the color key.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void ELCDIF_EnableOverlayColorKey(LCDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->AS_CTRL |= LCDIF_AS_CTRL_ENABLE_COLORKEY_MASK;
+ }
+ else
+ {
+ base->AS_CTRL &= ~LCDIF_AS_CTRL_ENABLE_COLORKEY_MASK;
+ }
+}
+
+/*!
+ * @brief Enable or disable the alpha surface.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void ELCDIF_EnableAlphaSurface(LCDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->AS_CTRL |= LCDIF_AS_CTRL_AS_ENABLE_MASK;
+ }
+ else
+ {
+ base->AS_CTRL &= ~LCDIF_AS_CTRL_AS_ENABLE_MASK;
+ }
+}
+
+/*!
+ * @brief Enable or disable the process surface.
+ *
+ * Process surface is the normal frame buffer. The process surface content
+ * is controlled by ::ELCDIF_SetNextBufferAddr.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void ELCDIF_EnableProcessSurface(LCDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->AS_CTRL &= ~LCDIF_AS_CTRL_PS_DISABLE_MASK;
+ }
+ else
+ {
+ base->AS_CTRL |= LCDIF_AS_CTRL_PS_DISABLE_MASK;
+ }
+}
+
+/* @} */
+#endif /* FSL_FEATURE_LCDIF_HAS_NO_AS */
+
+#if (defined(FSL_FEATURE_LCDIF_HAS_LUT) && (0 != FSL_FEATURE_LCDIF_HAS_LUT))
+/*!
+ * @name LUT
+ *
+ * The Lookup Table (LUT) is used to expand the 8 bits pixel to 24 bits pixel
+ * before output to external displayer.
+ *
+ * There are two 256x24 bits LUT memory in LCDIF, the LSB of frame buffer address
+ * determins which memory to use.
+ *
+ * @{
+ */
+
+/*!
+ * @brief Enable or disable the LUT.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void ELCDIF_EnableLut(LCDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LUT_CTRL &= ~LCDIF_LUT_CTRL_LUT_BYPASS_MASK;
+ }
+ else
+ {
+ base->LUT_CTRL |= LCDIF_LUT_CTRL_LUT_BYPASS_MASK;
+ }
+}
+
+/*!
+ * @brief Load the LUT value.
+ *
+ * This function loads the LUT value to the specific LUT memory, user can
+ * specify the start entry index.
+ *
+ * @param base eLCDIF peripheral base address.
+ * @param lut Which LUT to load.
+ * @param startIndex The start index of the LUT entry to update.
+ * @param lutData The LUT data to load.
+ * @param count Count of @p lutData.
+ * @retval kStatus_Success Initialization success.
+ * @retval kStatus_InvalidArgument Wrong argument.
+ */
+status_t ELCDIF_UpdateLut(
+ LCDIF_Type *base, elcdif_lut_t lut, uint16_t startIndex, const uint32_t *lutData, uint16_t count);
+
+/* @} */
+#endif /* FSL_FEATURE_LCDIF_HAS_LUT */
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/* @} */
+
+#endif /*_FSL_ELCDIF_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.c b/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.c
new file mode 100644
index 0000000000..aab9a505d8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.enc"
+#endif
+
+#define ENC_CTRL_W1C_FLAGS (ENC_CTRL_HIRQ_MASK | ENC_CTRL_XIRQ_MASK | ENC_CTRL_DIRQ_MASK | ENC_CTRL_CMPIRQ_MASK)
+#if (defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+#define ENC_CTRL2_W1C_FLAGS (ENC_CTRL2_ROIRQ_MASK | ENC_CTRL2_RUIRQ_MASK)
+#else
+#define ENC_CTRL2_W1C_FLAGS (ENC_CTRL2_SABIRQ_MASK | ENC_CTRL2_ROIRQ_MASK | ENC_CTRL2_RUIRQ_MASK)
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for ENC module.
+ *
+ * @param base ENC peripheral base address
+ */
+static uint32_t ENC_GetInstance(ENC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ENC bases for each instance. */
+static ENC_Type *const s_encBases[] = ENC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ENC clocks for each instance. */
+static const clock_ip_name_t s_encClocks[] = ENC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ENC_GetInstance(ENC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_encBases); instance++)
+ {
+ if (s_encBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_encBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialization for the ENC module.
+ *
+ * This function is to make the initialization for the ENC module. It should be called firstly before any operation to
+ * the ENC with the operations like:
+ * - Enable the clock for ENC module.
+ * - Configure the ENC's working attributes.
+ *
+ * param base ENC peripheral base address.
+ * param config Pointer to configuration structure. See to "enc_config_t".
+ */
+void ENC_Init(ENC_Type *base, const enc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t tmp16;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_encClocks[ENC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* ENC_CTRL. */
+ tmp16 = base->CTRL & (uint16_t)(~(ENC_CTRL_W1C_FLAGS | ENC_CTRL_HIP_MASK | ENC_CTRL_HNE_MASK | ENC_CTRL_REV_MASK |
+ ENC_CTRL_PH1_MASK | ENC_CTRL_XIP_MASK | ENC_CTRL_XNE_MASK | ENC_CTRL_WDE_MASK));
+ /* For HOME trigger. */
+ if (kENC_HOMETriggerDisabled != config->HOMETriggerMode)
+ {
+ tmp16 |= ENC_CTRL_HIP_MASK;
+ if (kENC_HOMETriggerOnFallingEdge == config->HOMETriggerMode)
+ {
+ tmp16 |= ENC_CTRL_HNE_MASK;
+ }
+ }
+ /* For encoder work mode. */
+ if (config->enableReverseDirection)
+ {
+ tmp16 |= ENC_CTRL_REV_MASK;
+ }
+ if (kENC_DecoderWorkAsSignalPhaseCountMode == config->decoderWorkMode)
+ {
+ tmp16 |= ENC_CTRL_PH1_MASK;
+ }
+ /* For INDEX trigger. */
+ if (kENC_INDEXTriggerDisabled != config->INDEXTriggerMode)
+ {
+ tmp16 |= ENC_CTRL_XIP_MASK;
+ if (kENC_INDEXTriggerOnFallingEdge == config->INDEXTriggerMode)
+ {
+ tmp16 |= ENC_CTRL_XNE_MASK;
+ }
+ }
+ /* Watchdog. */
+ if (config->enableWatchdog)
+ {
+ tmp16 |= ENC_CTRL_WDE_MASK;
+ base->WTR = config->watchdogTimeoutValue; /* WDOG can be only available when the feature is enabled. */
+ }
+ base->CTRL = tmp16;
+
+ /* ENC_FILT. */
+ base->FILT = ENC_FILT_FILT_CNT(config->filterCount) | ENC_FILT_FILT_PER(config->filterSamplePeriod);
+
+ /* ENC_CTRL2. */
+ tmp16 = base->CTRL2 & (uint16_t)(~(ENC_CTRL2_W1C_FLAGS | ENC_CTRL2_OUTCTL_MASK | ENC_CTRL2_REVMOD_MASK |
+ ENC_CTRL2_MOD_MASK | ENC_CTRL2_UPDPOS_MASK | ENC_CTRL2_UPDHLD_MASK));
+ if (kENC_POSMATCHOnReadingAnyPositionCounter == config->positionMatchMode)
+ {
+ tmp16 |= ENC_CTRL2_OUTCTL_MASK;
+ }
+ if (kENC_RevolutionCountOnRollOverModulus == config->revolutionCountCondition)
+ {
+ tmp16 |= ENC_CTRL2_REVMOD_MASK;
+ }
+ if (config->enableModuloCountMode)
+ {
+ tmp16 |= ENC_CTRL2_MOD_MASK;
+ /* Set modulus value. */
+ base->UMOD = (uint16_t)(config->positionModulusValue >> 16U); /* Upper 16 bits. */
+ base->LMOD = (uint16_t)(config->positionModulusValue); /* Lower 16 bits. */
+ }
+ if (config->enableTRIGGERClearPositionCounter)
+ {
+ tmp16 |= ENC_CTRL2_UPDPOS_MASK;
+ }
+ if (config->enableTRIGGERClearHoldPositionCounter)
+ {
+ tmp16 |= ENC_CTRL2_UPDHLD_MASK;
+ }
+ base->CTRL2 = tmp16;
+
+#if (defined(FSL_FEATURE_ENC_HAS_CTRL3) && FSL_FEATURE_ENC_HAS_CTRL3)
+ /* ENC_CTRL3. */
+ tmp16 = base->CTRL3 & (uint16_t)(~(ENC_CTRL3_PMEN_MASK | ENC_CTRL3_PRSC_MASK));
+ if (config->enablePeriodMeasurementFunction)
+ {
+ tmp16 |= ENC_CTRL3_PMEN_MASK;
+ /* Set prescaler value. */
+ tmp16 |= ((uint16_t)config->prescalerValue << ENC_CTRL3_PRSC_SHIFT);
+ }
+ base->CTRL3 = tmp16;
+#endif
+
+ /* ENC_UCOMP & ENC_LCOMP. */
+ base->UCOMP = (uint16_t)(config->positionCompareValue >> 16U); /* Upper 16 bits. */
+ base->LCOMP = (uint16_t)(config->positionCompareValue); /* Lower 16 bits. */
+
+ /* ENC_UINIT & ENC_LINIT. */
+ base->UINIT = (uint16_t)(config->positionInitialValue >> 16U); /* Upper 16 bits. */
+ base->LINIT = (uint16_t)(config->positionInitialValue); /* Lower 16 bits. */
+}
+
+/*!
+ * brief De-initialization for the ENC module.
+ *
+ * This function is to make the de-initialization for the ENC module. It could be called when ENC is no longer used with
+ * the operations like:
+ * - Disable the clock for ENC module.
+ *
+ * param base ENC peripheral base address.
+ */
+void ENC_Deinit(ENC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_encClocks[ENC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Get an available pre-defined settings for ENC's configuration.
+ *
+ * This function initializes the ENC configuration structure with an available settings, the default value are:
+ * code
+ * config->enableReverseDirection = false;
+ * config->decoderWorkMode = kENC_DecoderWorkAsNormalMode;
+ * config->HOMETriggerMode = kENC_HOMETriggerDisabled;
+ * config->INDEXTriggerMode = kENC_INDEXTriggerDisabled;
+ * config->enableTRIGGERClearPositionCounter = false;
+ * config->enableTRIGGERClearHoldPositionCounter = false;
+ * config->enableWatchdog = false;
+ * config->watchdogTimeoutValue = 0U;
+ * config->filterCount = 0U;
+ * config->filterSamplePeriod = 0U;
+ * config->positionMatchMode = kENC_POSMATCHOnPositionCounterEqualToComapreValue;
+ * config->positionCompareValue = 0xFFFFFFFFU;
+ * config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
+ * config->enableModuloCountMode = false;
+ * config->positionModulusValue = 0U;
+ * config->positionInitialValue = 0U;
+ * config->prescalerValue = kENC_ClockDiv1;
+ * config->enablePeriodMeasurementFunction = true;
+ * endcode
+ * param config Pointer to a variable of configuration structure. See to "enc_config_t".
+ */
+void ENC_GetDefaultConfig(enc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableReverseDirection = false;
+ config->decoderWorkMode = kENC_DecoderWorkAsNormalMode;
+ config->HOMETriggerMode = kENC_HOMETriggerDisabled;
+ config->INDEXTriggerMode = kENC_INDEXTriggerDisabled;
+ config->enableTRIGGERClearPositionCounter = false;
+ config->enableTRIGGERClearHoldPositionCounter = false;
+ config->enableWatchdog = false;
+ config->watchdogTimeoutValue = 0U;
+ config->filterCount = 0U;
+ config->filterSamplePeriod = 0U;
+ config->positionMatchMode = kENC_POSMATCHOnPositionCounterEqualToComapreValue;
+ config->positionCompareValue = 0xFFFFFFFFU;
+ config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
+ config->enableModuloCountMode = false;
+ config->positionModulusValue = 0U;
+ config->positionInitialValue = 0U;
+#if (defined(FSL_FEATURE_ENC_HAS_CTRL3) && FSL_FEATURE_ENC_HAS_CTRL3)
+ config->prescalerValue = kENC_ClockDiv1;
+ config->enablePeriodMeasurementFunction = true;
+#endif
+}
+
+/*!
+ * brief Load the initial position value to position counter.
+ *
+ * This function is to transfer the initial position value (UINIT and LINIT) contents to position counter (UPOS and
+ * LPOS), so that to provide the consistent operation the position counter registers.
+ *
+ * param base ENC peripheral base address.
+ */
+void ENC_DoSoftwareLoadInitialPositionValue(ENC_Type *base)
+{
+ uint16_t tmp16 = base->CTRL & (uint16_t)(~ENC_CTRL_W1C_FLAGS);
+
+ tmp16 |= ENC_CTRL_SWIP_MASK; /* Write 1 to trigger the command for loading initial position value. */
+ base->CTRL = tmp16;
+}
+
+/*!
+ * brief Enable and configure the self test function.
+ *
+ * This function is to enable and configuration the self test function. It controls and sets the frequency of a
+ * quadrature signal generator. It provides a quadrature test signal to the inputs of the quadrature decoder module.
+ * It is a factory test feature; however, it may be useful to customers' software development and testing.
+ *
+ * param base ENC peripheral base address.
+ * param config Pointer to configuration structure. See to "enc_self_test_config_t". Pass "NULL" to disable.
+ */
+void ENC_SetSelfTestConfig(ENC_Type *base, const enc_self_test_config_t *config)
+{
+ uint16_t tmp16 = 0U;
+
+ if (NULL == config) /* Pass "NULL" to disable the feature. */
+ {
+ tmp16 = 0U;
+ }
+ else
+ {
+ tmp16 = ENC_TST_TEN_MASK | ENC_TST_TCE_MASK | ENC_TST_TEST_PERIOD(config->signalPeriod) |
+ ENC_TST_TEST_COUNT(config->signalCount);
+ if (kENC_SelfTestDirectionNegative == config->signalDirection)
+ {
+ tmp16 |= ENC_TST_QDN_MASK;
+ }
+ }
+
+ base->TST = tmp16;
+}
+
+/*!
+ * brief Enable watchdog for ENC module.
+ *
+ * param base ENC peripheral base address
+ * param enable Enables or disables the watchdog
+ */
+void ENC_EnableWatchdog(ENC_Type *base, bool enable)
+{
+ uint16_t tmp16 = base->CTRL & (uint16_t)(~(ENC_CTRL_W1C_FLAGS | ENC_CTRL_WDE_MASK));
+
+ if (enable)
+ {
+ tmp16 |= ENC_CTRL_WDE_MASK;
+ }
+ base->CTRL = tmp16;
+}
+
+/*!
+ * brief Get the status flags.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Mask value of status flags. For available mask, see to "_enc_status_flags".
+ */
+uint32_t ENC_GetStatusFlags(ENC_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != (ENC_CTRL_HIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_HOMETransitionFlag;
+ }
+ if (0U != (ENC_CTRL_XIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_INDEXPulseFlag;
+ }
+ if (0U != (ENC_CTRL_DIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_WatchdogTimeoutFlag;
+ }
+ if (0U != (ENC_CTRL_CMPIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_PositionCompareFlag;
+ }
+
+ /* ENC_CTRL2. */
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ if (0U != (ENC_CTRL2_SABIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_SimultBothPhaseChangeFlag;
+ }
+#endif
+ if (0U != (ENC_CTRL2_ROIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollOverFlag;
+ }
+ if (0U != (ENC_CTRL2_RUIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollUnderFlag;
+ }
+ if (0U != (ENC_CTRL2_DIR_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_LastCountDirectionFlag;
+ }
+
+ return ret32;
+}
+
+/*!
+ * brief Clear the status flags.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of status flags to be cleared. For available mask, see to "_enc_status_flags".
+ */
+void ENC_ClearStatusFlags(ENC_Type *base, uint32_t mask)
+{
+ uint32_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_HIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_XIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_DIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIRQ_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL = (uint16_t)(((uint32_t)base->CTRL & (~ENC_CTRL_W1C_FLAGS)) | tmp16);
+ }
+
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIRQ_MASK;
+ }
+#endif
+ if (0U != ((uint32_t)kENC_PositionRollOverFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIRQ_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL2 = (uint16_t)(((uint32_t)base->CTRL2 & (~ENC_CTRL2_W1C_FLAGS)) | tmp16);
+ }
+}
+
+/*!
+ * brief Enable the interrupts.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of interrupts to be enabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_EnableInterrupts(ENC_Type *base, uint32_t mask)
+{
+ uint32_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_HIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_XIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_DIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareInerruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL = (uint16_t)(((uint32_t)base->CTRL & (~ENC_CTRL_W1C_FLAGS)) | tmp16);
+ }
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIE_MASK;
+ }
+#endif
+ if (0U != ((uint32_t)kENC_PositionRollOverInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL2 = (uint16_t)(((uint32_t)base->CTRL2 & (~ENC_CTRL2_W1C_FLAGS)) | tmp16);
+ }
+}
+
+/*!
+ * brief Disable the interrupts.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of interrupts to be disabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_DisableInterrupts(ENC_Type *base, uint32_t mask)
+{
+ uint16_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_HIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_XIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_DIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareInerruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIE_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL = (uint16_t)(base->CTRL & (uint16_t)(~ENC_CTRL_W1C_FLAGS)) & (uint16_t)(~tmp16);
+ }
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIE_MASK;
+ }
+#endif
+ if (0U != ((uint32_t)kENC_PositionRollOverInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL2 = (uint16_t)(base->CTRL2 & (uint16_t)(~ENC_CTRL2_W1C_FLAGS)) & (uint16_t)(~tmp16);
+ }
+}
+
+/*!
+ * brief Get the enabled interrupts' flags.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Mask value of enabled interrupts.
+ */
+uint32_t ENC_GetEnabledInterrupts(ENC_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != (ENC_CTRL_HIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_HOMETransitionInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_XIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_INDEXPulseInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_DIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_WatchdogTimeoutInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_CMPIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_PositionCompareInerruptEnable;
+ }
+ /* ENC_CTRL2. */
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ if (0U != (ENC_CTRL2_SABIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_SimultBothPhaseChangeInterruptEnable;
+ }
+#endif
+ if (0U != (ENC_CTRL2_ROIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollOverInterruptEnable;
+ }
+ if (0U != (ENC_CTRL2_RUIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollUnderInterruptEnable;
+ }
+ return ret32;
+}
+
+/*!
+ * brief Set initial position value for ENC module.
+ *
+ * param base ENC peripheral base address
+ * param value Positive initial value
+ */
+void ENC_SetInitialPositionValue(ENC_Type *base, uint32_t value)
+{
+ base->UINIT = (uint16_t)(value >> 16U); /* Set upper 16 bits. */
+ base->LINIT = (uint16_t)(value); /* Set lower 16 bits. */
+}
+
+/*!
+ * brief Get the current position counter's value.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Current position counter's value.
+ */
+uint32_t ENC_GetPositionValue(ENC_Type *base)
+{
+ uint32_t ret32;
+
+ ret32 = base->UPOS; /* Get upper 16 bits and make a snapshot. */
+ ret32 <<= 16U;
+ ret32 |= base->LPOSH; /* Get lower 16 bits from hold register. */
+
+ return ret32;
+}
+
+/*!
+ * brief Get the hold position counter's value.
+ *
+ * When any of the counter registers is read, the contents of each counter register is written to the corresponding hold
+ * register. Taking a snapshot of the counters' values provides a consistent view of a system position and a velocity to
+ * be attained.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Hold position counter's value.
+ */
+uint32_t ENC_GetHoldPositionValue(ENC_Type *base)
+{
+ uint32_t ret32;
+
+ ret32 = base->UPOSH; /* Get upper 16 bits and make a snapshot. */
+ ret32 <<= 16U;
+ ret32 |= base->LPOSH; /* Get lower 16 bits from hold register. */
+
+ return ret32;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.h b/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.h
new file mode 100644
index 0000000000..28ce466ce3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/enc/fsl_enc.h
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_ENC_H_
+#define _FSL_ENC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup enc
+ * @{
+ */
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define FSL_ENC_DRIVER_VERSION (MAKE_VERSION(2, 1, 0))
+
+/*!
+ * @brief Interrupt enable/disable mask.
+ */
+enum _enc_interrupt_enable
+{
+ kENC_HOMETransitionInterruptEnable = (1U << 0U), /*!< HOME interrupt enable. */
+ kENC_INDEXPulseInterruptEnable = (1U << 1U), /*!< INDEX pulse interrupt enable. */
+ kENC_WatchdogTimeoutInterruptEnable = (1U << 2U), /*!< Watchdog timeout interrupt enable. */
+ kENC_PositionCompareInerruptEnable = (1U << 3U), /*!< Position compare interrupt enable. */
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ kENC_SimultBothPhaseChangeInterruptEnable =
+ (1U << 4U), /*!< Simultaneous PHASEA and PHASEB change interrupt enable. */
+#endif
+ kENC_PositionRollOverInterruptEnable = (1U << 5U), /*!< Roll-over interrupt enable. */
+ kENC_PositionRollUnderInterruptEnable = (1U << 6U), /*!< Roll-under interrupt enable. */
+};
+
+/*!
+ * @brief Status flag mask.
+ *
+ * These flags indicate the counter's events.
+ */
+enum _enc_status_flags
+{
+ kENC_HOMETransitionFlag = (1U << 0U), /*!< HOME signal transition interrupt request. */
+ kENC_INDEXPulseFlag = (1U << 1U), /*!< INDEX Pulse Interrupt Request. */
+ kENC_WatchdogTimeoutFlag = (1U << 2U), /*!< Watchdog timeout interrupt request. */
+ kENC_PositionCompareFlag = (1U << 3U), /*!< Position compare interrupt request. */
+#if !(defined(FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT) && FSL_FEATURE_ENC_HAS_NO_CTRL2_SAB_INT)
+ kENC_SimultBothPhaseChangeFlag = (1U << 4U), /*!< Simultaneous PHASEA and PHASEB change interrupt request. */
+#endif
+ kENC_PositionRollOverFlag = (1U << 5U), /*!< Roll-over interrupt request. */
+ kENC_PositionRollUnderFlag = (1U << 6U), /*!< Roll-under interrupt request. */
+ kENC_LastCountDirectionFlag = (1U << 7U), /*!< Last count was in the up direction, or the down direction. */
+};
+
+/*!
+ * @brief Signal status flag mask.
+ *
+ * These flags indicate the counter's signal.
+ */
+enum _enc_signal_status_flags
+{
+ kENC_RawHOMEStatusFlag = ENC_IMR_HOME_MASK, /*!< Raw HOME input. */
+ kENC_RawINDEXStatusFlag = ENC_IMR_INDEX_MASK, /*!< Raw INDEX input. */
+ kENC_RawPHBStatusFlag = ENC_IMR_PHB_MASK, /*!< Raw PHASEB input. */
+ kENC_RawPHAEXStatusFlag = ENC_IMR_PHA_MASK, /*!< Raw PHASEA input. */
+ kENC_FilteredHOMEStatusFlag = ENC_IMR_FHOM_MASK, /*!< The filtered version of HOME input. */
+ kENC_FilteredINDEXStatusFlag = ENC_IMR_FIND_MASK, /*!< The filtered version of INDEX input. */
+ kENC_FilteredPHBStatusFlag = ENC_IMR_FPHB_MASK, /*!< The filtered version of PHASEB input. */
+ kENC_FilteredPHAStatusFlag = ENC_IMR_FPHA_MASK, /*!< The filtered version of PHASEA input. */
+};
+
+/*!
+ * @brief Define HOME signal's trigger mode.
+ *
+ * The ENC would count the trigger from HOME signal line.
+ */
+typedef enum _enc_home_trigger_mode
+{
+ kENC_HOMETriggerDisabled = 0U, /*!< HOME signal's trigger is disabled. */
+ kENC_HOMETriggerOnRisingEdge, /*!< Use positive going edge-to-trigger initialization of position counters. */
+ kENC_HOMETriggerOnFallingEdge, /*!< Use negative going edge-to-trigger initialization of position counters. */
+} enc_home_trigger_mode_t;
+
+/*!
+ * @brief Define INDEX signal's trigger mode.
+ *
+ * The ENC would count the trigger from INDEX signal line.
+ */
+typedef enum _enc_index_trigger_mode
+{
+ kENC_INDEXTriggerDisabled = 0U, /*!< INDEX signal's trigger is disabled. */
+ kENC_INDEXTriggerOnRisingEdge, /*!< Use positive going edge-to-trigger initialization of position counters. */
+ kENC_INDEXTriggerOnFallingEdge, /*!< Use negative going edge-to-trigger initialization of position counters. */
+} enc_index_trigger_mode_t;
+
+/*!
+ * @brief Define type for decoder work mode.
+ *
+ * The normal work mode uses the standard quadrature decoder with PHASEA and PHASEB. When in signal phase count mode,
+ * a positive transition of the PHASEA input generates a count signal while the PHASEB input and the reverse direction
+ * control the counter direction. If the reverse direction is not enabled, PHASEB = 0 means counting up and PHASEB = 1
+ * means counting down. Otherwise, the direction is reversed.
+ */
+typedef enum _enc_decoder_work_mode
+{
+ kENC_DecoderWorkAsNormalMode = 0U, /*!< Use standard quadrature decoder with PHASEA and PHASEB. */
+ kENC_DecoderWorkAsSignalPhaseCountMode, /*!< PHASEA input generates a count signal while PHASEB input control the
+ direction. */
+} enc_decoder_work_mode_t;
+
+/*!
+ * @brief Define type for the condition of POSMATCH pulses.
+ */
+typedef enum _enc_position_match_mode
+{
+ kENC_POSMATCHOnPositionCounterEqualToComapreValue = 0U, /*!< POSMATCH pulses when a match occurs between the
+ position counters (POS) and the compare value (COMP). */
+ kENC_POSMATCHOnReadingAnyPositionCounter, /*!< POSMATCH pulses when any position counter register is read. */
+} enc_position_match_mode_t;
+
+/*!
+ * @brief Define type for determining how the revolution counter (REV) is incremented/decremented.
+ */
+typedef enum _enc_revolution_count_condition
+{
+ kENC_RevolutionCountOnINDEXPulse = 0U, /*!< Use INDEX pulse to increment/decrement revolution counter. */
+ kENC_RevolutionCountOnRollOverModulus, /*!< Use modulus counting roll-over/under to increment/decrement revolution
+ counter. */
+} enc_revolution_count_condition_t;
+
+/*!
+ * @brief Define type for direction of self test generated signal.
+ */
+typedef enum _enc_self_test_direction
+{
+ kENC_SelfTestDirectionPositive = 0U, /*!< Self test generates the signal in positive direction. */
+ kENC_SelfTestDirectionNegative, /*!< Self test generates the signal in negative direction. */
+} enc_self_test_direction_t;
+
+#if (defined(FSL_FEATURE_ENC_HAS_CTRL3) && FSL_FEATURE_ENC_HAS_CTRL3)
+/*!
+ * @brief Define prescaler value for clock in CTRL3.
+ *
+ * The clock is prescaled by a value of 2^PRSC which means that the prescaler logic
+ * can divide the clock by a minimum of 1 and a maximum of 32,768.
+ */
+typedef enum _enc_prescaler
+{
+ kENC_ClockDiv1 = 0,
+ kENC_ClockDiv2 = 1,
+ kENC_ClockDiv4 = 2,
+ kENC_ClockDiv8 = 3,
+ kENC_ClockDiv16 = 4,
+ kENC_ClockDiv32 = 5,
+ kENC_ClockDiv64 = 6,
+ kENC_ClockDiv128 = 7,
+ kENC_ClockDiv256 = 8,
+ kENC_ClockDiv512 = 9,
+ kENC_ClockDiv1024 = 10,
+ kENC_ClockDiv2048 = 11,
+ kENC_ClockDiv4096 = 12,
+ kENC_ClockDiv8192 = 13,
+ kENC_ClockDiv16384 = 14,
+ kENC_ClockDiv32768 = 15,
+} enc_prescaler_t;
+#endif
+
+/*!
+ * @brief Define user configuration structure for ENC module.
+ */
+typedef struct _enc_config
+{
+ /* Basic counter. */
+ bool enableReverseDirection; /*!< Enable reverse direction counting. */
+ enc_decoder_work_mode_t decoderWorkMode; /*!< Enable signal phase count mode. */
+
+ /* Signal detection. */
+ enc_home_trigger_mode_t HOMETriggerMode; /*!< Enable HOME to initialize position counters. */
+ enc_index_trigger_mode_t INDEXTriggerMode; /*!< Enable INDEX to initialize position counters. */
+ bool enableTRIGGERClearPositionCounter; /*!< Clear POSD, REV, UPOS and LPOS on rising edge of TRIGGER, or not. */
+ bool enableTRIGGERClearHoldPositionCounter; /*!< Enable update of hold registers on rising edge of TRIGGER, or not.
+ */
+
+ /* Watchdog. */
+ bool enableWatchdog; /*!< Enable the watchdog to detect if the target is moving or not. */
+ uint16_t watchdogTimeoutValue; /*!< Watchdog timeout count value. It stores the timeout count for the quadrature
+ decoder module watchdog timer. This field is only available when
+ "enableWatchdog" = true. The available value is a 16-bit unsigned number.*/
+
+ /* Filter for PHASEA, PHASEB, INDEX and HOME. */
+ uint16_t filterCount; /*!< Input Filter Sample Count. This value should be chosen to reduce the probability of
+ noisy samples causing an incorrect transition to be recognized. The value represent the
+ number of consecutive samples that must agree prior to the input filter accepting an
+ input transition. A value of 0x0 represents 3 samples. A value of 0x7 represents 10
+ samples. The Available range is 0 - 7.*/
+ uint16_t filterSamplePeriod; /*!< Input Filter Sample Period. This value should be set such that the sampling period
+ is larger than the period of the expected noise. This value represents the
+ sampling period (in IPBus clock cycles) of the decoder input signals.
+ The available range is 0 - 255. */
+
+ /* Position compare. */
+ enc_position_match_mode_t positionMatchMode; /*!< The condition of POSMATCH pulses. */
+ uint32_t positionCompareValue; /*!< Position compare value. The available value is a 32-bit number.*/
+
+ /* Modulus counting. */
+ enc_revolution_count_condition_t revolutionCountCondition; /*!< Revolution Counter Modulus Enable. */
+ bool enableModuloCountMode; /*!< Enable Modulo Counting. */
+ uint32_t positionModulusValue; /*!< Position modulus value. This value would be available only when
+ "enableModuloCountMode" = true. The available value is a 32-bit number. */
+ uint32_t positionInitialValue; /*!< Position initial value. The available value is a 32-bit number. */
+
+#if (defined(FSL_FEATURE_ENC_HAS_CTRL3) && FSL_FEATURE_ENC_HAS_CTRL3)
+ /* Prescaler. */
+ bool enablePeriodMeasurementFunction; /*!< Enable period measurement function. */
+ enc_prescaler_t prescalerValue; /*!< The value of prescaler. */
+#endif
+} enc_config_t;
+
+/*!
+ * @brief Define configuration structure for self test module.
+ *
+ * The self test module provides a quadrature test signal to the inputs of the quadrature decoder module.
+ * This is a factory test feature. It is also useful to customers' software development and testing.
+ */
+typedef struct _enc_self_test_config
+{
+ enc_self_test_direction_t signalDirection; /*!< Direction of self test generated signal. */
+ uint16_t signalCount; /*!< Hold the number of quadrature advances to generate. The available range is 0 - 255.*/
+ uint16_t signalPeriod; /*!< Hold the period of quadrature phase in IPBus clock cycles.
+ The available range is 0 - 31. */
+} enc_self_test_config_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+/*!
+ * @name Initialization and De-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initialization for the ENC module.
+ *
+ * This function is to make the initialization for the ENC module. It should be called firstly before any operation to
+ * the ENC with the operations like:
+ * - Enable the clock for ENC module.
+ * - Configure the ENC's working attributes.
+ *
+ * @param base ENC peripheral base address.
+ * @param config Pointer to configuration structure. See to "enc_config_t".
+ */
+void ENC_Init(ENC_Type *base, const enc_config_t *config);
+
+/*!
+ * @brief De-initialization for the ENC module.
+ *
+ * This function is to make the de-initialization for the ENC module. It could be called when ENC is no longer used with
+ * the operations like:
+ * - Disable the clock for ENC module.
+ *
+ * @param base ENC peripheral base address.
+ */
+void ENC_Deinit(ENC_Type *base);
+
+/*!
+ * @brief Get an available pre-defined settings for ENC's configuration.
+ *
+ * This function initializes the ENC configuration structure with an available settings, the default value are:
+ * @code
+ * config->enableReverseDirection = false;
+ * config->decoderWorkMode = kENC_DecoderWorkAsNormalMode;
+ * config->HOMETriggerMode = kENC_HOMETriggerDisabled;
+ * config->INDEXTriggerMode = kENC_INDEXTriggerDisabled;
+ * config->enableTRIGGERClearPositionCounter = false;
+ * config->enableTRIGGERClearHoldPositionCounter = false;
+ * config->enableWatchdog = false;
+ * config->watchdogTimeoutValue = 0U;
+ * config->filterCount = 0U;
+ * config->filterSamplePeriod = 0U;
+ * config->positionMatchMode = kENC_POSMATCHOnPositionCounterEqualToComapreValue;
+ * config->positionCompareValue = 0xFFFFFFFFU;
+ * config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
+ * config->enableModuloCountMode = false;
+ * config->positionModulusValue = 0U;
+ * config->positionInitialValue = 0U;
+ * config->prescalerValue = kENC_ClockDiv1;
+ * config->enablePeriodMeasurementFunction = true;
+ * @endcode
+ * @param config Pointer to a variable of configuration structure. See to "enc_config_t".
+ */
+void ENC_GetDefaultConfig(enc_config_t *config);
+
+/*!
+ * @brief Load the initial position value to position counter.
+ *
+ * This function is to transfer the initial position value (UINIT and LINIT) contents to position counter (UPOS and
+ * LPOS), so that to provide the consistent operation the position counter registers.
+ *
+ * @param base ENC peripheral base address.
+ */
+void ENC_DoSoftwareLoadInitialPositionValue(ENC_Type *base);
+
+/*!
+ * @brief Enable and configure the self test function.
+ *
+ * This function is to enable and configuration the self test function. It controls and sets the frequency of a
+ * quadrature signal generator. It provides a quadrature test signal to the inputs of the quadrature decoder module.
+ * It is a factory test feature; however, it may be useful to customers' software development and testing.
+ *
+ * @param base ENC peripheral base address.
+ * @param config Pointer to configuration structure. See to "enc_self_test_config_t". Pass "NULL" to disable.
+ */
+void ENC_SetSelfTestConfig(ENC_Type *base, const enc_self_test_config_t *config);
+
+/*!
+ * @brief Enable watchdog for ENC module.
+ *
+ * @param base ENC peripheral base address
+ * @param enable Enables or disables the watchdog
+ */
+void ENC_EnableWatchdog(ENC_Type *base, bool enable);
+
+/*!
+ * @brief Set initial position value for ENC module.
+ *
+ * @param base ENC peripheral base address
+ * @param value Positive initial value
+ */
+void ENC_SetInitialPositionValue(ENC_Type *base, uint32_t value);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+/*!
+ * @brief Get the status flags.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Mask value of status flags. For available mask, see to "_enc_status_flags".
+ */
+uint32_t ENC_GetStatusFlags(ENC_Type *base);
+
+/*!
+ * @brief Clear the status flags.
+ *
+ * @param base ENC peripheral base address.
+ * @param mask Mask value of status flags to be cleared. For available mask, see to "_enc_status_flags".
+ */
+void ENC_ClearStatusFlags(ENC_Type *base, uint32_t mask);
+
+/*!
+ * @brief Get the signals' real-time status.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Mask value of signals' real-time status. For available mask, see to "_enc_signal_status_flags"
+ */
+static inline uint16_t ENC_GetSignalStatusFlags(ENC_Type *base)
+{
+ return base->IMR;
+}
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enable the interrupts.
+ *
+ * @param base ENC peripheral base address.
+ * @param mask Mask value of interrupts to be enabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_EnableInterrupts(ENC_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disable the interrupts.
+ *
+ * @param base ENC peripheral base address.
+ * @param mask Mask value of interrupts to be disabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_DisableInterrupts(ENC_Type *base, uint32_t mask);
+
+/*!
+ * @brief Get the enabled interrupts' flags.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Mask value of enabled interrupts.
+ */
+uint32_t ENC_GetEnabledInterrupts(ENC_Type *base);
+
+/* @} */
+
+/*!
+ * @name Value Operation
+ * @{
+ */
+
+/*!
+ * @brief Get the current position counter's value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Current position counter's value.
+ */
+uint32_t ENC_GetPositionValue(ENC_Type *base);
+
+/*!
+ * @brief Get the hold position counter's value.
+ *
+ * When any of the counter registers is read, the contents of each counter register is written to the corresponding hold
+ * register. Taking a snapshot of the counters' values provides a consistent view of a system position and a velocity to
+ * be attained.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Hold position counter's value.
+ */
+uint32_t ENC_GetHoldPositionValue(ENC_Type *base);
+
+/*!
+ * @brief Get the position difference counter's value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The position difference counter's value.
+ */
+static inline uint16_t ENC_GetPositionDifferenceValue(ENC_Type *base)
+{
+ return base->POSD;
+}
+
+/*!
+ * @brief Get the hold position difference counter's value.
+ *
+ * When any of the counter registers is read, the contents of each counter register is written to the corresponding hold
+ * register. Taking a snapshot of the counters' values provides a consistent view of a system position and a velocity to
+ * be attained.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Hold position difference counter's value.
+ */
+static inline uint16_t ENC_GetHoldPositionDifferenceValue(ENC_Type *base)
+{
+ return base->POSDH;
+}
+
+/*!
+ * @brief Get the position revolution counter's value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The position revolution counter's value.
+ */
+static inline uint16_t ENC_GetRevolutionValue(ENC_Type *base)
+{
+ return base->REV;
+}
+
+/*!
+ * @brief Get the hold position revolution counter's value.
+ *
+ * When any of the counter registers is read, the contents of each counter register is written to the corresponding hold
+ * register. Taking a snapshot of the counters' values provides a consistent view of a system position and a velocity to
+ * be attained.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return Hold position revolution counter's value.
+ */
+static inline uint16_t ENC_GetHoldRevolutionValue(ENC_Type *base)
+{
+ return base->REVH;
+}
+
+#if (defined(FSL_FEATURE_ENC_HAS_LASTEDGE) && FSL_FEATURE_ENC_HAS_LASTEDGE)
+/*!
+ * @brief Get the last edge time value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The last edge time hold value.
+ */
+static inline uint16_t ENC_GetLastEdgeTimeValue(ENC_Type *base)
+{
+ return base->LASTEDGE;
+}
+
+/*!
+ * @brief Get the last edge time hold value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The last edge time hold value.
+ */
+static inline uint16_t ENC_GetHoldLastEdgeTimeValue(ENC_Type *base)
+{
+ return base->LASTEDGEH;
+}
+#endif
+
+#if (defined(FSL_FEATURE_ENC_HAS_POSDPER) && FSL_FEATURE_ENC_HAS_POSDPER)
+/*!
+ * @brief Get the position difference period value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The position difference period hold value.
+ */
+static inline uint16_t ENC_GetPositionDifferencePeriodValue(ENC_Type *base)
+{
+ return base->POSDPER;
+}
+
+/*!
+ * @brief Get the position difference period buffer value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The position difference period hold value.
+ */
+static inline uint16_t ENC_GetPositionDifferencePeriodBufferValue(ENC_Type *base)
+{
+ return base->POSDPERBFR;
+}
+
+/*!
+ * @brief Get the position difference period hold value.
+ *
+ * @param base ENC peripheral base address.
+ *
+ * @return The position difference period hold value.
+ */
+static inline uint16_t ENC_GetHoldPositionDifferencePeriodValue(ENC_Type *base)
+{
+ return base->POSDPERH;
+}
+#endif
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* @} */
+
+#endif /* _FSL_ENC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.c b/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.c
new file mode 100644
index 0000000000..f6f5e68f89
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.c
@@ -0,0 +1,3993 @@
+/*
+ * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enet.h"
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+#include "fsl_cache.h"
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.enet"
+#endif
+
+/*! @brief Ethernet mac address length. */
+#define ENET_FRAME_MACLEN 6U
+/*! @brief MDC frequency. */
+#define ENET_MDC_FREQUENCY 2500000U
+/*! @brief NanoSecond in one second. */
+#define ENET_NANOSECOND_ONE_SECOND 1000000000U
+
+/*! @brief Define the ENET ring/class bumber . */
+enum
+{
+ kENET_Ring0 = 0U, /*!< ENET ring/class 0. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ kENET_Ring1 = 1U, /*!< ENET ring/class 1. */
+ kENET_Ring2 = 2U /*!< ENET ring/class 2. */
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to enet clocks for each instance. */
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+const clock_ip_name_t s_enetClock[] = ENET_CLOCKS;
+#if defined(FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE) && FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE
+const clock_ip_name_t s_enetExtraClock[] = ENET_EXTRA_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to enet transmit IRQ number for each instance. */
+static const IRQn_Type s_enetTxIrqId[] = ENET_Transmit_IRQS;
+/*! @brief Pointers to enet receive IRQ number for each instance. */
+static const IRQn_Type s_enetRxIrqId[] = ENET_Receive_IRQS;
+#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*! @brief Pointers to enet timestamp IRQ number for each instance. */
+static const IRQn_Type s_enetTsIrqId[] = ENET_Ts_IRQS;
+/*! @brief Pointers to enet 1588 timestamp IRQ number for each instance. */
+static const IRQn_Type s_enet1588TimerIrqId[] = ENET_1588_Timer_IRQS;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+/*! @brief Pointers to enet error IRQ number for each instance. */
+static const IRQn_Type s_enetErrIrqId[] = ENET_Error_IRQS;
+
+/*! @brief Pointers to enet bases for each instance. */
+static ENET_Type *const s_enetBases[] = ENET_BASE_PTRS;
+
+/*! @brief Pointers to enet handles for each instance. */
+static enet_handle_t *s_ENETHandle[ARRAY_SIZE(s_enetBases)];
+
+/* ENET ISR for transactional APIs. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+static enet_isr_ring_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_ring_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)];
+#else
+static enet_isr_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)];
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+static enet_isr_t s_enetErrIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_t s_enetTsIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_t s_enet1588TimerIsr[ARRAY_SIZE(s_enetBases)];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Set ENET MAC controller with the configuration.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param config ENET Mac configuration.
+ * @param bufferConfig ENET buffer configuration.
+ * @param macAddr ENET six-byte mac address.
+ * @param srcClock_Hz ENET module clock source, normally it's system clock.
+ */
+static void ENET_SetMacController(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Set ENET handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param config ENET configuration stucture pointer.
+ * @param bufferConfig ENET buffer configuration.
+ */
+static void ENET_SetHandler(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Set ENET MAC transmit buffer descriptors.
+ *
+ * @param handle The ENET handle pointer.
+ * @param config The ENET configuration structure.
+ * @param bufferConfig The ENET buffer configuration.
+ */
+static void ENET_SetTxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig);
+
+/*!
+ * @brief Set ENET MAC receive buffer descriptors.
+ *
+ * @param handle The ENET handle pointer.
+ * @param config The ENET configuration structure.
+ * @param bufferConfig The ENET buffer configuration.
+ */
+static void ENET_SetRxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig);
+
+/*!
+ * @brief Updates the ENET read buffer descriptors.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param ringId The descriptor ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ */
+static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId);
+
+/*!
+ * @brief Updates index.
+ */
+static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max);
+
+/*!
+ * @brief Allocates all Rx buffers in BDs.
+ */
+static status_t ENET_RxBufferAllocAll(ENET_Type *base, enet_handle_t *handle);
+
+/*!
+ * @brief Frees all Rx buffers in BDs.
+ */
+static void ENET_RxBufferFreeAll(ENET_Type *base, enet_handle_t *handle);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief Get the ENET instance from peripheral base address.
+ *
+ * @param base ENET peripheral base address.
+ * @return ENET instance.
+ */
+uint32_t ENET_GetInstance(ENET_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_enetBases); instance++)
+ {
+ if (s_enetBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_enetBases));
+
+ return instance;
+}
+
+/*!
+ * brief Gets the ENET default configuration structure.
+ *
+ * The purpose of this API is to get the default ENET MAC controller
+ * configure structure for ENET_Init(). User may use the initialized
+ * structure unchanged in ENET_Init(), or modify some fields of the
+ * structure before calling ENET_Init().
+ * Example:
+ code
+ enet_config_t config;
+ ENET_GetDefaultConfig(&config);
+ endcode
+ * param config The ENET mac controller configuration structure pointer.
+ */
+void ENET_GetDefaultConfig(enet_config_t *config)
+{
+ /* Checks input parameter. */
+ assert(config != NULL);
+
+ /* Initializes the MAC configure structure to zero. */
+ (void)memset(config, 0, sizeof(enet_config_t));
+
+ /* Sets MII mode, full duplex, 100Mbps for MAC and PHY data interface. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ config->miiMode = kENET_RgmiiMode;
+#else
+ config->miiMode = kENET_RmiiMode;
+#endif
+ config->miiSpeed = kENET_MiiSpeed100M;
+ config->miiDuplex = kENET_MiiFullDuplex;
+
+ config->ringNum = 1;
+
+ /* Sets the maximum receive frame length. */
+ config->rxMaxFrameLen = ENET_FRAME_MAX_FRAMELEN;
+}
+
+/*!
+ * brief Initializes the ENET module.
+ *
+ * This function initializes the module with the ENET configuration.
+ * note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Up().
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * param srcClock_Hz The internal module clock source for MII clock.
+ * retval kStatus_Success Succeed to initialize the ethernet driver.
+ * retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough.
+ */
+status_t ENET_Up(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+ /* Checks input parameters. */
+ assert(handle != NULL);
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+ assert(macAddr != NULL);
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+ assert(config->ringNum <= (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ status_t result = kStatus_Success;
+
+ /* Initializes the ENET transmit buffer descriptors. */
+ ENET_SetTxBufferDescriptors(handle, config, bufferConfig);
+
+ /* Initializes the ENET receive buffer descriptors. */
+ ENET_SetRxBufferDescriptors(handle, config, bufferConfig);
+
+ /* Initializes the ENET MAC controller with basic function. */
+ ENET_SetMacController(base, handle, config, bufferConfig, macAddr, srcClock_Hz);
+
+ /* Set all buffers or data in handler for data transmit/receive process. */
+ ENET_SetHandler(base, handle, config, bufferConfig, srcClock_Hz);
+
+ /* Allocate buffers for all Rx BDs when zero copy Rx API is needed. */
+ if (handle->rxBuffAlloc != NULL)
+ {
+ result = ENET_RxBufferAllocAll(base, handle);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the ENET module.
+ *
+ * This function ungates the module clock and initializes it with the ENET configuration.
+ * note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Init().
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * param srcClock_Hz The internal module clock source for MII clock.
+ * retval kStatus_Success Succeed to initialize the ethernet driver.
+ * retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough.
+ */
+status_t ENET_Init(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = ENET_GetInstance(base);
+
+ /* Ungate ENET clock. */
+ (void)CLOCK_EnableClock(s_enetClock[instance]);
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE) && FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE
+ /* Ungate ENET extra clock. */
+ (void)CLOCK_EnableClock(s_enetExtraClock[instance]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* Reset ENET module. */
+ ENET_Reset(base);
+
+ return ENET_Up(base, handle, config, bufferConfig, macAddr, srcClock_Hz);
+}
+
+/*!
+ * brief Stops the ENET module.
+
+ * This function disables the ENET module.
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_Down(ENET_Type *base)
+{
+ uint32_t instance = ENET_GetInstance(base);
+ enet_handle_t *handle = s_ENETHandle[instance];
+
+ /* Disable interrupt. */
+ base->EIMR = 0;
+
+ /* Disable ENET. */
+ base->ECR &= ~ENET_ECR_ETHEREN_MASK;
+
+ if (handle->rxBuffFree != NULL)
+ {
+ ENET_RxBufferFreeAll(base, handle);
+ }
+}
+
+/*!
+ * brief Deinitializes the ENET module.
+
+ * This function gates the module clock, clears ENET interrupts, and disables the ENET module.
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_Deinit(ENET_Type *base)
+{
+ ENET_Down(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disables the clock source. */
+ (void)CLOCK_DisableClock(s_enetClock[ENET_GetInstance(base)]);
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE) && FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE
+ /* Disables ENET extra clock. */
+ (void)CLOCK_DisableClock(s_enetExtraClock[ENET_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * deprecated Do not use this function. It has been superceded by the config param in @ref ENET_Init.
+ */
+void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Set callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetRxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetRxIrqId[instance]);
+}
+
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTxIrqId[instance]);
+}
+#else
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetRxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetRxIrqId[instance]);
+}
+
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTxIrqId[instance]);
+}
+#endif
+
+void ENET_SetErrISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetErrIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetErrIrqId[instance]);
+}
+
+#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+void ENET_SetTsISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTsIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTsIrqId[instance]);
+}
+
+void ENET_Set1588TimerISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enet1588TimerIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enet1588TimerIrqId[instance]);
+}
+#endif
+
+static void ENET_SetHandler(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint32_t srcClock_Hz)
+{
+ uint8_t count;
+ uint32_t instance = ENET_GetInstance(base);
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+
+ /* Store transfer parameters in handle pointer. */
+ (void)memset(handle, 0, sizeof(enet_handle_t));
+
+ for (count = 0; count < config->ringNum; count++)
+ {
+ assert(buffCfg->rxBuffSizeAlign * buffCfg->rxBdNumber > config->rxMaxFrameLen);
+
+ handle->rxBdRing[count].rxBdBase = buffCfg->rxBdStartAddrAlign;
+ handle->rxBuffSizeAlign[count] = buffCfg->rxBuffSizeAlign;
+ handle->rxBdRing[count].rxRingLen = buffCfg->rxBdNumber;
+ handle->rxMaintainEnable[count] = buffCfg->rxMaintainEnable;
+ handle->txBdRing[count].txBdBase = buffCfg->txBdStartAddrAlign;
+ handle->txBuffSizeAlign[count] = buffCfg->txBuffSizeAlign;
+ handle->txBdRing[count].txRingLen = buffCfg->txBdNumber;
+ handle->txMaintainEnable[count] = buffCfg->txMaintainEnable;
+ handle->txDirtyRing[count].txDirtyBase = buffCfg->txFrameInfo;
+ handle->txDirtyRing[count].txRingLen = buffCfg->txBdNumber;
+ buffCfg++;
+ }
+
+ handle->ringNum = config->ringNum;
+ handle->rxBuffAlloc = config->rxBuffAlloc;
+ handle->rxBuffFree = config->rxBuffFree;
+ handle->callback = config->callback;
+ handle->userData = config->userData;
+#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID
+ handle->enetClock = srcClock_Hz;
+#endif
+
+ /* Save the handle pointer in the global variables. */
+ s_ENETHandle[instance] = handle;
+
+ /* Set the IRQ handler when the interrupt is enabled. */
+ if (0U != (config->interrupt & (uint32_t)ENET_TX_INTERRUPT))
+ {
+ ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler);
+ }
+ if (0U != (config->interrupt & (uint32_t)ENET_RX_INTERRUPT))
+ {
+ ENET_SetRxISRHandler(base, ENET_ReceiveIRQHandler);
+ }
+ if (0U != (config->interrupt & (uint32_t)ENET_ERR_INTERRUPT))
+ {
+ ENET_SetErrISRHandler(base, ENET_ErrorIRQHandler);
+ }
+}
+
+static void ENET_SetMacController(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1)
+ {
+ /* Check the MII mode/speed/duplex setting. */
+ if (config->miiSpeed == kENET_MiiSpeed1000M)
+ {
+ /* Only RGMII mode has the 1000M bit/s. The 1000M only support full duplex. */
+ assert(config->miiMode == kENET_RgmiiMode);
+ assert(config->miiDuplex == kENET_MiiFullDuplex);
+ }
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ uint32_t rcr = 0;
+ uint32_t tcr = 0;
+ uint32_t ecr = base->ECR;
+ uint32_t macSpecialConfig = config->macSpecialConfig;
+ uint32_t maxFrameLen = config->rxMaxFrameLen;
+ uint32_t configVal = 0;
+
+ /* Maximum frame length check. */
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlVLANTagEnable))
+ {
+ maxFrameLen = (ENET_FRAME_MAX_FRAMELEN + ENET_FRAME_VLAN_TAGLEN);
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1)
+ {
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable))
+ {
+ /* Double vlan tag (SVLAN) supported. */
+ maxFrameLen += ENET_FRAME_VLAN_TAGLEN;
+ }
+ ecr |= (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable) != 0U) ?
+ (ENET_ECR_SVLANEN_MASK | ENET_ECR_SVLANDBL_MASK) :
+ 0U) |
+ (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlVLANUseSecondTag) != 0U) ?
+ ENET_ECR_VLANUSE2ND_MASK :
+ 0U);
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ }
+
+ /* Configures MAC receive controller with user configure structure. */
+ rcr = ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPayloadCheckEnable)) ? ENET_RCR_NLC_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_CFEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_FCE_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPadRemoveEnable)) ? ENET_RCR_PADEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxBroadCastRejectEnable)) ? ENET_RCR_BC_REJ_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlPromiscuousEnable)) ? ENET_RCR_PROM_MASK : 0U) |
+ ENET_RCR_MAX_FL(maxFrameLen) | ENET_RCR_CRCFWD_MASK;
+
+/* Set the RGMII or RMII, MII mode and control register. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1)
+ {
+ if (config->miiMode == kENET_RgmiiMode)
+ {
+ rcr |= ENET_RCR_RGMII_EN_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_RGMII_EN_MASK;
+ }
+
+ if (config->miiSpeed == kENET_MiiSpeed1000M)
+ {
+ ecr |= ENET_ECR_SPEED_MASK;
+ }
+ else
+ {
+ ecr &= ~ENET_ECR_SPEED_MASK;
+ }
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ rcr |= ENET_RCR_MII_MODE_MASK;
+ if (config->miiMode == kENET_RmiiMode)
+ {
+ rcr |= ENET_RCR_RMII_MODE_MASK;
+ }
+
+ /* Speed. */
+ if (config->miiSpeed == kENET_MiiSpeed10M)
+ {
+ rcr |= ENET_RCR_RMII_10T_MASK;
+ }
+
+ /* Receive setting for half duplex. */
+ if (config->miiDuplex == kENET_MiiHalfDuplex)
+ {
+ rcr |= ENET_RCR_DRT_MASK;
+ }
+ /* Sets internal loop only for MII mode. */
+ if ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlMIILoopEnable)) &&
+ (config->miiMode != kENET_RmiiMode))
+ {
+ rcr |= ENET_RCR_LOOP_MASK;
+ rcr &= ~ENET_RCR_DRT_MASK;
+ }
+ base->RCR = rcr;
+
+ /* Configures MAC transmit controller: duplex mode, mac address insertion. */
+ tcr = base->TCR & ~(ENET_TCR_FDEN_MASK | ENET_TCR_ADDINS_MASK);
+ tcr |= ((kENET_MiiHalfDuplex != config->miiDuplex) ? (uint32_t)ENET_TCR_FDEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlMacAddrInsert)) ? (uint32_t)ENET_TCR_ADDINS_MASK : 0U);
+ base->TCR = tcr;
+
+ /* Configures receive and transmit accelerator. */
+ base->TACC = config->txAccelerConfig;
+ base->RACC = config->rxAccelerConfig;
+
+ /* Sets the pause duration and FIFO threshold for the flow control enabled case. */
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable))
+ {
+ uint32_t reemReg;
+ base->OPD = config->pauseDuration;
+ reemReg = ENET_RSEM_RX_SECTION_EMPTY(config->rxFifoEmptyThreshold);
+#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD
+ reemReg |= ENET_RSEM_STAT_SECTION_EMPTY(config->rxFifoStatEmptyThreshold);
+#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */
+ base->RSEM = reemReg;
+ }
+
+ /* FIFO threshold setting for store and forward enable/disable case. */
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlStoreAndFwdDisable))
+ {
+ /* Transmit fifo watermark settings. */
+ configVal = ((uint32_t)config->txFifoWatermark) & ENET_TFWR_TFWR_MASK;
+ base->TFWR = configVal;
+ /* Receive fifo full threshold settings. */
+ configVal = ((uint32_t)config->rxFifoFullThreshold) & ENET_RSFL_RX_SECTION_FULL_MASK;
+ base->RSFL = configVal;
+ }
+ else
+ {
+ /* Transmit fifo watermark settings. */
+ base->TFWR = ENET_TFWR_STRFWD_MASK;
+ base->RSFL = 0;
+ }
+
+ /* Enable store and forward when accelerator is enabled */
+ if (0U !=
+ (config->txAccelerConfig & ((uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled)))
+ {
+ base->TFWR = ENET_TFWR_STRFWD_MASK;
+ }
+ if (0U != ((config->rxAccelerConfig &
+ ((uint32_t)kENET_RxAccelIpCheckEnabled | (uint32_t)kENET_RxAccelProtoCheckEnabled))))
+ {
+ base->RSFL = 0;
+ }
+
+/* Initializes the ring 0. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR = MEMORY_ConvertMemoryMapAddress((uintptr_t)bufferConfig->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR = MEMORY_ConvertMemoryMapAddress((uintptr_t)bufferConfig->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR = (uint32_t)(uintptr_t)bufferConfig->txBdStartAddrAlign;
+ base->RDSR = (uint32_t)(uintptr_t)bufferConfig->rxBdStartAddrAlign;
+#endif
+ base->MRBR = (uint32_t)bufferConfig->rxBuffSizeAlign;
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1)
+ {
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+
+ if (config->ringNum > 1U)
+ {
+ /* Initializes the ring 1. */
+ buffCfg++;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR1 = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR1 = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR1 = (uint32_t)(uintptr_t)buffCfg->txBdStartAddrAlign;
+ base->RDSR1 = (uint32_t)(uintptr_t)buffCfg->rxBdStartAddrAlign;
+#endif
+ base->MRBR1 = (uint32_t)buffCfg->rxBuffSizeAlign;
+ /* Enable the DMAC for ring 1 and with no rx classification set. */
+ base->DMACFG[0] = ENET_DMACFG_DMA_CLASS_EN_MASK;
+ }
+ if (config->ringNum > 2U)
+ {
+ /* Initializes the ring 2. */
+ buffCfg++;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR2 = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR2 = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR2 = (uint32_t)(uintptr_t)buffCfg->txBdStartAddrAlign;
+ base->RDSR2 = (uint32_t)(uintptr_t)buffCfg->rxBdStartAddrAlign;
+#endif
+ base->MRBR2 = (uint32_t)buffCfg->rxBuffSizeAlign;
+ /* Enable the DMAC for ring 2 and with no rx classification set. */
+ base->DMACFG[1] = ENET_DMACFG_DMA_CLASS_EN_MASK;
+ }
+
+ /* Defaulting the class/ring 1 and 2 are not enabled and the receive classification is disabled
+ * so we set the default transmit scheme with the round-robin mode. Beacuse the legacy bd mode
+ * only supports the round-robin mode. If the avb feature is required, just call the setup avb
+ * feature API. */
+ base->QOS |= ENET_QOS_TX_SCHEME(1);
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ /* Configures the Mac address. */
+ ENET_SetMacAddr(base, macAddr);
+
+ /* Initialize the SMI if uninitialized. */
+ if (!ENET_GetSMI(base))
+ {
+ ENET_SetSMI(base, srcClock_Hz,
+ ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlSMIPreambleDisable)) ? true : false));
+ }
+
+/* Enables Ethernet interrupt, enables the interrupt coalsecing if it is required. */
+#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE
+ uint8_t queue = 0;
+
+ if (NULL != config->intCoalesceCfg)
+ {
+ uint32_t intMask = (ENET_EIMR_TXB_MASK | ENET_EIMR_RXB_MASK);
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+ if (FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) > 1)
+ {
+ intMask |= ENET_EIMR_TXB2_MASK | ENET_EIMR_RXB2_MASK | ENET_EIMR_TXB1_MASK | ENET_EIMR_RXB1_MASK;
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ /* Clear all buffer interrupts. */
+ base->EIMR &= ~intMask;
+
+ /* Set the interrupt coalescence. */
+ for (queue = 0; queue < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base); queue++)
+ {
+ base->TXIC[queue] = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[queue]) |
+ config->intCoalesceCfg->txCoalesceTimeCount[queue] | ENET_TXIC_ICCS_MASK |
+ ENET_TXIC_ICEN_MASK;
+ base->RXIC[queue] = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[queue]) |
+ config->intCoalesceCfg->rxCoalesceTimeCount[queue] | ENET_RXIC_ICCS_MASK |
+ ENET_RXIC_ICEN_MASK;
+ }
+ }
+#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */
+ ENET_EnableInterrupts(base, config->interrupt);
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Sets the 1588 enhanced feature. */
+ ecr |= ENET_ECR_EN1588_MASK;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Enables Ethernet module after all configuration except the buffer descriptor active. */
+ ecr |= ENET_ECR_ETHEREN_MASK | ENET_ECR_DBSWP_MASK;
+ base->ECR = ecr;
+}
+
+static void ENET_SetTxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig)
+{
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+ uintptr_t txBuffer = 0;
+ uint32_t txBuffSizeAlign;
+ uint16_t txBdNumber;
+ uint8_t ringNum;
+ uint16_t count;
+
+ /* Check the input parameters. */
+ for (ringNum = 0; ringNum < config->ringNum; ringNum++)
+ {
+ if (buffCfg->txBdStartAddrAlign != NULL)
+ {
+ volatile enet_tx_bd_struct_t *curBuffDescrip = buffCfg->txBdStartAddrAlign;
+ txBuffSizeAlign = buffCfg->txBuffSizeAlign;
+ txBdNumber = buffCfg->txBdNumber;
+
+ if (buffCfg->txBufferAlign != NULL)
+ {
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ txBuffer = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->txBufferAlign, kMEMORY_Local2DMA);
+#else
+ txBuffer = (uintptr_t)buffCfg->txBufferAlign;
+#endif
+ assert((uint64_t)txBuffer + (uint64_t)txBdNumber * txBuffSizeAlign - 1U <= UINT32_MAX);
+ }
+
+ for (count = 0; count < txBdNumber; count++)
+ {
+ if (buffCfg->txBufferAlign != NULL)
+ {
+ /* Set data buffer address. */
+ curBuffDescrip->buffer = (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 == (txBdNumber - 1U))
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_WRAP_MASK;
+ }
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Enable transmit interrupt for store the transmit timestamp. */
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK;
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ /* Set the type of the frame when the credit-based scheme is used. */
+ curBuffDescrip->controlExtend1 |= (uint16_t)(ENET_BD_FTYPE(ringNum));
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Increase the index. */
+ curBuffDescrip++;
+ }
+ }
+ buffCfg++;
+ }
+}
+
+static void ENET_SetRxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig)
+{
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+ uint16_t rxBuffSizeAlign;
+ uint16_t rxBdNumber;
+ uintptr_t rxBuffer;
+ uint8_t ringNum;
+ uint16_t count;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint32_t mask = ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Check the input parameters. */
+ for (ringNum = 0; ringNum < config->ringNum; ringNum++)
+ {
+ assert(buffCfg->rxBuffSizeAlign >= ENET_RX_MIN_BUFFERSIZE);
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+#if FSL_FEATURE_ENET_QUEUE > 1
+ if (ringNum == 1U)
+ {
+ mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt);
+ }
+ else if (ringNum == 2U)
+ {
+ mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ if ((buffCfg->rxBdStartAddrAlign != NULL) && ((buffCfg->rxBufferAlign != NULL) || config->rxBuffAlloc != NULL))
+ {
+ volatile enet_rx_bd_struct_t *curBuffDescrip = buffCfg->rxBdStartAddrAlign;
+ rxBuffSizeAlign = buffCfg->rxBuffSizeAlign;
+ rxBdNumber = buffCfg->rxBdNumber;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ rxBuffer = MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->rxBufferAlign, kMEMORY_Local2DMA);
+#else
+ rxBuffer = (uintptr_t)buffCfg->rxBufferAlign;
+#endif
+ assert((uint64_t)rxBuffer + (uint64_t)rxBdNumber * rxBuffSizeAlign - 1U <= UINT32_MAX);
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (buffCfg->rxMaintainEnable)
+ {
+ /* Invalidate rx buffers before DMA transfer data into them. */
+ DCACHE_InvalidateByRange(rxBuffer, ((uint32_t)rxBdNumber * rxBuffSizeAlign));
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ for (count = 0; count < rxBdNumber; count++)
+ {
+ /* Set data buffer and the length. */
+ curBuffDescrip->length = 0;
+ if (config->rxBuffAlloc == NULL)
+ {
+ curBuffDescrip->buffer = (uint32_t)(rxBuffer + (uintptr_t)count * rxBuffSizeAlign);
+ /* Initializes the buffer descriptors with empty bit. */
+ curBuffDescrip->control = ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ }
+
+ /* Sets the last buffer descriptor with the wrap flag. */
+ if (count == (rxBdNumber - 1U))
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (0U != (config->interrupt & mask))
+ {
+ /* Enable receive interrupt. */
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_RX_INTERRUPT_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 = 0;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Increase the index. */
+ curBuffDescrip++;
+ }
+ }
+ buffCfg++;
+ }
+}
+
+/*!
+ * brief Allocates all Rx buffers in BDs.
+ */
+static status_t ENET_RxBufferAllocAll(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle->rxBuffAlloc != NULL);
+
+ volatile enet_rx_bd_struct_t *curBuffDescrip;
+ enet_rx_bd_ring_t *rxBdRing;
+ uintptr_t buffer;
+ uint16_t ringId;
+ uint16_t index;
+
+ /* Allocate memory for all empty buffers in buffer descriptor */
+ for (ringId = 0; ringId < handle->ringNum; ringId++)
+ {
+ assert(handle->rxBdRing[ringId].rxBdBase != NULL);
+
+ rxBdRing = &handle->rxBdRing[ringId];
+ curBuffDescrip = rxBdRing->rxBdBase;
+ index = 0;
+
+ do
+ {
+ buffer = (uintptr_t)(uint8_t *)handle->rxBuffAlloc(base, handle->userData, ringId);
+ if (buffer == 0U)
+ {
+ ENET_RxBufferFreeAll(base, handle);
+ return kStatus_ENET_InitMemoryFail;
+ }
+ assert((uint64_t)buffer + handle->rxBuffSizeAlign[ringId] - 1U <= UINT32_MAX);
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ /* Invalidate cache in case any unfinished cache operation occurs. */
+ DCACHE_InvalidateByRange(buffer, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ buffer = MEMORY_ConvertMemoryMapAddress(buffer, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ curBuffDescrip->buffer = (uint32_t)buffer;
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring. */
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + index;
+ } while (index != 0U);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Frees all Rx buffers in BDs.
+ */
+static void ENET_RxBufferFreeAll(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle->rxBuffFree != NULL);
+
+ uint16_t index;
+ enet_rx_bd_ring_t *rxBdRing;
+ volatile enet_rx_bd_struct_t *curBuffDescrip;
+ uintptr_t buffer;
+ uint16_t ringId;
+
+ for (ringId = 0; ringId < handle->ringNum; ringId++)
+ {
+ assert(handle->rxBdRing[ringId].rxBdBase != NULL);
+
+ rxBdRing = &handle->rxBdRing[ringId];
+ curBuffDescrip = rxBdRing->rxBdBase;
+ index = 0;
+
+ /* Free memory for all buffers in buffer descriptor */
+ do
+ {
+ if (curBuffDescrip->buffer != 0U)
+ {
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ buffer = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ buffer = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ handle->rxBuffFree(base, (void *)(uint8_t *)buffer, handle->userData, ringId);
+ curBuffDescrip->buffer = 0;
+ /* Clears status. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+
+ /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring. */
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + index;
+ } while (index != 0U);
+ }
+}
+
+/*!
+ * brief Activates frame reception for specified ring.
+ *
+ * This function is to active the enet read process for specified ring.
+ * note This must be called after the MAC configuration and
+ * state are ready. It must be called after the ENET_Init() and
+ * ENET_Ptp1588Configure(). This should be called when the ENET receive required.
+ *
+ * param base ENET peripheral base address.
+ * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ */
+static inline void ENET_ActiveReadRing(ENET_Type *base, uint8_t ringId)
+{
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ /* Ensure previous data update is completed with Data Synchronization Barrier before activing Rx BD. */
+ __DSB();
+
+ /* Actives the receive buffer descriptor. */
+ switch (ringId)
+ {
+ case kENET_Ring0:
+ base->RDAR = ENET_RDAR_RDAR_MASK;
+ break;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ case kENET_Ring1:
+ base->RDAR1 = ENET_RDAR1_RDAR_MASK;
+ break;
+ case kENET_Ring2:
+ base->RDAR2 = ENET_RDAR2_RDAR_MASK;
+ break;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Activates frame sending for specified ring.
+ * note This must be called after the MAC configuration and
+ * state are ready. It must be called after the ENET_Init() and
+ * this should be called when the ENET receive required.
+ *
+ * param base ENET peripheral base address.
+ * param ringId The descriptor ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ *
+ */
+static void ENET_ActiveSendRing(ENET_Type *base, uint8_t ringId)
+{
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ volatile uint32_t *txDesActive = NULL;
+
+ /* Ensure previous data update is completed with Data Synchronization Barrier before activing Tx BD. */
+ __DSB();
+
+ switch (ringId)
+ {
+ case kENET_Ring0:
+ txDesActive = &(base->TDAR);
+ break;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ case kENET_Ring1:
+ txDesActive = &(base->TDAR1);
+ break;
+ case kENET_Ring2:
+ txDesActive = &(base->TDAR2);
+ break;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ default:
+ txDesActive = &(base->TDAR);
+ break;
+ }
+
+#if defined(FSL_FEATURE_ENET_HAS_ERRATA_007885) && FSL_FEATURE_ENET_HAS_ERRATA_007885
+ /* There is a TDAR race condition for mutliQ when the software sets TDAR
+ * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
+ * This will cause the udma_tx and udma_tx_arbiter state machines to hang.
+ * Software workaround: introduces a delay by reading the relevant ENET_TDARn_TDAR 4 times
+ */
+ for (uint8_t i = 0; i < 4U; i++)
+ {
+ if (*txDesActive == 0U)
+ {
+ break;
+ }
+ }
+#endif
+
+ /* Write to active tx descriptor */
+ *txDesActive = 0;
+}
+
+/*!
+ * brief Sets the ENET MII speed and duplex.
+ *
+ * This API is provided to dynamically change the speed and dulpex for MAC.
+ *
+ * param base ENET peripheral base address.
+ * param speed The speed of the RMII mode.
+ * param duplex The duplex of the RMII mode.
+ */
+void ENET_SetMII(ENET_Type *base, enet_mii_speed_t speed, enet_mii_duplex_t duplex)
+{
+ uint32_t rcr = base->RCR;
+ uint32_t tcr = base->TCR;
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1)
+ {
+ uint32_t ecr = base->ECR;
+
+ if (kENET_MiiSpeed1000M == speed)
+ {
+ assert(duplex == kENET_MiiFullDuplex);
+ ecr |= ENET_ECR_SPEED_MASK;
+ }
+ else
+ {
+ ecr &= ~ENET_ECR_SPEED_MASK;
+ }
+
+ base->ECR = ecr;
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ /* Sets speed mode. */
+ if (kENET_MiiSpeed10M == speed)
+ {
+ rcr |= ENET_RCR_RMII_10T_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_RMII_10T_MASK;
+ }
+ /* Set duplex mode. */
+ if (duplex == kENET_MiiHalfDuplex)
+ {
+ rcr |= ENET_RCR_DRT_MASK;
+ tcr &= ~ENET_TCR_FDEN_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_DRT_MASK;
+ tcr |= ENET_TCR_FDEN_MASK;
+ }
+
+ base->RCR = rcr;
+ base->TCR = tcr;
+}
+
+/*!
+ * brief Sets the ENET module Mac address.
+ *
+ * param base ENET peripheral base address.
+ * param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_SetMacAddr(ENET_Type *base, uint8_t *macAddr)
+{
+ uint32_t address;
+
+ /* Set physical address lower register. */
+ address = (uint32_t)(((uint32_t)macAddr[0] << 24U) | ((uint32_t)macAddr[1] << 16U) | ((uint32_t)macAddr[2] << 8U) |
+ (uint32_t)macAddr[3]);
+ base->PALR = address;
+ /* Set physical address high register. */
+ address = (uint32_t)(((uint32_t)macAddr[4] << 8U) | ((uint32_t)macAddr[5]));
+ base->PAUR = address << ENET_PAUR_PADDR2_SHIFT;
+}
+
+/*!
+ * brief Gets the ENET module Mac address.
+ *
+ * param base ENET peripheral base address.
+ * param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_GetMacAddr(ENET_Type *base, uint8_t *macAddr)
+{
+ assert(macAddr != NULL);
+
+ uint32_t address;
+
+ /* Get from physical address lower register. */
+ address = base->PALR;
+ macAddr[0] = 0xFFU & (uint8_t)(address >> 24U);
+ macAddr[1] = 0xFFU & (uint8_t)(address >> 16U);
+ macAddr[2] = 0xFFU & (uint8_t)(address >> 8U);
+ macAddr[3] = 0xFFU & (uint8_t)address;
+
+ /* Get from physical address high register. */
+ address = (base->PAUR & ENET_PAUR_PADDR2_MASK) >> ENET_PAUR_PADDR2_SHIFT;
+ macAddr[4] = 0xFFU & (uint8_t)(address >> 8U);
+ macAddr[5] = 0xFFU & (uint8_t)address;
+}
+
+/*!
+ * brief Sets the ENET SMI(serial management interface)- MII management interface.
+ *
+ * param base ENET peripheral base address.
+ * param srcClock_Hz This is the ENET module clock frequency. See clock distribution.
+ * param isPreambleDisabled The preamble disable flag.
+ * - true Enables the preamble.
+ * - false Disables the preamble.
+ */
+void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled)
+{
+ /* Due to bits limitation of SPEED and HOLDTIME, srcClock_Hz must ensure MDC <= 2.5M and holdtime >= 10ns. */
+ assert((srcClock_Hz != 0U) && (srcClock_Hz <= 320000000U));
+
+ uint32_t clkCycle = 0;
+ uint32_t speed = 0;
+ uint32_t mscr = 0;
+
+ /* Use (param + N - 1) / N to increase accuracy with rounding. */
+ /* Calculate the MII speed which controls the frequency of the MDC. */
+ speed = (srcClock_Hz + 2U * ENET_MDC_FREQUENCY - 1U) / (2U * ENET_MDC_FREQUENCY) - 1U;
+ /* Calculate the hold time on the MDIO output. */
+ clkCycle = (10U + ENET_NANOSECOND_ONE_SECOND / srcClock_Hz - 1U) / (ENET_NANOSECOND_ONE_SECOND / srcClock_Hz) - 1U;
+ /* Build the configuration for MDC/MDIO control. */
+ mscr =
+ ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0U);
+ base->MSCR = mscr;
+}
+
+static status_t ENET_MDIOWaitTransferOver(ENET_Type *base)
+{
+ status_t result = kStatus_Success;
+#ifdef ENET_MDIO_TIMEOUT_COUNT
+ uint32_t counter;
+#endif
+
+ /* Wait for MDIO access to complete. */
+#ifdef ENET_MDIO_TIMEOUT_COUNT
+ for (counter = ENET_MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
+ {
+ if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK))
+ {
+ break;
+ }
+ }
+ /* Check for timeout. */
+ if (0U == counter)
+ {
+ result = kStatus_Timeout;
+ }
+#else
+ while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK))
+ {
+ }
+#endif
+ return result;
+}
+
+/*!
+ * @brief MDIO write with IEEE802.3 Clause 22 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address.
+ * @param regAddr The PHY register. Range from 0 ~ 31.
+ * @param data The data written to PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOWrite(ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
+{
+ status_t result = kStatus_Success;
+
+ /* Clear the MDIO access complete event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ /* Starts MDIO write command. */
+ ENET_StartSMIWrite(base, phyAddr, regAddr, kENET_MiiWriteValidFrame, data);
+
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* Clear the MDIO access complete event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ return result;
+}
+
+/*!
+ * @brief MDIO read with IEEE802.3 Clause 22 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address.
+ * @param regAddr The PHY register. Range from 0 ~ 31.
+ * @param pData The data read from PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIORead(ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
+{
+ assert(pData != NULL);
+
+ status_t result = kStatus_Success;
+
+ /* Clear the MDIO access complete event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ /* Starts a MDIO read command operation. */
+ ENET_StartSMIRead(base, phyAddr, regAddr, kENET_MiiReadValidFrame);
+
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* Get received data. */
+ *pData = (uint16_t)ENET_ReadSMIData(base);
+
+ /* Clear the MDIO access complete event. */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ return result;
+}
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
+/*!
+ * @brief MDIO write with IEEE802.3 Clause 45 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param regAddr The PHY register address.
+ * @param data The data written to PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOC45Write(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t data)
+{
+ status_t result = kStatus_Success;
+
+ /* Write the register address */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ ENET_StartExtC45SMIWriteReg(base, portAddr, devAddr, regAddr);
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ /* Write data to the specified register address */
+ ENET_StartExtC45SMIWriteData(base, portAddr, devAddr, data);
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+
+ return result;
+}
+/*!
+ * @brief MDIO read with IEEE802.3 Clause 45 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param regAddr The PHY register address.
+ * @param pData The data read from PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOC45Read(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t *pData)
+{
+ assert(pData != NULL);
+
+ status_t result = kStatus_Success;
+
+ /* Write the register address */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ ENET_StartExtC45SMIWriteReg(base, portAddr, devAddr, regAddr);
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* Read data from the specified register address */
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ ENET_StartExtC45SMIReadData(base, portAddr, devAddr);
+ result = ENET_MDIOWaitTransferOver(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ *pData = (uint16_t)ENET_ReadSMIData(base);
+ return result;
+}
+#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */
+
+static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max)
+{
+ assert(index < max);
+
+ /* Increase the index. */
+ index++;
+ if (index >= max)
+ {
+ index = 0;
+ }
+ return index;
+}
+
+static inline bool ENET_TxDirtyRingAvailable(enet_tx_dirty_ring_t *txDirtyRing)
+{
+ return !txDirtyRing->isFull;
+}
+
+/*!
+ * brief Gets the error statistics of a received frame for ENET specified ring.
+ *
+ * This API must be called after the ENET_GetRxFrameSize and before the ENET_ReadFrame().
+ * If the ENET_GetRxFrameSize returns kStatus_ENET_RxFrameError,
+ * the ENET_GetRxErrBeforeReadFrame can be used to get the exact error statistics.
+ * This is an example.
+ * code
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (status == kStatus_ENET_RxFrameError)
+ * {
+ * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic, 0);
+ * ENET_ReadFrame(EXAMPLE_ENET, &g_handle, NULL, 0);
+ * }
+ * endcode
+ * param handle The ENET handler structure pointer. This is the same handler pointer used in the ENET_Init.
+ * param eErrorStatic The error statistics structure pointer.
+ * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ */
+void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(eErrorStatic != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ uint16_t control = 0;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ volatile enet_rx_bd_struct_t *cmpBuffDescrip = curBuffDescrip;
+
+ do
+ {
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ control = curBuffDescrip->control;
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK))
+ {
+ /* The receive truncate error. */
+ eErrorStatic->statsRxTruncateErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK))
+ {
+ /* The receive over run error. */
+ eErrorStatic->statsRxOverRunErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK))
+ {
+ /* The receive length violation error. */
+ eErrorStatic->statsRxLenGreaterErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK))
+ {
+ /* The receive alignment error. */
+ eErrorStatic->statsRxAlignErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_CRC_MASK))
+ {
+ /* The receive CRC error. */
+ eErrorStatic->statsRxFcsErr++;
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint16_t controlExt = curBuffDescrip->controlExtend1;
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_MACERR_MASK))
+ {
+ /* The MAC error. */
+ eErrorStatic->statsRxMacErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK))
+ {
+ /* The PHY error. */
+ eErrorStatic->statsRxPhyErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK))
+ {
+ /* The receive collision error. */
+ eErrorStatic->statsRxCollisionErr++;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ break;
+ }
+
+ /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring buffer. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ curBuffDescrip = rxBdRing->rxBdBase;
+ }
+ else
+ {
+ curBuffDescrip++;
+ }
+
+ } while (curBuffDescrip != cmpBuffDescrip);
+}
+
+/*!
+ * brief Gets statistical data in transfer.
+ *
+ * param base ENET peripheral base address.
+ * param statistics The statistics structure pointer.
+ */
+void ENET_GetStatistics(ENET_Type *base, enet_transfer_stats_t *statistics)
+{
+ /* Rx statistics */
+ statistics->statsRxFrameCount = base->RMON_R_PACKETS;
+ statistics->statsRxFrameOk = base->IEEE_R_FRAME_OK;
+ statistics->statsRxCrcErr = base->IEEE_R_CRC;
+ statistics->statsRxAlignErr = base->IEEE_R_ALIGN;
+ statistics->statsRxDropInvalidSFD = base->IEEE_R_DROP;
+ statistics->statsRxFifoOverflowErr = base->IEEE_R_MACERR;
+
+ /* Tx statistics */
+ statistics->statsTxFrameCount = base->RMON_T_PACKETS;
+ statistics->statsTxFrameOk = base->IEEE_T_FRAME_OK;
+ statistics->statsTxCrcAlignErr = base->RMON_T_CRC_ALIGN;
+ statistics->statsTxFifoUnderRunErr = base->IEEE_T_MACERR;
+}
+
+/*!
+ * brief Gets the size of the read frame for specified ring.
+ *
+ * This function gets a received frame size from the ENET buffer descriptors.
+ * note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS.
+ * After calling ENET_GetRxFrameSize, ENET_ReadFrame() should be called to receive frame and update the BD
+ * if the result is not "kStatus_ENET_RxFrameEmpty".
+ *
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param length The length of the valid frame received.
+ * param ringId The ring index or ring number.
+ * retval kStatus_ENET_RxFrameEmpty No frame received. Should not call ENET_ReadFrame to read frame.
+ * retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrame should be called with NULL data
+ * and NULL length to update the receive buffers.
+ * retval kStatus_Success Receive a frame Successfully then the ENET_ReadFrame
+ * should be called with the right data buffer and the captured data length input.
+ */
+status_t ENET_GetRxFrameSize(enet_handle_t *handle, uint32_t *length, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(length != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ /* Reset the length to zero. */
+ *length = 0;
+
+ uint16_t validLastMask = ENET_BUFFDESCRIPTOR_RX_LAST_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uint16_t index = rxBdRing->rxGenIdx;
+ bool isReturn = false;
+ status_t result = kStatus_Success;
+
+ /* Check the current buffer descriptor's empty flag. If empty means there is no frame received. */
+ /* If this buffer descriptor is owned by application, return empty. Only need to check the first BD's owner if one
+ * frame in mutiple BDs. */
+ if (0U != (curBuffDescrip->control & (ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK | ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)))
+ {
+ isReturn = true;
+ result = kStatus_ENET_RxFrameEmpty;
+ }
+ else
+ {
+ do
+ {
+ /* Add check for abnormal case. */
+ if (curBuffDescrip->length == 0U)
+ {
+ isReturn = true;
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+
+ /* Find the last buffer descriptor. */
+ if ((curBuffDescrip->control & validLastMask) == ENET_BUFFDESCRIPTOR_RX_LAST_MASK)
+ {
+ isReturn = true;
+ /* The last buffer descriptor in the frame check the status of the received frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (0U != (curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* FCS is removed by MAC. */
+ *length = curBuffDescrip->length;
+ break;
+ }
+ /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + index;
+ } while (index != rxBdRing->rxGenIdx);
+ }
+
+ if (isReturn == false)
+ {
+ /* The frame is on processing - set to empty status to make application to receive it next time. */
+ result = kStatus_ENET_RxFrameEmpty;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Reads a frame from the ENET device.
+ * This function reads a frame (both the data and the length) from the ENET buffer descriptors.
+ * User can get timestamp through ts pointer if the ts is not NULL.
+ * note It doesn't store the timestamp in the receive timestamp queue.
+ * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer.
+ * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer
+ * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time
+ * consumption.
+ * This is an example:
+ * code
+ * uint32_t length;
+ * enet_handle_t g_handle;
+ * Comments: Get the received frame size firstly.
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (length != 0)
+ * {
+ * Comments: Allocate memory here with the size of "length"
+ * uint8_t *data = memory allocate interface;
+ * if (!data)
+ * {
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * Comments: Add the console warning log.
+ * }
+ * else
+ * {
+ * status = ENET_ReadFrame(ENET, &g_handle, data, length, 0, NULL);
+ * Comments: Call stack input API to deliver the data to stack
+ * }
+ * }
+ * else if (status == kStatus_ENET_RxFrameError)
+ * {
+ * Comments: Update the received buffer when a error frame is received.
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * }
+ * endcode
+ * param base ENET peripheral base address.
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to store the frame which memory size should be at least "length".
+ * param length The size of the data buffer which is still the length of the received frame.
+ * param ringId The ring index or ring number.
+ * param ts The timestamp address to store received timestamp.
+ * return The execute status, successful or failure.
+ */
+status_t ENET_ReadFrame(
+ ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t ringId, uint32_t *ts)
+{
+ assert(handle != NULL);
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ uint32_t len = 0;
+ uint32_t offset = 0;
+ uint16_t control;
+ bool isLastBuff = false;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uint16_t index = rxBdRing->rxGenIdx;
+ status_t result = kStatus_Success;
+ uintptr_t address;
+ uintptr_t dest;
+
+ /* For data-NULL input, only update the buffer descriptor. */
+ if (data == NULL)
+ {
+ do
+ {
+ /* Update the control flag. */
+ control = curBuffDescrip->control;
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+
+ /* Find the last buffer descriptor for the frame. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ break;
+ }
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ } while (index != rxBdRing->rxGenIdx);
+ }
+ else
+ {
+ while (!isLastBuff)
+ {
+/* A frame on one buffer or several receive buffers are both considered. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ /* Add the cache invalidate maintain. */
+ DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ dest = (uintptr_t)data + offset;
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* This is a valid frame. */
+ isLastBuff = true;
+ if (length == curBuffDescrip->length)
+ {
+ /* Copy the frame to user's buffer without FCS. */
+ len = curBuffDescrip->length - offset;
+ (void)memcpy((void *)(uint8_t *)dest, (void *)(uint8_t *)address, len);
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Get the timestamp if the ts isn't NULL. */
+ if (ts != NULL)
+ {
+ *ts = curBuffDescrip->timestamp;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ break;
+ }
+ else
+ {
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ }
+ }
+ else
+ {
+ /* Store a frame on several buffer descriptors. */
+ isLastBuff = false;
+ /* Length check. */
+ if (offset >= length)
+ {
+ result = kStatus_ENET_RxFrameFail;
+ break;
+ }
+ (void)memcpy((void *)(uint8_t *)dest, (void *)(uint8_t *)address, handle->rxBuffSizeAlign[ringId]);
+ offset += handle->rxBuffSizeAlign[ringId];
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ }
+
+ /* Get the current buffer descriptor. */
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ }
+ }
+
+ return result;
+}
+
+static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+
+ /* Clears status. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase current buffer descriptor to the next one. */
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+
+ ENET_ActiveReadRing(base, ringId);
+}
+
+/*!
+ * brief Transmits an ENET frame for specified ring.
+ * note The CRC is automatically appended to the data. Input the data to send without the CRC.
+ * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer
+ * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time
+ * consumption.
+ *
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to send.
+ * param length The length of the data to send.
+ * param ringId The ring index or ring number.
+ * param tsFlag Timestamp enable flag.
+ * param context Used by user to handle some events after transmit over.
+ * retval kStatus_Success Send frame succeed.
+ * retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ * The waiting mechanism is recommended to be added after each call return with
+ * kStatus_ENET_TxFrameBusy.
+ */
+status_t ENET_SendFrame(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context)
+{
+ assert(handle != NULL);
+ assert(data != NULL);
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t len = 0;
+ uint32_t sizeleft = 0;
+ uintptr_t address;
+ status_t result = kStatus_Success;
+ uintptr_t src;
+ uint32_t configVal;
+ bool isReturn = false;
+ uint32_t primask;
+
+ /* Check the frame length. */
+ if (length > ENET_FRAME_TX_LEN_LIMITATION(base))
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ else
+ {
+ /* Check if the transmit buffer is ready. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if ((handle->txReclaimEnable[ringId]) && !ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ /* One transmit buffer is enough for one frame. */
+ if (handle->txBuffSizeAlign[ringId] >= length)
+ {
+ /* Copy data to the buffer for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ (void)memcpy((void *)(uint8_t *)address, (const void *)data, length);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ DCACHE_CleanByRange(address, length);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ /* Set data length. */
+ curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Increase the buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ /* Add context to frame info ring */
+ if (handle->txReclaimEnable[ringId])
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSendRing(base, ringId);
+ }
+ else
+ {
+ /* One frame requires more than one transmit buffers. */
+ do
+ {
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Update the size left to be transmit. */
+ sizeleft = length - len;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ src = (uintptr_t)data + len;
+
+ /* Increase the current software index of BD */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ if (sizeleft > handle->txBuffSizeAlign[ringId])
+ {
+ /* Data copy. */
+ (void)memcpy((void *)(uint8_t *)address, (void *)(uint8_t *)src,
+ handle->txBuffSizeAlign[ringId]);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ /* Add the cache clean maintain. */
+ DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ /* Data length update. */
+ curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
+ len += handle->txBuffSizeAlign[ringId];
+ /* Sets the control flag. */
+ configVal = (uint32_t)curBuffDescrip->control;
+ configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+ configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ curBuffDescrip->control = (uint16_t)configVal;
+
+ if (handle->txReclaimEnable[ringId])
+ {
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor*/
+ ENET_ActiveSendRing(base, ringId);
+ }
+ else
+ {
+ (void)memcpy((void *)(uint8_t *)address, (void *)(uint8_t *)src, sizeleft);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ /* Add the cache clean maintain. */
+ DCACHE_CleanByRange(address, sizeleft);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ curBuffDescrip->length = (uint16_t)sizeleft;
+ /* Set Last buffer wrap flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+
+ if (handle->txReclaimEnable[ringId])
+ {
+ /* Add context to frame info ring */
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSendRing(base, ringId);
+ isReturn = true;
+ break;
+ }
+ /* Update the buffer descriptor address. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * brief Enable or disable tx descriptors reclaim mechanism.
+ * note This function must be called when no pending send frame action.
+ * Set enable if you want to reclaim context or timestamp in interrupt.
+ *
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param isEnable Enable or disable flag.
+ * param ringId The ring index or ring number.
+ * retval kStatus_Success Succeed to enable/disable Tx reclaim.
+ * retval kStatus_Fail Fail to enable/disable Tx reclaim.
+ */
+status_t ENET_SetTxReclaim(enet_handle_t *handle, bool isEnable, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+
+ status_t result = kStatus_Success;
+
+ /* If tx dirty ring is empty, can set this flag and reset txConsumIdx */
+ if ((txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) && ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ if (isEnable)
+ {
+ handle->txReclaimEnable[ringId] = true;
+ txBdRing->txConsumIdx = txBdRing->txGenIdx;
+ }
+ else
+ {
+ handle->txReclaimEnable[ringId] = false;
+ }
+ }
+ else
+ {
+ result = kStatus_Fail;
+ }
+ return result;
+}
+
+/*!
+ * brief Reclaim tx descriptors.
+ * This function is used to update the tx descriptor status and
+ * store the tx timestamp when the 1588 feature is enabled.
+ * This is called by the transmit interupt IRQ handler after the
+ * complete of a frame transmission.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param ringId The ring index or ring number.
+ */
+void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId)
+{
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx;
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t primask;
+
+ /* Need to update the first index for transmit buffer free. */
+ while ((0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) && (txBdRing->txDescUsed > 0U))
+ {
+ if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) != 0U)
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txConsumIdx;
+ txDirtyRing->txConsumIdx = ENET_IncreaseIndex(txDirtyRing->txConsumIdx, txDirtyRing->txRingLen);
+ txDirtyRing->isFull = false;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ txDirty->isTsAvail = false;
+ if ((curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK) != 0U)
+ {
+ enet_ptp_time_t *ts = &txDirty->timeStamp;
+ /* Get transmit time stamp second. */
+ txDirty->isTsAvail = true;
+ ts->second = handle->msTimerSecond;
+ ts->nanosecond = curBuffDescrip->timestamp;
+ }
+#endif
+ /* For tx buffer free or requeue for last descriptor.
+ * The tx interrupt callback should free/requeue the tx buffer. */
+ if (handle->callback != NULL)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, ringId, kENET_TxEvent, txDirty, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TxEvent, txDirty, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed--;
+ EnableGlobalIRQ(primask);
+
+ /* Update the index. */
+ txBdRing->txConsumIdx = ENET_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen);
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx;
+ }
+}
+
+/*!
+ * deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame.
+ */
+status_t ENET_GetRxBuffer(ENET_Type *base,
+ enet_handle_t *handle,
+ void **buffer,
+ uint32_t *length,
+ uint8_t ringId,
+ bool *isLastBuff,
+ uint32_t *ts)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+ assert(handle->rxBdRing[ringId].rxBdBase != NULL);
+ assert(handle->rxBuffAlloc == NULL);
+
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uintptr_t address;
+
+ /* Check if current rx BD is under usage by certain application */
+ /* Buffer owner flag, 1: owned by application, 0: owned by driver */
+ if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK) == 0U)
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK;
+ }
+ else
+ {
+ return kStatus_ENET_RxFrameFail;
+ }
+
+/* A frame on one buffer or several receive buffers are both considered. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ /* Add the cache invalidate maintain. */
+ DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ *buffer = (void *)(uint8_t *)address;
+ *length = curBuffDescrip->length;
+
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* This is a valid frame. */
+ *isLastBuff = true;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (ts != NULL)
+ {
+ *ts = curBuffDescrip->timestamp;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ }
+ else
+ {
+ *isLastBuff = false;
+ }
+
+ /* Increase current buffer descriptor to the next one. */
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+
+ return kStatus_Success;
+}
+
+/*!
+ * deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame.
+ */
+void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ enet_rx_bd_struct_t *ownBuffDescrip = (enet_rx_bd_struct_t *)rxBdRing->rxBdBase;
+ enet_rx_bd_struct_t *blockBuffDescrip = (enet_rx_bd_struct_t *)rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ enet_rx_bd_struct_t tempBuffDescrip;
+ uint16_t index = rxBdRing->rxGenIdx;
+ bool isReleaseBd = false;
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ buffer = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)buffer, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+ do
+ {
+ /* Find the BD for releasing, do nothing if it's not owned by application. */
+ if (buffer == (void *)(uint8_t *)ownBuffDescrip->buffer)
+ {
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK))
+ {
+ isReleaseBd = true;
+ break;
+ }
+ }
+
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ break;
+ }
+ ownBuffDescrip++;
+ } while (true);
+
+ if (isReleaseBd)
+ {
+ /* Find the first BD owned by application after rxBdCurrent, isReleaseBd is true so there's at least one BD is
+ * owned by application */
+ do
+ {
+ if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK))
+ {
+ break;
+ }
+ if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase;
+ }
+ else
+ {
+ blockBuffDescrip++;
+ }
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ } while (index != rxBdRing->rxGenIdx);
+
+ /* If the BD ready for releasing isn't the first BD owned by application after rxBdCurrent then exchange the two
+ * BDs */
+ if (blockBuffDescrip != ownBuffDescrip)
+ {
+ /* Exchange buffer descriptor content */
+ tempBuffDescrip = *ownBuffDescrip;
+ *ownBuffDescrip = *blockBuffDescrip;
+ *blockBuffDescrip = tempBuffDescrip;
+
+ /* Maintain the wrap flag */
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ ownBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK);
+ blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+ else if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ blockBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK);
+ ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ /* Clears status including the owner flag. */
+ blockBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ }
+ else
+ {
+ /* Clears status including the owner flag. */
+ ownBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ }
+
+ ENET_ActiveReadRing(base, ringId);
+ }
+}
+
+static inline status_t ENET_GetRxFrameErr(enet_rx_bd_struct_t *rxDesc, enet_rx_frame_error_t *rxFrameError)
+{
+ assert(rxDesc != NULL);
+ assert(rxFrameError != NULL);
+
+ status_t result = kStatus_Success;
+ uint16_t control = rxDesc->control;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint16_t controlExtend1 = rxDesc->controlExtend1;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ union _frame_error
+ {
+ uint32_t data;
+ enet_rx_frame_error_t frameError;
+ };
+ union _frame_error error;
+
+ (void)memset((void *)&error.frameError, 0, sizeof(enet_rx_frame_error_t));
+
+ /* The last buffer descriptor in the frame check the status of the received frame. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (0U != (controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ if (result != kStatus_Success)
+ {
+ error.data = control;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ error.data |= ((uint32_t)controlExtend1 << 16U);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ }
+
+ *rxFrameError = error.frameError;
+
+ return result;
+}
+
+/*!
+ * brief Receives one frame in specified BD ring with zero copy.
+ *
+ * This function will use the user-defined allocate and free callback. Every time application gets one frame through
+ * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application.
+ * note This function will drop current frame and update related BDs as available for DMA if new buffers allocating
+ * fails. Application must provide a memory pool including at least BD number + 1 buffers to make this function work
+ * normally. If user calls this function in Rx interrupt handler, be careful that this function makes Rx BD ready with
+ * allocating new buffer(normal) or updating current BD(out of memory). If there's always new Rx frame input, Rx
+ * interrupt will be triggered forever. Application need to disable Rx interrupt according to specific design in this
+ * case.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param rxFrame The received frame information structure provided by user.
+ * param ringId The ring index or ring number.
+ * retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer.
+ * retval kStatus_ENET_RxFrameEmpty There's no Rx frame in the BD.
+ * retval kStatus_ENET_RxFrameError There's issue in this receiving.
+ * retval kStatus_ENET_RxFrameDrop There's no new buffer memory for BD, drop this frame.
+ */
+status_t ENET_GetRxFrame(ENET_Type *base, enet_handle_t *handle, enet_rx_frame_struct_t *rxFrame, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+ assert(handle->rxBdRing[ringId].rxBdBase != NULL);
+ assert(rxFrame != NULL);
+ assert(rxFrame->rxBuffArray != NULL);
+
+ status_t result = kStatus_Success;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ bool isLastBuff = false;
+ uintptr_t newBuff = 0;
+ uint16_t buffLen = 0;
+ enet_buffer_struct_t *rxBuffer;
+ uintptr_t address;
+ uintptr_t buffer;
+ uint16_t index;
+
+ /* Check the current buffer descriptor's empty flag. If empty means there is no frame received. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK))
+ {
+ result = kStatus_ENET_RxFrameEmpty;
+ }
+ else
+ {
+ index = rxBdRing->rxGenIdx;
+ do
+ {
+ /* Find the last buffer descriptor. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* The last buffer descriptor stores the status of rhis received frame. */
+ result = ENET_GetRxFrameErr((enet_rx_bd_struct_t *)(uint32_t)curBuffDescrip, &rxFrame->rxFrameError);
+ break;
+ }
+
+ /* Can't find the last BD flag, no valid frame. */
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + index;
+ if (index == rxBdRing->rxGenIdx)
+ {
+ result = kStatus_ENET_RxFrameEmpty;
+ break;
+ }
+ } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK));
+ }
+
+ /* Drop the error frame. */
+ if (result == kStatus_ENET_RxFrameError)
+ {
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ do
+ {
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ isLastBuff = true;
+ }
+
+ /* Clears status including the owner flag. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase current buffer descriptor to the next one. */
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ } while (!isLastBuff);
+
+ ENET_ActiveReadRing(base, ringId);
+
+ return result;
+ }
+ else if (result != kStatus_Success)
+ {
+ return result;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ /* Get the valid frame */
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ index = 0;
+ do
+ {
+ newBuff = (uintptr_t)(uint8_t *)handle->rxBuffAlloc(base, handle->userData, ringId);
+ if (newBuff != 0U)
+ {
+ assert((uint64_t)newBuff + handle->rxBuffSizeAlign[ringId] - 1U <= UINT32_MAX);
+ rxBuffer = &rxFrame->rxBuffArray[index];
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress(curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ rxBuffer->buffer = (void *)(uint8_t *)address;
+
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* This is a valid frame. */
+ isLastBuff = true;
+ rxFrame->totLen = curBuffDescrip->length;
+ rxBuffer->length = curBuffDescrip->length - buffLen;
+
+ rxFrame->rxAttribute.promiscuous = false;
+ if (0U != (base->RCR & ENET_RCR_PROM_MASK))
+ {
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_MISS_MASK))
+ {
+ rxFrame->rxAttribute.promiscuous = true;
+ }
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ rxFrame->rxAttribute.timestamp = curBuffDescrip->timestamp;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ }
+ else
+ {
+ rxBuffer->length = curBuffDescrip->length;
+ buffLen += rxBuffer->length;
+ }
+
+ /* Give new buffer from application to BD */
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ buffer = MEMORY_ConvertMemoryMapAddress(newBuff, kMEMORY_Local2DMA);
+#else
+ buffer = newBuff;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ DCACHE_InvalidateByRange(buffer, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ curBuffDescrip->buffer = (uint32_t)buffer;
+
+ /* Clears status including the owner flag. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase Rx array index and the buffer descriptor address. */
+ index++;
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ }
+ else
+ {
+ /* Drop frame if there's no new buffer memory */
+
+ /* Free the incomplete frame buffers. */
+ while (index-- != 0U)
+ {
+ handle->rxBuffFree(base, &rxFrame->rxBuffArray[index].buffer, handle->userData, ringId);
+ }
+
+ /* Update left buffers as ready for next coming frame */
+ do
+ {
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ isLastBuff = true;
+ }
+
+ /* Clears status including the owner flag. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase current buffer descriptor to the next one. */
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ } while (!isLastBuff);
+
+ result = kStatus_ENET_RxFrameDrop;
+ break;
+ }
+ } while (!isLastBuff);
+
+ ENET_ActiveReadRing(base, ringId);
+
+ return result;
+}
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+static inline void ENET_PrepareTxDesc(volatile enet_tx_bd_struct_t *txDesc, enet_tx_config_struct_t *txConfig)
+{
+ uint16_t controlExtend1 = 0U;
+
+ /* For enable the timestamp. */
+ if (txConfig->intEnable)
+ {
+ controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK;
+ }
+ if (txConfig->tsEnable)
+ {
+ controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ if (txConfig->autoProtocolChecksum)
+ {
+ controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_PROTOCHECKSUM_MASK;
+ }
+ if (txConfig->autoIPChecksum)
+ {
+ controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_IPCHECKSUM_MASK;
+ }
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (txConfig->tltEnable)
+ {
+ controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_USETXLAUNCHTIME_MASK;
+ txDesc->txLaunchTimeLow |= txConfig->tltLow;
+ txDesc->txLaunchTimeHigh |= txConfig->tltHigh;
+ }
+ controlExtend1 |= (uint16_t)ENET_BD_FTYPE(txConfig->AVBFrameType);
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ txDesc->controlExtend1 = controlExtend1;
+}
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*!
+ * brief Sends one frame in specified BD ring with zero copy.
+ *
+ * This function supports scattered buffer transmit, user needs to provide the buffer array.
+ * note Tx reclaim should be enabled to ensure the Tx buffer ownership can be given back to
+ * application after Tx is over.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param txFrame The Tx frame structure.
+ * param ringId The ring index or ring number.
+ * retval kStatus_Success Succeed to send one frame.
+ * retval kStatus_ENET_TxFrameBusy The BD is not ready for Tx or the reclaim operation still not finishs.
+ * retval kStatus_ENET_TxFrameOverLen The Tx frame length is over max ethernet frame length.
+ */
+status_t ENET_StartTxFrame(ENET_Type *base, enet_handle_t *handle, enet_tx_frame_struct_t *txFrame, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+ assert(txFrame->txBuffArray != NULL);
+ assert(txFrame->txBuffNum != 0U);
+ assert(handle->txReclaimEnable[ringId]);
+
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ status_t result = kStatus_Success;
+ enet_buffer_struct_t *txBuff = txFrame->txBuffArray;
+ uint32_t txBuffNum = txFrame->txBuffNum;
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t frameLen = 0;
+ uint32_t idleDescNum = 0;
+ uint16_t index = 0;
+ uint32_t configVal;
+ uint32_t primask;
+ uintptr_t buffer;
+
+ /* Calculate frame length and Tx data buffer number. */
+ do
+ {
+ frameLen += txBuff->length;
+ txBuff++;
+ } while (--txBuffNum != 0U);
+ txBuffNum = txFrame->txBuffNum;
+
+ /* Check whether the available BD number is enough for Tx data buffer. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ index = txBdRing->txGenIdx;
+ do
+ {
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ break;
+ }
+
+ /* Idle BD number is enough */
+ if (++idleDescNum >= txBuffNum)
+ {
+ break;
+ }
+ index = ENET_IncreaseIndex(index, txBdRing->txRingLen);
+ curBuffDescrip = txBdRing->txBdBase + index;
+ } while (index != txBdRing->txGenIdx);
+
+ /* Check the frame length. */
+ if (frameLen > ENET_FRAME_TX_LEN_LIMITATION(base))
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ /* Return busy if idle BD is not enough. */
+ else if (txBuffNum > idleDescNum)
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if (!ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ txBuff = txFrame->txBuffArray;
+ do
+ {
+ assert(txBuff->buffer != NULL);
+ assert((uint64_t)(uintptr_t)(uint8_t *)txBuff->buffer + txBuff->length - 1U <= UINT32_MAX);
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ DCACHE_CleanByRange((uintptr_t)(uint8_t *)txBuff->buffer, txBuff->length);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ /* Map loacl memory address to DMA for special platform. */
+ buffer = MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)txBuff->buffer, kMEMORY_Local2DMA);
+#else
+ buffer = (uintptr_t)(uint8_t *)txBuff->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+ /* Set data buffer and length. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ curBuffDescrip->buffer = (uint32_t)buffer;
+ curBuffDescrip->length = txBuff->length;
+
+ /* Increase txBuffer array address and the buffer descriptor address. */
+ txBuff++;
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ ENET_PrepareTxDesc(curBuffDescrip, &txFrame->txConfig);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Linked buffers */
+ if (--txBuffNum != 0U)
+ {
+ /* Set BD ready flag and clean last BD flag. */
+ configVal = (uint32_t)curBuffDescrip->control;
+ configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+ configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ curBuffDescrip->control = (uint16_t)configVal;
+
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+ else
+ {
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Add context to frame info ring */
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = txFrame->context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+ /* Active Tx BD everytime to speed up transfer */
+ ENET_ActiveSendRing(base, ringId);
+ } while (txBuffNum != 0U);
+ }
+ return result;
+}
+
+/*!
+ * deprecated Do not use this function. It has been superseded by @ref ENET_StartTxFrame.
+ */
+status_t ENET_SendFrameZeroCopy(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context)
+{
+ assert(handle != NULL);
+ assert(data != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t len = 0;
+ uint32_t sizeleft = 0;
+ status_t result = kStatus_Success;
+ uintptr_t data_temp;
+ uint32_t configVal;
+ bool isReturn = false;
+ uint32_t primask;
+
+ /* Check the frame length. */
+ if (length > ENET_FRAME_TX_LEN_LIMITATION(base))
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ else
+ {
+ /* Check if the transmit buffer is ready. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if (handle->txReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ assert((uint64_t)(uintptr_t)data + length - 1U <= UINT32_MAX);
+ /* One transmit buffer is enough for one frame. */
+ if (handle->txBuffSizeAlign[ringId] >= length)
+ {
+ /* Copy data to the buffer for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uintptr_t)data, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ curBuffDescrip->buffer = (uint32_t)(uintptr_t)data;
+ /* Set data length. */
+ curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Increase the buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ /* Add context to frame info ring */
+ if (handle->txReclaimEnable[ringId])
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSendRing(base, ringId);
+ }
+ else
+ {
+ /* One frame requires more than one transmit buffers. */
+ do
+ {
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Update the size left to be transmit. */
+ sizeleft = length - len;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uintptr_t)data, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ data_temp = (uintptr_t)data + len;
+
+ /* Increase the current software index of BD */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ if (sizeleft > handle->txBuffSizeAlign[ringId])
+ {
+ /* Set buffer. */
+ curBuffDescrip->buffer = (uint32_t)data_temp;
+ /* Data length update. */
+ curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
+ len += handle->txBuffSizeAlign[ringId];
+ /* Sets the control flag. */
+ configVal = (uint32_t)curBuffDescrip->control;
+ configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+ configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ curBuffDescrip->control = (uint16_t)configVal;
+
+ if (handle->txReclaimEnable[ringId])
+ {
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor*/
+ ENET_ActiveSendRing(base, ringId);
+ }
+ else
+ {
+ curBuffDescrip->buffer = (uint32_t)data_temp;
+ curBuffDescrip->length = (uint16_t)sizeleft;
+ /* Set Last buffer wrap flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+
+ if (handle->txReclaimEnable[ringId])
+ {
+ /* Add context to frame info ring */
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ primask = DisableGlobalIRQ();
+ txBdRing->txDescUsed++;
+ EnableGlobalIRQ(primask);
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSendRing(base, ringId);
+ isReturn = true;
+ break;
+ }
+ /* Update buffer descriptor address. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+
+ } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * brief Adds the ENET device to a multicast group.
+ *
+ * param base ENET peripheral base address.
+ * param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_AddMulticastGroup(ENET_Type *base, uint8_t *address)
+{
+ assert(address != NULL);
+
+ enet_handle_t *handle = s_ENETHandle[ENET_GetInstance(base)];
+ uint32_t crc = 0xFFFFFFFFU;
+ uint32_t count1 = 0;
+ uint32_t count2 = 0;
+ uint32_t configVal = 0;
+
+ /* Calculates the CRC-32 polynomial on the multicast group address. */
+ for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++)
+ {
+ uint8_t c = address[count1];
+ for (count2 = 0; count2 < 0x08U; count2++)
+ {
+ if (0U != ((c ^ crc) & 1U))
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ crc ^= 0xEDB88320U;
+ }
+ else
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ }
+ }
+ }
+
+ crc = crc >> 26U;
+
+ handle->multicastCount[crc]++;
+
+ /* Enable a multicast group address. */
+ configVal = ((uint32_t)1U << (crc & 0x1FU));
+
+ if (0U != (crc & 0x20U))
+ {
+ base->GAUR |= configVal;
+ }
+ else
+ {
+ base->GALR |= configVal;
+ }
+}
+
+/*!
+ * brief Moves the ENET device from a multicast group.
+ *
+ * param base ENET peripheral base address.
+ * param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_LeaveMulticastGroup(ENET_Type *base, uint8_t *address)
+{
+ assert(address != NULL);
+
+ enet_handle_t *handle = s_ENETHandle[ENET_GetInstance(base)];
+ uint32_t crc = 0xFFFFFFFFU;
+ uint32_t count1 = 0;
+ uint32_t count2 = 0;
+ uint32_t configVal = 0;
+
+ /* Calculates the CRC-32 polynomial on the multicast group address. */
+ for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++)
+ {
+ uint8_t c = address[count1];
+ for (count2 = 0; count2 < 0x08U; count2++)
+ {
+ if (0U != ((c ^ crc) & 1U))
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ crc ^= 0xEDB88320U;
+ }
+ else
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ }
+ }
+ }
+
+ crc = crc >> 26U;
+
+ handle->multicastCount[crc]--;
+
+ /* Set the hash table if no collisions */
+ if (0U == handle->multicastCount[crc])
+ {
+ configVal = ~((uint32_t)1U << (crc & 0x1FU));
+
+ if (0U != (crc & 0x20U))
+ {
+ base->GAUR &= configVal;
+ }
+ else
+ {
+ base->GALR &= configVal;
+ }
+ }
+}
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * brief Gets the ENET transmit frame statistics after the data send for specified ring.
+ *
+ * This interface gets the error statistics of the transmit frame.
+ * Because the error information is reported by the uDMA after the data delivery, this interface
+ * should be called after the data transmit API. It is recommended to call this function on
+ * transmit interrupt handler. After calling the ENET_SendFrame, the
+ * transmit interrupt notifies the transmit completion.
+ *
+ * param handle The PTP handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param eErrorStatic The error statistics structure pointer.
+ * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ * return The execute status.
+ */
+status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(eErrorStatic != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ uint16_t control = 0;
+ uint16_t controlExt = 0;
+ status_t result = kStatus_Success;
+ bool isReturn = false;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+
+ do
+ {
+ /* Get the current dirty transmit buffer descriptor. */
+ control = handle->txBdDirtyStatic[ringId]->control;
+ controlExt = handle->txBdDirtyStatic[ringId]->controlExtend0;
+
+ /* Get the control status data, If the buffer descriptor has not been processed break out. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ isReturn = true;
+ break;
+ }
+
+ /* Increase the transmit dirty static pointer. */
+ if (0U != (handle->txBdDirtyStatic[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK))
+ {
+ handle->txBdDirtyStatic[ringId] = txBdRing->txBdBase;
+ }
+ else
+ {
+ handle->txBdDirtyStatic[ringId]++;
+ }
+
+ /* If the transmit buffer descriptor is ready and the last buffer descriptor, store packet statistic. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK))
+ {
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_ERR_MASK))
+ {
+ /* Transmit error. */
+ eErrorStatic->statsTxErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK))
+ {
+ /* Transmit excess collision error. */
+ eErrorStatic->statsTxExcessCollisionErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK))
+ {
+ /* Transmit late collision error. */
+ eErrorStatic->statsTxLateCollisionErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK))
+ {
+ /* Transmit under flow error. */
+ eErrorStatic->statsTxUnderFlowErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK))
+ {
+ /* Transmit over flow error. */
+ eErrorStatic->statsTxOverFlowErr++;
+ }
+ isReturn = true;
+ break;
+ }
+
+ } while (handle->txBdDirtyStatic[ringId] != curBuffDescrip);
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameFail;
+ }
+ return result;
+}
+
+void ENET_Ptp1588ConfigureHandler(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig)
+{
+ assert(handle != NULL);
+ assert(ptpConfig != NULL);
+ uint8_t count;
+
+ uint32_t mask = (uint32_t)kENET_TxBufferInterrupt;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ mask |= (uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxBuffer2Interrupt;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ for (count = 0; count < handle->ringNum; count++)
+ {
+ handle->txBdDirtyStatic[count] = handle->txBdRing[count].txBdBase;
+ }
+
+ /* Setting the receive and transmit state for transaction. */
+ handle->msTimerSecond = 0;
+
+#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID
+ uint32_t refClock;
+
+ /* The minimum time is defined by the greater of either six register clock cycles or six ptp clock cycles. */
+ if (handle->enetClock <= ptpConfig->ptp1588ClockSrc_Hz)
+ {
+ /* Caculate how many core cycles delay is needed. */
+ /* In the cases with this IP design issue, core clock = enetClock */
+ handle->tsDelayCount = 6U * handle->enetClock;
+ }
+ else
+ {
+ refClock = ptpConfig->ptp1588ClockSrc_Hz;
+
+ /* Caculate how many core cycles delay is needed. */
+ /* In the cases with this IP design issue, core clock = enetClock */
+ handle->tsDelayCount = 6U * ((handle->enetClock + refClock - 1U) / refClock);
+ }
+
+#endif
+
+ ENET_DisableInterrupts(base, mask);
+
+ /* Set the IRQ handler when the interrupt is enabled. */
+ ENET_SetTsISRHandler(base, ENET_TimeStampIRQHandler);
+ ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler);
+
+ /* Enables the time stamp interrupt and transmit frame interrupt to
+ * handle the time-stamp . */
+ ENET_EnableInterrupts(base, (ENET_TS_INTERRUPT | ENET_TX_INTERRUPT));
+}
+
+/*!
+ * brief Configures the ENET PTP IEEE 1588 feature with the basic configuration.
+ * The function sets the clock for PTP 1588 timer and enables
+ * time stamp interrupts and transmit interrupts for PTP 1588 features.
+ * This API should be called when the 1588 feature is enabled
+ * or the ENET_ENHANCEDBUFFERDESCRIPTOR_MODE is defined.
+ * ENET_Init should be called before calling this API.
+ *
+ * note The PTP 1588 time-stamp second increase though time-stamp interrupt handler
+ * and the transmit time-stamp store is done through transmit interrupt handler.
+ * As a result, the TS interrupt and TX interrupt are enabled when you call this API.
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param ptpConfig The ENET PTP1588 configuration.
+ */
+void ENET_Ptp1588Configure(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig)
+{
+ assert(handle != NULL);
+ assert(ptpConfig != NULL);
+
+ /* Start the 1588 timer. */
+ ENET_Ptp1588StartTimer(base, ptpConfig->ptp1588ClockSrc_Hz);
+
+ ENET_Ptp1588ConfigureHandler(base, handle, ptpConfig);
+}
+
+/*!
+ * brief Starts the ENET PTP 1588 Timer.
+ * This function is used to initialize the PTP timer. After the PTP starts,
+ * the PTP timer starts running.
+ *
+ * param base ENET peripheral base address.
+ * param ptpClkSrc The clock source of the PTP timer.
+ */
+void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc)
+{
+ /* Restart PTP 1588 timer, master clock. */
+ base->ATCR = ENET_ATCR_RESTART_MASK;
+
+ /* Initializes PTP 1588 timer. */
+ base->ATINC = ENET_ATINC_INC(ENET_NANOSECOND_ONE_SECOND / ptpClkSrc);
+ base->ATPER = ENET_NANOSECOND_ONE_SECOND;
+ /* Sets periodical event and the event signal output assertion and Actives PTP 1588 timer. */
+ base->ATCR = ENET_ATCR_PEREN_MASK | ENET_ATCR_PINPER_MASK | ENET_ATCR_EN_MASK;
+}
+
+/*!
+ * brief Gets the current ENET time from the PTP 1588 timer.
+ * Interrupts are not disabled.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ /* Get the current PTP time. */
+ ptpTime->second = handle->msTimerSecond;
+ /* Get the nanosecond from the master timer. */
+ base->ATCR |= ENET_ATCR_CAPTURE_MASK;
+
+#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID
+ /* The whole while loop includes at least three instructions(subs, nop and bne). */
+ uint32_t count = (handle->tsDelayCount + 3U - 1U) / 3U;
+
+ while (0U != (count--))
+ {
+ __NOP();
+ }
+#else
+ /* Wait for capture over */
+ while (0U != (base->ATCR & ENET_ATCR_CAPTURE_MASK))
+ {
+ }
+#endif
+
+ /* Get the captured time. */
+ ptpTime->nanosecond = base->ATVR;
+}
+
+/*!
+ * brief Gets the current ENET time from the PTP 1588 timer.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ assert(handle != NULL);
+ assert(ptpTime != NULL);
+ uint32_t primask;
+
+ /* Disables the interrupt. */
+ primask = DisableGlobalIRQ();
+
+ ENET_Ptp1588GetTimerNoIrqDisable(base, handle, ptpTime);
+
+ /* Get PTP timer wrap event. */
+ if (0U != (base->EIR & (uint32_t)kENET_TsTimerInterrupt))
+ {
+ ptpTime->second++;
+ }
+
+ /* Enables the interrupt. */
+ EnableGlobalIRQ(primask);
+}
+
+/*!
+ * brief Sets the ENET PTP 1588 timer to the assigned time.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The timer to be set to the PTP timer.
+ */
+void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ assert(handle != NULL);
+ assert(ptpTime != NULL);
+
+ uint32_t primask;
+
+ /* Disables the interrupt. */
+ primask = DisableGlobalIRQ();
+
+ /* Sets PTP timer. */
+ handle->msTimerSecond = ptpTime->second;
+ base->ATVR = ptpTime->nanosecond;
+
+ /* Enables the interrupt. */
+ EnableGlobalIRQ(primask);
+}
+
+/*!
+ * brief Adjusts the ENET PTP 1588 timer.
+ *
+ * param base ENET peripheral base address.
+ * param corrIncrease The correction increment value. This value is added every time the correction
+ * timer expires. A value less than the PTP timer frequency(1/ptpClkSrc) slows down the timer,
+ * a value greater than the 1/ptpClkSrc speeds up the timer.
+ * param corrPeriod The PTP timer correction counter wrap-around value. This defines after how
+ * many timer clock the correction counter should be reset and trigger a correction
+ * increment on the timer. A value of 0 disables the correction counter and no correction occurs.
+ */
+void ENET_Ptp1588AdjustTimer(ENET_Type *base, uint32_t corrIncrease, uint32_t corrPeriod)
+{
+ /* Set correction for PTP timer increment. */
+ base->ATINC = (base->ATINC & ~ENET_ATINC_INC_CORR_MASK) | (corrIncrease << ENET_ATINC_INC_CORR_SHIFT);
+ /* Set correction for PTP timer period. */
+ base->ATCOR = (base->ATCOR & ~ENET_ATCOR_COR_MASK) | (corrPeriod << ENET_ATCOR_COR_SHIFT);
+}
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+/*!
+ * brief Sets the ENET AVB feature.
+ *
+ * ENET AVB feature configuration, set the Receive classification match and transmit
+ * bandwidth. This API is called when the AVB feature is required.
+ *
+ * Note: The AVB frames transmission scheme is credit-based tx scheme and it's only supported
+ * with the Enhanced buffer descriptors. so the AVB configuration should only done with
+ * Enhanced buffer descriptor. so when the AVB feature is required, please make sure the
+ * the "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" is defined.
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config The ENET AVB feature configuration structure.
+ */
+void ENET_AVBConfigure(ENET_Type *base, enet_handle_t *handle, const enet_avb_config_t *config)
+{
+ assert(config != NULL);
+ assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+
+ uint8_t count = 0;
+
+ for (count = 0; count < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) - 1U; count++)
+ {
+ /* Set the AVB receive ring classification match when the match is not 0. */
+ if (0U != (config->rxClassifyMatch[count]))
+ {
+ base->RCMR[count] = ((uint32_t)config->rxClassifyMatch[count] & 0xFFFFU) | ENET_RCMR_MATCHEN_MASK;
+ }
+ /* Set the dma controller for the extended ring. */
+ base->DMACFG[count] |= ENET_DMACFG_IDLE_SLOPE(config->idleSlope[count]);
+ }
+
+ /* Shall use the credit-based scheme for avb. */
+ base->QOS &= ~ENET_QOS_TX_SCHEME_MASK;
+ base->QOS |= ENET_QOS_RX_FLUSH0_MASK;
+}
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * brief The transmit IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId)
+#else
+/*!
+ * brief The transmit IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle)
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+{
+ assert(handle != NULL);
+ uint32_t mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt;
+ uint32_t index = 0;
+ uint32_t irq;
+
+/* Check if the transmit interrupt happen. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ switch (ringId)
+ {
+ case kENET_Ring1:
+ mask = ((uint32_t)kENET_TxFrame1Interrupt | (uint32_t)kENET_TxBuffer1Interrupt);
+ break;
+ case kENET_Ring2:
+ mask = ((uint32_t)kENET_TxFrame2Interrupt | (uint32_t)kENET_TxBuffer2Interrupt);
+ break;
+ default:
+ mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt;
+ break;
+ }
+ index = ringId;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ while (0U != (mask & base->EIR))
+ {
+ irq = base->EIR;
+
+ /* Clear the transmit interrupt event. */
+ base->EIR = mask;
+
+ /* Callback Handler. */
+ if (handle->txReclaimEnable[index] && (0U != (irq & (uint32_t)kENET_TxFrameInterrupt)))
+ {
+ ENET_ReclaimTxDescriptor(base, handle, (uint8_t)index);
+ }
+ else
+ {
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, index, kENET_TxEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TxEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ }
+}
+
+/*!
+ * brief The receive IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+#if FSL_FEATURE_ENET_QUEUE > 1
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId)
+#else
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle)
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+{
+ assert(handle != NULL);
+ uint32_t mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt;
+
+/* Check if the receive interrupt happen. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ switch (ringId)
+ {
+ case kENET_Ring1:
+ mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt);
+ break;
+ case kENET_Ring2:
+ mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt);
+ break;
+ default:
+ mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt;
+ break;
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ while (0U != (mask & base->EIR))
+ {
+ /* Clear the transmit interrupt event. */
+ base->EIR = mask;
+
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, ringId, kENET_RxEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_RxEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+}
+
+/*!
+ * brief Some special IRQ handler including the error, mii, wakeup irq handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_ErrorIRQHandler(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t errMask = (uint32_t)kENET_BabrInterrupt | (uint32_t)kENET_BabtInterrupt | (uint32_t)kENET_EBusERInterrupt |
+ (uint32_t)kENET_PayloadRxInterrupt | (uint32_t)kENET_LateCollisionInterrupt |
+ (uint32_t)kENET_RetryLimitInterrupt | (uint32_t)kENET_UnderrunInterrupt;
+
+ /* Check if the error interrupt happen. */
+ if (0U != ((uint32_t)kENET_WakeupInterrupt & base->EIR))
+ {
+ /* Clear the wakeup interrupt. */
+ base->EIR = (uint32_t)kENET_WakeupInterrupt;
+ /* wake up and enter the normal mode. */
+ ENET_EnableSleepMode(base, false);
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_WakeUpEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_WakeUpEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ else
+ {
+ /* Clear the error interrupt event status. */
+ errMask &= base->EIR;
+ base->EIR = errMask;
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_ErrEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_ErrEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+}
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * brief The IEEE 1588 PTP time stamp interrupt handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ */
+void ENET_TimeStampIRQHandler(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Check if the PTP time stamp interrupt happen. */
+ if (0U != ((uint32_t)kENET_TsTimerInterrupt & base->EIR))
+ {
+ /* Clear the time stamp interrupt. */
+ base->EIR = (uint32_t)kENET_TsTimerInterrupt;
+
+ /* Increase timer second counter. */
+ handle->msTimerSecond++;
+
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_TimeStampEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TimeStampEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+
+ if (0U != ((uint32_t)kENET_TsAvailInterrupt & base->EIR))
+ {
+ /* Clear the time stamp interrupt. */
+ base->EIR = (uint32_t)kENET_TsAvailInterrupt;
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_TimeStampAvailEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TimeStampAvailEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+}
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*!
+ * brief the common IRQ handler for the tx/rx/error etc irq handler.
+ *
+ * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame0IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ event &= base->EIMR;
+ if (0U != (event & ((uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt)))
+ {
+ if (s_enetTxIsr[instance] != NULL)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 0);
+#else
+ s_enetTxIsr[instance](base, s_ENETHandle[instance]);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBufferInterrupt | (uint32_t)kENET_RxFrameInterrupt)))
+ {
+ if (s_enetRxIsr[instance] != NULL)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 0);
+#else
+ s_enetRxIsr[instance](base, s_ENETHandle[instance]);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+
+ if (0U != (event & ENET_TS_INTERRUPT) && (NULL != s_enetTsIsr[instance]))
+ {
+ s_enetTsIsr[instance](base, s_ENETHandle[instance]);
+ }
+ if (0U != (event & ENET_ERR_INTERRUPT) && (NULL != s_enetErrIsr[instance]))
+ {
+ s_enetErrIsr[instance](base, s_ENETHandle[instance]);
+ }
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 1).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame1IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ event &= base->EIMR;
+ if (0U != (event & ((uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame1Interrupt)))
+ {
+ if (s_enetTxIsr[instance] != NULL)
+ {
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 1);
+ }
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame1Interrupt)))
+ {
+ if (s_enetRxIsr[instance] != NULL)
+ {
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 1);
+ }
+ }
+}
+
+/*!
+ * brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 2).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame2IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ event &= base->EIMR;
+ if (0U != (event & ((uint32_t)kENET_TxBuffer2Interrupt | (uint32_t)kENET_TxFrame2Interrupt)))
+ {
+ if (s_enetTxIsr[instance] != NULL)
+ {
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 2);
+ }
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBuffer2Interrupt | (uint32_t)kENET_RxFrame2Interrupt)))
+ {
+ if (s_enetRxIsr[instance] != NULL)
+ {
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 2);
+ }
+ }
+}
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+void ENET_Ptp1588IRQHandler(ENET_Type *base)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* In some platforms, the 1588 event uses same irq with timestamp event. */
+ if ((s_enetTsIrqId[instance] == s_enet1588TimerIrqId[instance]) && (s_enetTsIrqId[instance] != NotAvail_IRQn))
+ {
+ uint32_t event = base->EIR;
+ event &= base->EIMR;
+ if (0U != (event & ((uint32_t)kENET_TsTimerInterrupt | (uint32_t)kENET_TsAvailInterrupt)))
+ {
+ if (s_enetTsIsr[instance] != NULL)
+ {
+ s_enetTsIsr[instance](base, s_ENETHandle[instance]);
+ }
+ }
+ }
+#endif
+
+ if (s_enet1588TimerIsr[instance] != NULL)
+ {
+ s_enet1588TimerIsr[instance](base, s_ENETHandle[instance]);
+ }
+}
+
+#if defined(ENET)
+#if FSL_FEATURE_ENET_QUEUE < 2
+void ENET_TxIRQHandler(ENET_Type *base);
+void ENET_TxIRQHandler(ENET_Type *base)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (s_enetTxIsr[instance] != NULL)
+ {
+ s_enetTxIsr[instance](base, s_ENETHandle[instance]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_RxIRQHandler(ENET_Type *base);
+void ENET_RxIRQHandler(ENET_Type *base)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (s_enetRxIsr[instance] != NULL)
+ {
+ s_enetRxIsr[instance](base, s_ENETHandle[instance]);
+ }
+}
+
+void ENET_ErrIRQHandler(ENET_Type *base);
+void ENET_ErrIRQHandler(ENET_Type *base)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (s_enetErrIsr[instance] != NULL)
+ {
+ s_enetErrIsr[instance](base, s_ENETHandle[instance]);
+ }
+}
+
+void ENET_Transmit_DriverIRQHandler(void);
+void ENET_Transmit_DriverIRQHandler(void)
+{
+ ENET_TxIRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_Receive_DriverIRQHandler(void);
+void ENET_Receive_DriverIRQHandler(void)
+{
+ ENET_RxIRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_Error_DriverIRQHandler(void);
+void ENET_Error_DriverIRQHandler(void)
+{
+ ENET_ErrIRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+
+void ENET_MAC0_Rx_Tx_Done1_DriverIRQHandler(void);
+void ENET_MAC0_Rx_Tx_Done1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET_MAC0_Rx_Tx_Done2_DriverIRQHandler(void);
+void ENET_MAC0_Rx_Tx_Done2_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+void ENET_DriverIRQHandler(void);
+void ENET_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_1588_Timer_DriverIRQHandler(void);
+void ENET_1588_Timer_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET */
+
+#if defined(ENET1)
+void ENET1_DriverIRQHandler(void);
+void ENET1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET1 */
+
+#if defined(ENET2)
+void ENET2_DriverIRQHandler(void);
+void ENET2_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET2);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET2_1588_Timer_DriverIRQHandler(void);
+void ENET2_1588_Timer_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(ENET2);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET2 */
+
+#if defined(CONNECTIVITY__ENET0)
+void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+#if FSL_FEATURE_ENET_QUEUE > 1
+void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET0_TIMER_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET0_TIMER_INT_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+#endif /* CONNECTIVITY__ENET0 */
+#if defined(CONNECTIVITY__ENET1)
+void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#if FSL_FEATURE_ENET_QUEUE > 1
+void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET1_TIMER_INT_DriverIRQHandler(void);
+void CONNECTIVITY_ENET1_TIMER_INT_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+#endif /* CONNECTIVITY__ENET1 */
+#if FSL_FEATURE_ENET_QUEUE > 1
+#if defined(ENET_1G)
+void ENET_1G_DriverIRQHandler(void);
+void ENET_1G_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET_1G);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET_1G_MAC0_Tx_Rx_1_DriverIRQHandler(void);
+void ENET_1G_MAC0_Tx_Rx_1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(ENET_1G);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET_1G_MAC0_Tx_Rx_2_DriverIRQHandler(void);
+void ENET_1G_MAC0_Tx_Rx_2_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(ENET_1G);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET_1G_1588_Timer_DriverIRQHandler(void);
+void ENET_1G_1588_Timer_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(ENET_1G);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET_1G */
+
+#if defined(ENET1)
+void ENET1_MAC0_Rx_Tx_Done1_DriverIRQHandler(void);
+void ENET1_MAC0_Rx_Tx_Done1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET1_MAC0_Rx_Tx_Done2_DriverIRQHandler(void);
+void ENET1_MAC0_Rx_Tx_Done2_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+void ENET1_1588_Timer_DriverIRQHandler(void);
+void ENET1_1588_Timer_DriverIRQHandler(void)
+{
+ ENET_Ptp1588IRQHandler(ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET1 */
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ \ No newline at end of file
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.h b/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.h
new file mode 100644
index 0000000000..2a155b9dbd
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/enet/fsl_enet.h
@@ -0,0 +1,2046 @@
+/*
+ * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_ENET_H_
+#define _FSL_ENET_H_
+
+#include "fsl_common.h"
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#include "fsl_memory.h"
+#endif
+/*!
+ * @addtogroup enet
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Defines the driver version. */
+#define FSL_ENET_DRIVER_VERSION (MAKE_VERSION(2, 6, 3))
+/*@}*/
+
+/*! @name ENET DESCRIPTOR QUEUE */
+/*@{*/
+/*! @brief Defines the queue number. */
+#ifndef FSL_FEATURE_ENET_QUEUE
+#define FSL_FEATURE_ENET_QUEUE 1 /* Singal queue for previous IP. */
+#endif
+/*@}*/
+
+/*! @name Control and status region bit masks of the receive buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK 0x8000U /*!< Empty bit mask. */
+#define ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK 0x4000U /*!< Software owner one mask. */
+#define ENET_BUFFDESCRIPTOR_RX_WRAP_MASK 0x2000U /*!< Next buffer descriptor is the start address. */
+#define ENET_BUFFDESCRIPTOR_RX_SOFTOWNER2_Mask 0x1000U /*!< Software owner two mask. */
+#define ENET_BUFFDESCRIPTOR_RX_LAST_MASK 0x0800U /*!< Last BD of the frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_MISS_MASK 0x0100U /*!< Received because of the promiscuous mode. */
+#define ENET_BUFFDESCRIPTOR_RX_BROADCAST_MASK 0x0080U /*!< Broadcast packet mask. */
+#define ENET_BUFFDESCRIPTOR_RX_MULTICAST_MASK 0x0040U /*!< Multicast packet mask. */
+#define ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK 0x0020U /*!< Length violation mask. */
+#define ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK 0x0010U /*!< Non-octet aligned frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_CRC_MASK 0x0004U /*!< CRC error mask. */
+#define ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK 0x0002U /*!< FIFO overrun mask. */
+#define ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK 0x0001U /*!< Frame is truncated mask. */
+/*@}*/
+
+/*! @name Control and status bit masks of the transmit buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_TX_READY_MASK 0x8000U /*!< Ready bit mask. */
+#define ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK 0x4000U /*!< Software owner one mask. */
+#define ENET_BUFFDESCRIPTOR_TX_WRAP_MASK 0x2000U /*!< Wrap buffer descriptor mask. */
+#define ENET_BUFFDESCRIPTOR_TX_SOFTOWENER2_MASK 0x1000U /*!< Software owner two mask. */
+#define ENET_BUFFDESCRIPTOR_TX_LAST_MASK 0x0800U /*!< Last BD of the frame mask. */
+#define ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK 0x0400U /*!< Transmit CRC mask. */
+/*@}*/
+
+/* Extended control regions for enhanced buffer descriptors. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*! @name First extended control region bit masks of the receive buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_RX_IPV4_MASK 0x0001U /*!< Ipv4 frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_IPV6_MASK 0x0002U /*!< Ipv6 frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_VLAN_MASK 0x0004U /*!< VLAN frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_PROTOCOLCHECKSUM_MASK 0x0010U /*!< Protocol checksum error mask. */
+#define ENET_BUFFDESCRIPTOR_RX_IPHEADCHECKSUM_MASK 0x0020U /*!< IP header checksum error mask. */
+/*@}*/
+
+/*! @name Second extended control region bit masks of the receive buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_RX_INTERRUPT_MASK 0x0080U /*!< BD interrupt mask. */
+#define ENET_BUFFDESCRIPTOR_RX_UNICAST_MASK 0x0100U /*!< Unicast frame mask. */
+#define ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK 0x0200U /*!< BD collision mask. */
+#define ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK 0x0400U /*!< PHY error mask. */
+#define ENET_BUFFDESCRIPTOR_RX_MACERR_MASK 0x8000U /*!< Mac error mask. */
+/*@}*/
+
+/*! @name First extended control region bit masks of the transmit buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_TX_ERR_MASK 0x8000U /*!< Transmit error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK 0x2000U /*!< Underflow error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK 0x1000U /*!< Excess collision error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_FRAMEERR_MASK 0x0800U /*!< Frame error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK 0x0400U /*!< Late collision error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK 0x0200U /*!< Overflow error mask. */
+#define ENET_BUFFDESCRIPTOR_TX_TIMESTAMPERR_MASK 0x0100U /*!< Timestamp error mask. */
+/*@}*/
+
+/*! @name Second extended control region bit masks of the transmit buffer descriptor. */
+/*@{*/
+#define ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK 0x4000U /*!< Interrupt mask. */
+#define ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK 0x2000U /*!< Timestamp flag mask. */
+#define ENET_BUFFDESCRIPTOR_TX_PROTOCHECKSUM_MASK 0x1000U /*!< Protocal checksum mask. */
+#define ENET_BUFFDESCRIPTOR_TX_IPCHECKSUM_MASK 0x0800U /*!< IP header checksum flag mask. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+#define ENET_BUFFDESCRIPTOR_TX_USETXLAUNCHTIME_MASK 0x0100U /*!< Use the transmit launch time. */
+#define ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_MASK 0x00F0U /*!< Frame type mask. */
+#define ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_SHIFT 4U /*!< Frame type shift. */
+#define ENET_BD_FTYPE(n) \
+ (((uint32_t)(n) << ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_SHIFT) & ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_MASK)
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+/*@}*/
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*! @brief Defines the receive error status flag mask. */
+#define ENET_BUFFDESCRIPTOR_RX_ERR_MASK \
+ (ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK | ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK | \
+ ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK | ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK | ENET_BUFFDESCRIPTOR_RX_CRC_MASK)
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+#define ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK \
+ (ENET_BUFFDESCRIPTOR_RX_MACERR_MASK | ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK | ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK)
+#endif
+
+/*! @name Defines some Ethernet parameters. */
+/*@{*/
+#define ENET_FRAME_MAX_FRAMELEN 1518U /*!< Default maximum Ethernet frame size without VLAN tag. */
+#define ENET_FRAME_VLAN_TAGLEN 4U /*!< Ethernet single VLAN tag size. */
+#define ENET_FRAME_CRC_LEN 4U /*!< CRC size in a frame. */
+#define ENET_FRAME_TX_LEN_LIMITATION(x) \
+ ((((x)->RCR & ENET_RCR_MAX_FL_MASK) >> ENET_RCR_MAX_FL_SHIFT) - ENET_FRAME_CRC_LEN)
+
+#define ENET_FIFO_MIN_RX_FULL 5U /*!< ENET minimum receive FIFO full. */
+#define ENET_RX_MIN_BUFFERSIZE 256U /*!< ENET minimum buffer size. */
+#define ENET_PHY_MAXADDRESS (ENET_MMFR_PA_MASK >> ENET_MMFR_PA_SHIFT) /*!< Maximum PHY address. */
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+#define ENET_TX_INTERRUPT \
+ ((uint32_t)kENET_TxFrameInterrupt | (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrame1Interrupt | \
+ (uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame2Interrupt | \
+ (uint32_t)kENET_TxBuffer2Interrupt) /*!< Enet Tx interrupt flag. */
+#define ENET_RX_INTERRUPT \
+ ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt | (uint32_t)kENET_RxFrame1Interrupt | \
+ (uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame2Interrupt | \
+ (uint32_t)kENET_RxBuffer2Interrupt) /*!< Enet Rx interrupt flag. */
+#else
+#define ENET_TX_INTERRUPT \
+ ((uint32_t)kENET_TxFrameInterrupt | (uint32_t)kENET_TxBufferInterrupt) /*!< Enet Tx interrupt flag. */
+#define ENET_RX_INTERRUPT \
+ ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt) /*!< Enet Rx interrupt flag. */
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+#define ENET_TS_INTERRUPT \
+ ((uint32_t)kENET_TsTimerInterrupt | (uint32_t)kENET_TsAvailInterrupt) /*!< Enet timestamp interrupt flag. */
+#define ENET_ERR_INTERRUPT \
+ ((uint32_t)kENET_BabrInterrupt | (uint32_t)kENET_BabtInterrupt | (uint32_t)kENET_EBusERInterrupt | \
+ (uint32_t)kENET_LateCollisionInterrupt | (uint32_t)kENET_RetryLimitInterrupt | \
+ (uint32_t)kENET_UnderrunInterrupt | (uint32_t)kENET_PayloadRxInterrupt) /*!< Enet error interrupt flag. */
+/*@}*/
+
+/*! @brief Defines the status return codes for transaction. */
+enum
+{
+ kStatus_ENET_InitMemoryFail =
+ MAKE_STATUS(kStatusGroup_ENET, 0U), /*!< Init fails since buffer memory is not enough. */
+ kStatus_ENET_RxFrameError = MAKE_STATUS(kStatusGroup_ENET, 1U), /*!< A frame received but data error happen. */
+ kStatus_ENET_RxFrameFail = MAKE_STATUS(kStatusGroup_ENET, 2U), /*!< Failed to receive a frame. */
+ kStatus_ENET_RxFrameEmpty = MAKE_STATUS(kStatusGroup_ENET, 3U), /*!< No frame arrive. */
+ kStatus_ENET_RxFrameDrop = MAKE_STATUS(kStatusGroup_ENET, 4U), /*!< Rx frame is dropped since no buffer memory. */
+ kStatus_ENET_TxFrameOverLen = MAKE_STATUS(kStatusGroup_ENET, 5U), /*!< Tx frame over length. */
+ kStatus_ENET_TxFrameBusy = MAKE_STATUS(kStatusGroup_ENET, 6U), /*!< Tx buffer descriptors are under process. */
+ kStatus_ENET_TxFrameFail = MAKE_STATUS(kStatusGroup_ENET, 7U), /*!< Transmit frame fail. */
+};
+
+/*! @brief Defines the MII/RMII/RGMII mode for data interface between the MAC and the PHY. */
+typedef enum _enet_mii_mode
+{
+ kENET_MiiMode = 0U, /*!< MII mode for data interface. */
+ kENET_RmiiMode = 1U, /*!< RMII mode for data interface. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ kENET_RgmiiMode = 2U /*!< RGMII mode for data interface. */
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+} enet_mii_mode_t;
+
+/*! @brief Defines the 10/100/1000 Mbps speed for the MII data interface.
+ *
+ * Notice: "kENET_MiiSpeed1000M" only supported when mii mode is "kENET_RgmiiMode".
+ */
+typedef enum _enet_mii_speed
+{
+ kENET_MiiSpeed10M = 0U, /*!< Speed 10 Mbps. */
+ kENET_MiiSpeed100M = 1U, /*!< Speed 100 Mbps. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ kENET_MiiSpeed1000M = 2U /*!< Speed 1000M bps. */
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+} enet_mii_speed_t;
+
+/*! @brief Defines the half or full duplex for the MII data interface. */
+typedef enum _enet_mii_duplex
+{
+ kENET_MiiHalfDuplex = 0U, /*!< Half duplex mode. */
+ kENET_MiiFullDuplex /*!< Full duplex mode. */
+} enet_mii_duplex_t;
+
+/*! @brief Define the MII opcode for normal MDIO_CLAUSES_22 Frame. */
+typedef enum _enet_mii_write
+{
+ kENET_MiiWriteNoCompliant = 0U, /*!< Write frame operation, but not MII-compliant. */
+ kENET_MiiWriteValidFrame /*!< Write frame operation for a valid MII management frame. */
+} enet_mii_write_t;
+
+/*! @brief Defines the read operation for the MII management frame. */
+typedef enum _enet_mii_read
+{
+ kENET_MiiReadValidFrame = 2U, /*!< Read frame operation for a valid MII management frame. */
+ kENET_MiiReadNoCompliant = 3U /*!< Read frame operation, but not MII-compliant. */
+} enet_mii_read_t;
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
+/*! @brief Define the MII opcode for extended MDIO_CLAUSES_45 Frame. */
+typedef enum _enet_mii_extend_opcode
+{
+ kENET_MiiAddrWrite_C45 = 0U, /*!< Address Write operation. */
+ kENET_MiiWriteFrame_C45 = 1U, /*!< Write frame operation for a valid MII management frame. */
+ kENET_MiiReadFrame_C45 = 3U /*!< Read frame operation for a valid MII management frame. */
+} enet_mii_extend_opcode;
+#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */
+
+/*! @brief Defines a special configuration for ENET MAC controller.
+ *
+ * These control flags are provided for special user requirements.
+ * Normally, these control flags are unused for ENET initialization.
+ * For special requirements, set the flags to
+ * macSpecialConfig in the enet_config_t.
+ * The kENET_ControlStoreAndFwdDisable is used to disable the FIFO store
+ * and forward. FIFO store and forward means that the FIFO read/send is started
+ * when a complete frame is stored in TX/RX FIFO. If this flag is set,
+ * configure rxFifoFullThreshold and txFifoWatermark
+ * in the enet_config_t.
+ */
+typedef enum _enet_special_control_flag
+{
+ kENET_ControlFlowControlEnable = 0x0001U, /*!< Enable ENET flow control: pause frame. */
+ kENET_ControlRxPayloadCheckEnable = 0x0002U, /*!< Enable ENET receive payload length check. */
+ kENET_ControlRxPadRemoveEnable = 0x0004U, /*!< Padding is removed from received frames. */
+ kENET_ControlRxBroadCastRejectEnable = 0x0008U, /*!< Enable broadcast frame reject. */
+ kENET_ControlMacAddrInsert = 0x0010U, /*!< Enable MAC address insert. */
+ kENET_ControlStoreAndFwdDisable = 0x0020U, /*!< Enable FIFO store and forward. */
+ kENET_ControlSMIPreambleDisable = 0x0040U, /*!< Enable SMI preamble. */
+ kENET_ControlPromiscuousEnable = 0x0080U, /*!< Enable promiscuous mode. */
+ kENET_ControlMIILoopEnable = 0x0100U, /*!< Enable ENET MII loop back. */
+ kENET_ControlVLANTagEnable = 0x0200U, /*!< Enable normal VLAN (single vlan tag). */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ kENET_ControlSVLANEnable = 0x0400U, /*!< Enable S-VLAN. */
+ kENET_ControlVLANUseSecondTag = 0x0800U /*!< Enable extracting the second vlan tag for further processing. */
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+} enet_special_control_flag_t;
+
+/*! @brief List of interrupts supported by the peripheral. This
+ * enumeration uses one-bit encoding to allow a logical OR of multiple
+ * members. Members usually map to interrupt enable bits in one or more
+ * peripheral registers.
+ */
+typedef enum _enet_interrupt_enable
+{
+ kENET_BabrInterrupt = ENET_EIR_BABR_MASK, /*!< Babbling receive error interrupt source */
+ kENET_BabtInterrupt = ENET_EIR_BABT_MASK, /*!< Babbling transmit error interrupt source */
+ kENET_GraceStopInterrupt = ENET_EIR_GRA_MASK, /*!< Graceful stop complete interrupt source */
+ kENET_TxFrameInterrupt = ENET_EIR_TXF_MASK, /*!< TX FRAME interrupt source */
+ kENET_TxBufferInterrupt = ENET_EIR_TXB_MASK, /*!< TX BUFFER interrupt source */
+ kENET_RxFrameInterrupt = ENET_EIR_RXF_MASK, /*!< RX FRAME interrupt source */
+ kENET_RxBufferInterrupt = ENET_EIR_RXB_MASK, /*!< RX BUFFER interrupt source */
+ kENET_MiiInterrupt = ENET_EIR_MII_MASK, /*!< MII interrupt source */
+ kENET_EBusERInterrupt = ENET_EIR_EBERR_MASK, /*!< Ethernet bus error interrupt source */
+ kENET_LateCollisionInterrupt = ENET_EIR_LC_MASK, /*!< Late collision interrupt source */
+ kENET_RetryLimitInterrupt = ENET_EIR_RL_MASK, /*!< Collision Retry Limit interrupt source */
+ kENET_UnderrunInterrupt = ENET_EIR_UN_MASK, /*!< Transmit FIFO underrun interrupt source */
+ kENET_PayloadRxInterrupt = ENET_EIR_PLR_MASK, /*!< Payload Receive error interrupt source */
+ kENET_WakeupInterrupt = ENET_EIR_WAKEUP_MASK, /*!< WAKEUP interrupt source */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ kENET_RxFlush2Interrupt = ENET_EIR_RXFLUSH_2_MASK, /*!< Rx DMA ring2 flush indication. */
+ kENET_RxFlush1Interrupt = ENET_EIR_RXFLUSH_1_MASK, /*!< Rx DMA ring1 flush indication. */
+ kENET_RxFlush0Interrupt = ENET_EIR_RXFLUSH_0_MASK, /*!< RX DMA ring0 flush indication. */
+ kENET_TxFrame2Interrupt = ENET_EIR_TXF2_MASK, /*!< Tx frame interrupt for Tx ring/class 2. */
+ kENET_TxBuffer2Interrupt = ENET_EIR_TXB2_MASK, /*!< Tx buffer interrupt for Tx ring/class 2. */
+ kENET_RxFrame2Interrupt = ENET_EIR_RXF2_MASK, /*!< Rx frame interrupt for Rx ring/class 2. */
+ kENET_RxBuffer2Interrupt = ENET_EIR_RXB2_MASK, /*!< Rx buffer interrupt for Rx ring/class 2. */
+ kENET_TxFrame1Interrupt = ENET_EIR_TXF1_MASK, /*!< Tx frame interrupt for Tx ring/class 1. */
+ kENET_TxBuffer1Interrupt = ENET_EIR_TXB1_MASK, /*!< Tx buffer interrupt for Tx ring/class 1. */
+ kENET_RxFrame1Interrupt = ENET_EIR_RXF1_MASK, /*!< Rx frame interrupt for Rx ring/class 1. */
+ kENET_RxBuffer1Interrupt = ENET_EIR_RXB1_MASK, /*!< Rx buffer interrupt for Rx ring/class 1. */
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ kENET_TsAvailInterrupt = ENET_EIR_TS_AVAIL_MASK, /*!< TS AVAIL interrupt source for PTP */
+ kENET_TsTimerInterrupt = ENET_EIR_TS_TIMER_MASK /*!< TS WRAP interrupt source for PTP */
+} enet_interrupt_enable_t;
+
+/*! @brief Defines the common interrupt event for callback use. */
+typedef enum _enet_event
+{
+ kENET_RxEvent, /*!< Receive event. */
+ kENET_TxEvent, /*!< Transmit event. */
+ kENET_ErrEvent, /*!< Error event: BABR/BABT/EBERR/LC/RL/UN/PLR . */
+ kENET_WakeUpEvent, /*!< Wake up from sleep mode event. */
+ kENET_TimeStampEvent, /*!< Time stamp event. */
+ kENET_TimeStampAvailEvent /*!< Time stamp available event.*/
+} enet_event_t;
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+/*! @brief Defines certain idle slope for bandwidth fraction. */
+typedef enum _enet_idle_slope
+{
+ kENET_IdleSlope1 = 1U, /*!< The bandwidth fraction is about 0.002. */
+ kENET_IdleSlope2 = 2U, /*!< The bandwidth fraction is about 0.003. */
+ kENET_IdleSlope4 = 4U, /*!< The bandwidth fraction is about 0.008. */
+ kENET_IdleSlope8 = 8U, /*!< The bandwidth fraction is about 0.02. */
+ kENET_IdleSlope16 = 16U, /*!< The bandwidth fraction is about 0.03. */
+ kENET_IdleSlope32 = 32U, /*!< The bandwidth fraction is about 0.06. */
+ kENET_IdleSlope64 = 64U, /*!< The bandwidth fraction is about 0.11. */
+ kENET_IdleSlope128 = 128U, /*!< The bandwidth fraction is about 0.20. */
+ kENET_IdleSlope256 = 256U, /*!< The bandwidth fraction is about 0.33. */
+ kENET_IdleSlope384 = 384U, /*!< The bandwidth fraction is about 0.43. */
+ kENET_IdleSlope512 = 512U, /*!< The bandwidth fraction is about 0.50. */
+ kENET_IdleSlope640 = 640U, /*!< The bandwidth fraction is about 0.56. */
+ kENET_IdleSlope768 = 768U, /*!< The bandwidth fraction is about 0.60. */
+ kENET_IdleSlope896 = 896U, /*!< The bandwidth fraction is about 0.64. */
+ kENET_IdleSlope1024 = 1024U, /*!< The bandwidth fraction is about 0.67. */
+ kENET_IdleSlope1152 = 1152U, /*!< The bandwidth fraction is about 0.69. */
+ kENET_IdleSlope1280 = 1280U, /*!< The bandwidth fraction is about 0.71. */
+ kENET_IdleSlope1408 = 1408U, /*!< The bandwidth fraction is about 0.73. */
+ kENET_IdleSlope1536 = 1536U /*!< The bandwidth fraction is about 0.75. */
+} enet_idle_slope_t;
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+/*! @brief Defines the transmit accelerator configuration. */
+typedef enum _enet_tx_accelerator
+{
+ kENET_TxAccelIsShift16Enabled = ENET_TACC_SHIFT16_MASK, /*!< Transmit FIFO shift-16. */
+ kENET_TxAccelIpCheckEnabled = ENET_TACC_IPCHK_MASK, /*!< Insert IP header checksum. */
+ kENET_TxAccelProtoCheckEnabled = ENET_TACC_PROCHK_MASK /*!< Insert protocol checksum. */
+} enet_tx_accelerator_t;
+
+/*! @brief Defines the receive accelerator configuration. */
+typedef enum _enet_rx_accelerator
+{
+ kENET_RxAccelPadRemoveEnabled = ENET_RACC_PADREM_MASK, /*!< Padding removal for short IP frames. */
+ kENET_RxAccelIpCheckEnabled = ENET_RACC_IPDIS_MASK, /*!< Discard with wrong IP header checksum. */
+ kENET_RxAccelProtoCheckEnabled = ENET_RACC_PRODIS_MASK, /*!< Discard with wrong protocol checksum. */
+ kENET_RxAccelMacCheckEnabled = ENET_RACC_LINEDIS_MASK, /*!< Discard with Mac layer errors. */
+ kENET_RxAccelisShift16Enabled = ENET_RACC_SHIFT16_MASK /*!< Receive FIFO shift-16. */
+} enet_rx_accelerator_t;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*! @brief Defines the ENET PTP message related constant. */
+typedef enum _enet_ptp_event_type
+{
+ kENET_PtpEventMsgType = 3U, /*!< PTP event message type. */
+ kENET_PtpSrcPortIdLen = 10U, /*!< PTP message sequence id length. */
+ kENET_PtpEventPort = 319U, /*!< PTP event port number. */
+ kENET_PtpGnrlPort = 320U /*!< PTP general port number. */
+} enet_ptp_event_type_t;
+
+/*! @brief Defines the IEEE 1588 PTP timer channel numbers. */
+typedef enum _enet_ptp_timer_channel
+{
+ kENET_PtpTimerChannel1 = 0U, /*!< IEEE 1588 PTP timer Channel 1. */
+ kENET_PtpTimerChannel2, /*!< IEEE 1588 PTP timer Channel 2. */
+ kENET_PtpTimerChannel3, /*!< IEEE 1588 PTP timer Channel 3. */
+ kENET_PtpTimerChannel4 /*!< IEEE 1588 PTP timer Channel 4. */
+} enet_ptp_timer_channel_t;
+
+/*! @brief Defines the capture or compare mode for IEEE 1588 PTP timer channels. */
+typedef enum _enet_ptp_timer_channel_mode
+{
+ kENET_PtpChannelDisable = 0U, /*!< Disable timer channel. */
+ kENET_PtpChannelRisingCapture = 1U, /*!< Input capture on rising edge. */
+ kENET_PtpChannelFallingCapture = 2U, /*!< Input capture on falling edge. */
+ kENET_PtpChannelBothCapture = 3U, /*!< Input capture on both edges. */
+ kENET_PtpChannelSoftCompare = 4U, /*!< Output compare software only. */
+ kENET_PtpChannelToggleCompare = 5U, /*!< Toggle output on compare. */
+ kENET_PtpChannelClearCompare = 6U, /*!< Clear output on compare. */
+ kENET_PtpChannelSetCompare = 7U, /*!< Set output on compare. */
+ kENET_PtpChannelClearCompareSetOverflow = 10U, /*!< Clear output on compare, set output on overflow. */
+ kENET_PtpChannelSetCompareClearOverflow = 11U, /*!< Set output on compare, clear output on overflow. */
+ kENET_PtpChannelPulseLowonCompare = 14U, /*!< Pulse output low on compare for one IEEE 1588 clock cycle. */
+ kENET_PtpChannelPulseHighonCompare = 15U /*!< Pulse output high on compare for one IEEE 1588 clock cycle. */
+} enet_ptp_timer_channel_mode_t;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*! @brief Defines the receive buffer descriptor structure for the little endian system.*/
+typedef struct _enet_rx_bd_struct
+{
+ uint16_t length; /*!< Buffer descriptor data length. */
+ uint16_t control; /*!< Buffer descriptor control and status. */
+ uint32_t buffer; /*!< Data buffer pointer. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint16_t controlExtend0; /*!< Extend buffer descriptor control0. */
+ uint16_t controlExtend1; /*!< Extend buffer descriptor control1. */
+ uint16_t payloadCheckSum; /*!< Internal payload checksum. */
+ uint8_t headerLength; /*!< Header length. */
+ uint8_t protocolTyte; /*!< Protocol type. */
+ uint16_t reserved0;
+ uint16_t controlExtend2; /*!< Extend buffer descriptor control2. */
+ uint32_t timestamp; /*!< Timestamp. */
+ uint16_t reserved1;
+ uint16_t reserved2;
+ uint16_t reserved3;
+ uint16_t reserved4;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+} enet_rx_bd_struct_t;
+
+/*! @brief Defines the enhanced transmit buffer descriptor structure for the little endian system. */
+typedef struct _enet_tx_bd_struct
+{
+ uint16_t length; /*!< Buffer descriptor data length. */
+ uint16_t control; /*!< Buffer descriptor control and status. */
+ uint32_t buffer; /*!< Data buffer pointer. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint16_t controlExtend0; /*!< Extend buffer descriptor control0. */
+ uint16_t controlExtend1; /*!< Extend buffer descriptor control1. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ uint16_t txLaunchTimeLow; /*!< Low 16-bits of transmit launch time. */
+ uint16_t txLaunchTimeHigh; /*!< High 16-bits of transmit launch time. */
+#else
+ uint16_t reserved0;
+ uint16_t reserved1;
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ uint16_t reserved2;
+ uint16_t controlExtend2; /*!< Extend buffer descriptor control2. */
+ uint32_t timestamp; /*!< Timestamp. */
+ uint16_t reserved3;
+ uint16_t reserved4;
+ uint16_t reserved5;
+ uint16_t reserved6;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+} enet_tx_bd_struct_t;
+
+/*! @brief Defines the ENET data error statistics structure. */
+typedef struct _enet_data_error_stats
+{
+ uint32_t statsRxLenGreaterErr; /*!< Receive length greater than RCR[MAX_FL]. */
+ uint32_t statsRxAlignErr; /*!< Receive non-octet alignment/ */
+ uint32_t statsRxFcsErr; /*!< Receive CRC error. */
+ uint32_t statsRxOverRunErr; /*!< Receive over run. */
+ uint32_t statsRxTruncateErr; /*!< Receive truncate. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint32_t statsRxProtocolChecksumErr; /*!< Receive protocol checksum error. */
+ uint32_t statsRxIpHeadChecksumErr; /*!< Receive IP header checksum error. */
+ uint32_t statsRxMacErr; /*!< Receive Mac error. */
+ uint32_t statsRxPhyErr; /*!< Receive PHY error. */
+ uint32_t statsRxCollisionErr; /*!< Receive collision. */
+ uint32_t statsTxErr; /*!< The error happen when transmit the frame. */
+ uint32_t statsTxFrameErr; /*!< The transmit frame is error. */
+ uint32_t statsTxOverFlowErr; /*!< Transmit overflow. */
+ uint32_t statsTxLateCollisionErr; /*!< Transmit late collision. */
+ uint32_t statsTxExcessCollisionErr; /*!< Transmit excess collision.*/
+ uint32_t statsTxUnderFlowErr; /*!< Transmit under flow error. */
+ uint32_t statsTxTsErr; /*!< Transmit time stamp error. */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+} enet_data_error_stats_t;
+
+/*! @brief Defines the Rx frame error structure. */
+typedef struct _enet_rx_frame_error
+{
+ bool statsRxTruncateErr : 1; /*!< Receive truncate. */
+ bool statsRxOverRunErr : 1; /*!< Receive over run. */
+ bool statsRxFcsErr : 1; /*!< Receive CRC error. */
+ bool : 1;
+ bool statsRxAlignErr : 1; /*!< Receive non-octet alignment. */
+ bool statsRxLenGreaterErr : 1; /*!< Receive length greater than RCR[MAX_FL]. */
+ uint32_t : 19;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ bool statsRxCollisionErr : 1; /*!< Receive collision. */
+ bool statsRxPhyErr : 1; /*!< Receive PHY error. */
+ uint8_t : 4;
+ bool statsRxMacErr : 1; /*!< Receive Mac error. */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+} enet_rx_frame_error_t;
+
+/*! @brief Defines the ENET transfer statistics structure. */
+typedef struct _enet_transfer_stats
+{
+ uint32_t statsRxFrameCount; /*!< Rx frame number. */
+ uint32_t statsRxFrameOk; /*!< Good Rx frame number. */
+ uint32_t statsRxCrcErr; /*!< Rx frame number with CRC error. */
+ uint32_t statsRxAlignErr; /*!< Rx frame number with alignment error. */
+ uint32_t statsRxDropInvalidSFD; /*!< Dropped frame number due to invalid SFD. */
+ uint32_t statsRxFifoOverflowErr; /*!< Rx FIFO overflow count. */
+ uint32_t statsTxFrameCount; /*!< Tx frame number. */
+ uint32_t statsTxFrameOk; /*!< Good Tx frame number. */
+ uint32_t statsTxCrcAlignErr; /*!< The transmit frame is error. */
+ uint32_t statsTxFifoUnderRunErr; /*!< Tx FIFO underrun count. */
+} enet_transfer_stats_t;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*! @brief Defines the ENET PTP time stamp structure. */
+typedef struct _enet_ptp_time
+{
+ uint64_t second; /*!< Second. */
+ uint32_t nanosecond; /*!< Nanosecond. */
+} enet_ptp_time_t;
+
+/*! @brief Defines the structure for the ENET PTP message data and timestamp data.*/
+typedef struct _enet_ptp_time_data
+{
+ uint8_t version; /*!< PTP version. */
+ uint8_t sourcePortId[kENET_PtpSrcPortIdLen]; /*!< PTP source port ID. */
+ uint16_t sequenceId; /*!< PTP sequence ID. */
+ uint8_t messageType; /*!< PTP message type. */
+ enet_ptp_time_t timeStamp; /*!< PTP timestamp. */
+} enet_ptp_time_data_t;
+
+/*! @brief Defines the ENET PTP configuration structure. */
+typedef struct _enet_ptp_config
+{
+ enet_ptp_timer_channel_t channel; /*!< Used for ERRATA_2579: the PTP 1588 timer channel for time interrupt. */
+ uint32_t ptp1588ClockSrc_Hz; /*!< The clock source of the PTP 1588 timer. */
+} enet_ptp_config_t;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*! @brief Defines the frame info structure. */
+typedef struct enet_frame_info
+{
+ void *context; /*!< User specified data */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ bool isTsAvail; /*!< Flag indicates timestamp available status */
+ enet_ptp_time_t timeStamp; /*!< Timestamp of frame */
+#endif
+} enet_frame_info_t;
+
+/*! @brief Defines the ENET transmit dirty addresses ring/queue structure. */
+typedef struct _enet_tx_dirty_ring
+{
+ enet_frame_info_t *txDirtyBase; /*!< Dirty buffer descriptor base address pointer. */
+ uint16_t txGenIdx; /*!< tx generate index. */
+ uint16_t txConsumIdx; /*!< tx consume index. */
+ uint16_t txRingLen; /*!< tx ring length. */
+ bool isFull; /*!< tx ring is full flag. */
+} enet_tx_dirty_ring_t;
+
+/*! @brief Defines the ENET Rx memory buffer alloc function pointer. */
+typedef void *(*enet_rx_alloc_callback_t)(ENET_Type *base, void *userData, uint8_t ringId);
+
+/*! @brief Defines the ENET Rx memory buffer free function pointer. */
+typedef void (*enet_rx_free_callback_t)(ENET_Type *base, void *buffer, void *userData, uint8_t ringId);
+
+/*! @brief Defines the receive buffer descriptor configuration structure.
+ *
+ * Note that for the internal DMA requirements, the buffers have a corresponding alignment requirements.
+ * 1. The aligned receive and transmit buffer size must be evenly divisible by ENET_BUFF_ALIGNMENT.
+ * when the data buffers are in cacheable region when cache is enabled, all those size should be
+ * aligned to the maximum value of "ENET_BUFF_ALIGNMENT" and the cache line size.
+ * 2. The aligned transmit and receive buffer descriptor start address must be at
+ * least 64 bit aligned. However, it's recommended to be evenly divisible by ENET_BUFF_ALIGNMENT.
+ * buffer descriptors should be put in non-cacheable region when cache is enabled.
+ * 3. The aligned transmit and receive data buffer start address must be evenly divisible by ENET_BUFF_ALIGNMENT.
+ * Receive buffers should be continuous with the total size equal to "rxBdNumber * rxBuffSizeAlign".
+ * Transmit buffers should be continuous with the total size equal to "txBdNumber * txBuffSizeAlign".
+ * when the data buffers are in cacheable region when cache is enabled, all those size should be
+ * aligned to the maximum value of "ENET_BUFF_ALIGNMENT" and the cache line size.
+ */
+typedef struct _enet_buffer_config
+{
+ uint16_t rxBdNumber; /*!< Receive buffer descriptor number. */
+ uint16_t txBdNumber; /*!< Transmit buffer descriptor number. */
+ uint16_t rxBuffSizeAlign; /*!< Aligned receive data buffer size. */
+ uint16_t txBuffSizeAlign; /*!< Aligned transmit data buffer size. */
+ volatile enet_rx_bd_struct_t
+ *rxBdStartAddrAlign; /*!< Aligned receive buffer descriptor start address: should be non-cacheable. */
+ volatile enet_tx_bd_struct_t
+ *txBdStartAddrAlign; /*!< Aligned transmit buffer descriptor start address: should be non-cacheable. */
+ uint8_t *rxBufferAlign; /*!< Receive data buffer start address. */
+ uint8_t *txBufferAlign; /*!< Transmit data buffer start address. */
+ bool rxMaintainEnable; /*!< Receive buffer cache maintain. */
+ bool txMaintainEnable; /*!< Transmit buffer cache maintain. */
+ enet_frame_info_t *txFrameInfo; /*!< Transmit frame information start address. */
+} enet_buffer_config_t;
+
+#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE
+/*! @brief Defines the interrupt coalescing configure structure. */
+typedef struct _enet_intcoalesce_config
+{
+ uint8_t txCoalesceFrameCount[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit interrupt coalescing frame count threshold. */
+ uint16_t txCoalesceTimeCount[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit interrupt coalescing timer count threshold. */
+ uint8_t rxCoalesceFrameCount[FSL_FEATURE_ENET_QUEUE]; /*!< Receive interrupt coalescing frame count threshold. */
+ uint16_t rxCoalesceTimeCount[FSL_FEATURE_ENET_QUEUE]; /*!< Receive interrupt coalescing timer count threshold. */
+} enet_intcoalesce_config_t;
+#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+/*! @brief Defines the ENET AVB Configure structure.
+ *
+ * This is used for to configure the extended ring 1 and ring 2.
+ * 1. The classification match format is (CMP3 << 12) | (CMP2 << 8) | (CMP1 << 4) | CMP0.
+ * composed of four 3-bit compared VLAN priority field cmp0~cmp3, cm0 ~ cmp3 are used in parallel.
+ *
+ * If CMP1,2,3 are not unused, please set them to the same value as CMP0.
+ * 2. The idleSlope is used to calculate the Band Width fraction, BW fraction = 1 / (1 + 512/idleSlope).
+ * For avb configuration, the BW fraction of Class 1 and Class 2 combined must not exceed 0.75.
+ */
+typedef struct _enet_avb_config
+{
+ uint16_t rxClassifyMatch[FSL_FEATURE_ENET_QUEUE - 1]; /*!< The classification match value for the ring. */
+ enet_idle_slope_t idleSlope[FSL_FEATURE_ENET_QUEUE - 1]; /*!< The idle slope for certian bandwidth fraction. */
+} enet_avb_config_t;
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+/* Forward declaration of the handle typedef. */
+typedef struct _enet_handle enet_handle_t;
+
+/*! @brief ENET callback function. */
+typedef void (*enet_callback_t)(ENET_Type *base,
+ enet_handle_t *handle,
+#if FSL_FEATURE_ENET_QUEUE > 1
+ uint32_t ringId,
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ enet_event_t event,
+ enet_frame_info_t *frameInfo,
+ void *userData);
+
+/*! @brief Defines the basic configuration structure for the ENET device.
+ *
+ * Note:
+ * 1. macSpecialConfig is used for a special control configuration, A logical OR of
+ * "enet_special_control_flag_t". For a special configuration for MAC,
+ * set this parameter to 0.
+ * 2. txWatermark is used for a cut-through operation. It is in steps of 64 bytes:
+ * 0/1 - 64 bytes written to TX FIFO before transmission of a frame begins.
+ * 2 - 128 bytes written to TX FIFO ....
+ * 3 - 192 bytes written to TX FIFO ....
+ * The maximum of txWatermark is 0x2F - 4032 bytes written to TX FIFO ....
+ * txWatermark allows minimizing the transmit latency to set the txWatermark to 0 or 1
+ * or for larger bus access latency 3 or larger due to contention for the system bus.
+ * 3. rxFifoFullThreshold is similar to the txWatermark for cut-through operation in RX.
+ * It is in 64-bit words. The minimum is ENET_FIFO_MIN_RX_FULL and the maximum is 0xFF.
+ * If the end of the frame is stored in FIFO and the frame size if smaller than the
+ * txWatermark, the frame is still transmitted. The rule is the
+ * same for rxFifoFullThreshold in the receive direction.
+ * 4. When "kENET_ControlFlowControlEnable" is set in the macSpecialConfig, ensure
+ * that the pauseDuration, rxFifoEmptyThreshold, and rxFifoStatEmptyThreshold
+ * are set for flow control enabled case.
+ * 5. When "kENET_ControlStoreAndFwdDisabled" is set in the macSpecialConfig, ensure
+ * that the rxFifoFullThreshold and txFifoWatermark are set for store and forward disable.
+ * 6. The rxAccelerConfig and txAccelerConfig default setting with 0 - accelerator
+ * are disabled. The "enet_tx_accelerator_t" and "enet_rx_accelerator_t" are
+ * recommended to be used to enable the transmit and receive accelerator.
+ * After the accelerators are enabled, the store and forward feature should be enabled.
+ * As a result, kENET_ControlStoreAndFwdDisabled should not be set.
+ * 7. The intCoalesceCfg can be used in the rx or tx enabled cases to decrese the CPU loading.
+ */
+typedef struct _enet_config
+{
+ uint32_t macSpecialConfig; /*!< Mac special configuration. A logical OR of "enet_special_control_flag_t". */
+ uint32_t interrupt; /*!< Mac interrupt source. A logical OR of "enet_interrupt_enable_t". */
+ uint16_t rxMaxFrameLen; /*!< Receive maximum frame length. */
+ enet_mii_mode_t miiMode; /*!< MII mode. */
+ enet_mii_speed_t miiSpeed; /*!< MII Speed. */
+ enet_mii_duplex_t miiDuplex; /*!< MII duplex. */
+ uint8_t rxAccelerConfig; /*!< Receive accelerator, A logical OR of "enet_rx_accelerator_t". */
+ uint8_t txAccelerConfig; /*!< Transmit accelerator, A logical OR of "enet_rx_accelerator_t". */
+ uint16_t pauseDuration; /*!< For flow control enabled case: Pause duration. */
+ uint8_t rxFifoEmptyThreshold; /*!< For flow control enabled case: when RX FIFO level reaches this value,
+ it makes MAC generate XOFF pause frame. */
+#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD
+ uint8_t rxFifoStatEmptyThreshold; /*!< For flow control enabled case: number of frames in the receive FIFO,
+ independent of size, that can be accept. If the limit is reached, reception
+ continues and a pause frame is triggered. */
+#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */
+ uint8_t rxFifoFullThreshold; /*!< For store and forward disable case, the data required in RX FIFO to notify
+ the MAC receive ready status. */
+ uint8_t txFifoWatermark; /*!< For store and forward disable case, the data required in TX FIFO
+ before a frame transmit start. */
+#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE
+ enet_intcoalesce_config_t *intCoalesceCfg; /*!< If the interrupt coalsecence is not required in the ring n(0,1,2),
+ please set to NULL. */
+#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */
+ uint8_t ringNum; /*!< Number of used rings. default with 1 -- single ring. */
+ enet_rx_alloc_callback_t rxBuffAlloc; /*!< Callback function to alloc memory, must be provided for zero-copy Rx. */
+ enet_rx_free_callback_t rxBuffFree; /*!< Callback function to free memory, must be provided for zero-copy Rx. */
+ enet_callback_t callback; /*!< General callback function. */
+ void *userData; /*!< Callback function parameter.*/
+} enet_config_t;
+
+/*! @brief Defines the ENET transmit buffer descriptor ring/queue structure. */
+typedef struct _enet_tx_bd_ring
+{
+ volatile enet_tx_bd_struct_t *txBdBase; /*!< Buffer descriptor base address pointer. */
+ uint16_t txGenIdx; /*!< The current available transmit buffer descriptor pointer. */
+ uint16_t txConsumIdx; /*!< Transmit consume index. */
+ volatile uint16_t txDescUsed; /*!< Transmit descriptor used number. */
+ uint16_t txRingLen; /*!< Transmit ring length. */
+} enet_tx_bd_ring_t;
+
+/*! @brief Defines the ENET receive buffer descriptor ring/queue structure. */
+typedef struct _enet_rx_bd_ring
+{
+ volatile enet_rx_bd_struct_t *rxBdBase; /*!< Buffer descriptor base address pointer. */
+ uint16_t rxGenIdx; /*!< The current available receive buffer descriptor pointer. */
+ uint16_t rxRingLen; /*!< Receive ring length. */
+} enet_rx_bd_ring_t;
+
+/*! @brief Defines the ENET handler structure. */
+struct _enet_handle
+{
+ enet_rx_bd_ring_t rxBdRing[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer descriptor. */
+ enet_tx_bd_ring_t txBdRing[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer descriptor. */
+ uint16_t rxBuffSizeAlign[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer size alignment. */
+ uint16_t txBuffSizeAlign[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer size alignment. */
+ bool rxMaintainEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer cache maintain. */
+ bool txMaintainEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer cache maintain. */
+ uint8_t ringNum; /*!< Number of used rings. */
+ enet_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< Callback function parameter.*/
+ enet_tx_dirty_ring_t txDirtyRing[FSL_FEATURE_ENET_QUEUE]; /*!< Ring to store tx frame information.*/
+ bool txReclaimEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Tx reclaim enable flag.*/
+ enet_rx_alloc_callback_t rxBuffAlloc; /*!< Callback function to alloc memory for zero copy Rx. */
+ enet_rx_free_callback_t rxBuffFree; /*!< Callback function to free memory for zero copy Rx. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ volatile enet_tx_bd_struct_t
+ *txBdDirtyStatic[FSL_FEATURE_ENET_QUEUE]; /*!< The dirty transmit buffer descriptor for error static update. */
+ uint64_t msTimerSecond; /*!< The second for Master PTP timer. */
+#endif
+ uint8_t multicastCount[64]; /*!< Multicast collisions counter */
+#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID
+ uint32_t enetClock; /*!< The clock of enet peripheral, to caculate core cycles for PTP timestamp.*/
+ uint32_t tsDelayCount; /*!< The count of core cycles for PTP timestamp capture delay.*/
+#endif
+};
+
+typedef struct _enet_buffer_struct
+{
+ void *buffer; /*!< The buffer store the whole or partial frame. */
+ uint16_t length; /*!< The byte length of this buffer. */
+} enet_buffer_struct_t;
+
+typedef struct _enet_rx_frame_attribute_struct
+{
+ bool promiscuous; /*!< This frame is received because of promiscuous mode. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint32_t timestamp; /*!< The nanosecond part timestamp of this Rx frame. */
+#endif
+} enet_rx_frame_attribute_t;
+
+typedef struct _enet_rx_frame_struct
+{
+ enet_buffer_struct_t *rxBuffArray; /*!< Rx frame buffer structure. */
+ uint16_t totLen; /*!< Rx frame total length. */
+ enet_rx_frame_attribute_t rxAttribute; /*!< Rx frame attribute structure. */
+ enet_rx_frame_error_t rxFrameError; /*!< Rx frame error. */
+} enet_rx_frame_struct_t;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+typedef struct _enet_tx_config_struct
+{
+ bool intEnable : 1;
+ bool tsEnable : 1;
+ bool autoProtocolChecksum : 1;
+ bool autoIPChecksum : 1;
+ uint8_t AVBFrameType : 4; /*!< AVB class type. */
+ bool tltEnable : 1; /*!< Transmit launch time enable. */
+ uint16_t tltLow; /*!< Specifies when frame can be transmitted. */
+ uint16_t tltHigh; /*!< Specifies when frame can be transmitted. */
+} enet_tx_config_struct_t;
+#endif
+
+typedef struct _enet_tx_frame_struct
+{
+ enet_buffer_struct_t *txBuffArray; /*!< Tx frame buffer structure. */
+ uint32_t txBuffNum; /*!< Buffer number of this Tx frame. */
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ enet_tx_config_struct_t txConfig; /*!< Tx extra configuation. */
+#endif
+ void *context; /*!< Driver reclaims and gives it in Tx over callback, usually store network packet header. */
+} enet_tx_frame_struct_t;
+
+/*! @brief Define interrupt IRQ handler. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+typedef void (*enet_isr_ring_t)(ENET_Type *base, enet_handle_t *handle, uint32_t ringId);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+typedef void (*enet_isr_t)(ENET_Type *base, enet_handle_t *handle);
+
+/*! @brief Pointers to enet clocks for each instance. */
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+extern const clock_ip_name_t s_enetClock[];
+#if defined(FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE) && FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE
+extern const clock_ip_name_t s_enetExtraClock[];
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Get the ENET instance from peripheral base address.
+ *
+ * @param base ENET peripheral base address.
+ * @return ENET instance.
+ */
+uint32_t ENET_GetInstance(ENET_Type *base);
+
+/*!
+ * @name Initialization and De-initialization
+ * @{
+ */
+
+/*!
+ * @brief Gets the ENET default configuration structure.
+ *
+ * The purpose of this API is to get the default ENET MAC controller
+ * configure structure for ENET_Init(). User may use the initialized
+ * structure unchanged in ENET_Init(), or modify some fields of the
+ * structure before calling ENET_Init().
+ * Example:
+ @code
+ enet_config_t config;
+ ENET_GetDefaultConfig(&config);
+ @endcode
+ * @param config The ENET mac controller configuration structure pointer.
+ */
+void ENET_GetDefaultConfig(enet_config_t *config);
+
+/*!
+ * @brief Initializes the ENET module.
+ *
+ * This function initializes the module with the ENET configuration.
+ * @note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Up().
+ *
+ * @param base ENET peripheral base address.
+ * @param handle ENET handler pointer.
+ * @param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * @param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * @param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * @param srcClock_Hz The internal module clock source for MII clock.
+ * @retval kStatus_Success Succeed to initialize the ethernet driver.
+ * @retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough.
+ *
+ */
+status_t ENET_Up(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Initializes the ENET module.
+ *
+ * This function ungates the module clock and initializes it with the ENET configuration.
+ * @note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Init().
+ *
+ * @param base ENET peripheral base address.
+ * @param handle ENET handler pointer.
+ * @param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * @param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * @param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * @param srcClock_Hz The internal module clock source for MII clock.
+ * @retval kStatus_Success Succeed to initialize the ethernet driver.
+ * @retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough.
+ */
+status_t ENET_Init(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Stops the ENET module.
+
+ * This function disables the ENET module.
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_Down(ENET_Type *base);
+
+/*!
+ * @brief Deinitializes the ENET module.
+
+ * This function gates the module clock, clears ENET interrupts, and disables the ENET module.
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_Deinit(ENET_Type *base);
+
+/*!
+ * @brief Resets the ENET module.
+ *
+ * This function restores the ENET module to reset state.
+ * Note that this function sets all registers to
+ * reset state. As a result, the ENET module can't work after calling this function.
+ *
+ * @param base ENET peripheral base address.
+ */
+static inline void ENET_Reset(ENET_Type *base)
+{
+ base->ECR |= ENET_ECR_RESET_MASK;
+}
+
+/* @} */
+
+/*!
+ * @name MII interface operation
+ * @{
+ */
+
+/*!
+ * @brief Sets the ENET MII speed and duplex.
+ *
+ * This API is provided to dynamically change the speed and dulpex for MAC.
+ *
+ * @param base ENET peripheral base address.
+ * @param speed The speed of the RMII mode.
+ * @param duplex The duplex of the RMII mode.
+ */
+void ENET_SetMII(ENET_Type *base, enet_mii_speed_t speed, enet_mii_duplex_t duplex);
+
+/*!
+ * @brief Sets the ENET SMI(serial management interface)- MII management interface.
+ *
+ * @param base ENET peripheral base address.
+ * @param srcClock_Hz This is the ENET module clock frequency. See clock distribution.
+ * @param isPreambleDisabled The preamble disable flag.
+ * - true Enables the preamble.
+ * - false Disables the preamble.
+ */
+void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled);
+
+/*!
+ * @brief Gets the ENET SMI- MII management interface configuration.
+ *
+ * This API is used to get the SMI configuration to check whether the MII management
+ * interface has been set.
+ *
+ * @param base ENET peripheral base address.
+ * @return The SMI setup status true or false.
+ */
+static inline bool ENET_GetSMI(ENET_Type *base)
+{
+ return (0U != (base->MSCR & 0x7EU));
+}
+
+/*!
+ * @brief Reads data from the PHY register through an SMI interface.
+ *
+ * @param base ENET peripheral base address.
+ * @return The data read from PHY
+ */
+static inline uint32_t ENET_ReadSMIData(ENET_Type *base)
+{
+ return (uint32_t)((base->MMFR & ENET_MMFR_DATA_MASK) >> ENET_MMFR_DATA_SHIFT);
+}
+
+/*!
+ * @brief Sends the MDIO IEEE802.3 Clause 22 format write command.
+ *
+ * After calling this function, need to check whether the transmission is over then do next MDIO operation.
+ * For ease of use, encapsulated ENET_MDIOWrite() can be called. For customized requirements, implement
+ * with combining separated APIs.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address. Range from 0 ~ 31.
+ * @param regAddr The PHY register address. Range from 0 ~ 31.
+ * @param operation The write operation.
+ * @param data The data written to PHY.
+ */
+static inline void ENET_StartSMIWrite(
+ ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, enet_mii_write_t operation, uint16_t data)
+{
+ base->MMFR = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(regAddr) |
+ ENET_MMFR_TA(2U) | data;
+}
+
+/*!
+ * @brief Sends the MDIO IEEE802.3 Clause 22 format read command.
+ *
+ * After calling this function, need to check whether the transmission is over then do next MDIO operation.
+ * For ease of use, encapsulated ENET_MDIORead() can be called. For customized requirements, implement
+ * with combining separated APIs.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address. Range from 0 ~ 31.
+ * @param regAddr The PHY register address. Range from 0 ~ 31.
+ * @param operation The read operation.
+ */
+static inline void ENET_StartSMIRead(ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, enet_mii_read_t operation)
+{
+ base->MMFR =
+ ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(regAddr) | ENET_MMFR_TA(2U);
+}
+
+/*!
+ * @brief MDIO write with IEEE802.3 Clause 22 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address. Range from 0 ~ 31.
+ * @param regAddr The PHY register. Range from 0 ~ 31.
+ * @param data The data written to PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOWrite(ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t data);
+
+/*!
+ * @brief MDIO read with IEEE802.3 Clause 22 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param phyAddr The PHY address. Range from 0 ~ 31.
+ * @param regAddr The PHY register. Range from 0 ~ 31.
+ * @param pData The data read from PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIORead(ENET_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t *pData);
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
+/*!
+ * @brief Sends the MDIO IEEE802.3 Clause 45 format write register command.
+ *
+ * After calling this function, need to check whether the transmission is over then do next MDIO operation.
+ * For ease of use, encapsulated ENET_MDIOC45Write()/ENET_MDIOC45Read() can be called. For customized
+ * requirements, implement with combining separated APIs.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param regAddr The PHY register address.
+ */
+static inline void ENET_StartExtC45SMIWriteReg(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr)
+{
+ base->MMFR = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(portAddr) |
+ ENET_MMFR_RA(devAddr) | ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr);
+}
+
+/*!
+ * @brief Sends the MDIO IEEE802.3 Clause 45 format write data command.
+ *
+ * After calling this function, need to check whether the transmission is over then do next MDIO operation.
+ * For ease of use, encapsulated ENET_MDIOC45Write() can be called. For customized requirements, implement
+ * with combining separated APIs.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param data The data written to PHY.
+ */
+static inline void ENET_StartExtC45SMIWriteData(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t data)
+{
+ base->MMFR = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(portAddr) |
+ ENET_MMFR_RA(devAddr) | ENET_MMFR_TA(2) | ENET_MMFR_DATA(data);
+}
+
+/*!
+ * @brief Sends the MDIO IEEE802.3 Clause 45 format read data command.
+ *
+ * After calling this function, need to check whether the transmission is over then do next MDIO operation.
+ * For ease of use, encapsulated ENET_MDIOC45Read() can be called. For customized requirements, implement
+ * with combining separated APIs.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ */
+static inline void ENET_StartExtC45SMIReadData(ENET_Type *base, uint8_t portAddr, uint8_t devAddr)
+{
+ base->MMFR = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(portAddr) |
+ ENET_MMFR_RA(devAddr) | ENET_MMFR_TA(2);
+}
+
+/*!
+ * @brief MDIO write with IEEE802.3 Clause 45 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param regAddr The PHY register address.
+ * @param data The data written to PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOC45Write(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t data);
+
+/*!
+ * @brief MDIO read with IEEE802.3 Clause 45 format.
+ *
+ * @param base ENET peripheral base address.
+ * @param portAddr The MDIO port address(PHY address).
+ * @param devAddr The device address.
+ * @param regAddr The PHY register address.
+ * @param pData The data read from PHY.
+ * @return kStatus_Success MDIO access succeeds.
+ * @return kStatus_Timeout MDIO access timeout.
+ */
+status_t ENET_MDIOC45Read(ENET_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t *pData);
+#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */
+
+#if ((defined(FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) || \
+ (defined(FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY))
+/*!
+ * @brief Control the usage of the delayed tx/rx RGMII clock.
+ *
+ * @param base ENET peripheral base address.
+ * @param txEnabled Enable or disable to generate the delayed version of RGMII_TXC.
+ * @param rxEnabled Enable or disable to use the delayed version of RGMII_RXC.
+ */
+static inline void ENET_SetRGMIIClockDelay(ENET_Type *base, bool txEnabled, bool rxEnabled)
+{
+ uint32_t ecrReg = base->ECR;
+
+#if defined(FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY
+ /* Set for transmit clock delay. */
+ if (txEnabled)
+ {
+ ecrReg |= ENET_ECR_TXC_DLY_MASK;
+ }
+ else
+ {
+ ecrReg &= ~ENET_ECR_TXC_DLY_MASK;
+ }
+#endif /* FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY */
+
+#if defined(FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY
+ /* Set for receive clock delay. */
+ if (rxEnabled)
+ {
+ ecrReg |= ENET_ECR_RXC_DLY_MASK;
+ }
+ else
+ {
+ ecrReg &= ~ENET_ECR_RXC_DLY_MASK;
+ }
+#endif /* FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY */
+ base->ECR = ecrReg;
+}
+#endif
+
+/* @} */
+
+/*!
+ * @name MAC Address Filter
+ * @{
+ */
+
+/*!
+ * @brief Sets the ENET module Mac address.
+ *
+ * @param base ENET peripheral base address.
+ * @param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_SetMacAddr(ENET_Type *base, uint8_t *macAddr);
+
+/*!
+ * @brief Gets the ENET module Mac address.
+ *
+ * @param base ENET peripheral base address.
+ * @param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_GetMacAddr(ENET_Type *base, uint8_t *macAddr);
+
+/*!
+ * @brief Adds the ENET device to a multicast group.
+ *
+ * @param base ENET peripheral base address.
+ * @param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_AddMulticastGroup(ENET_Type *base, uint8_t *address);
+
+/*!
+ * @brief Moves the ENET device from a multicast group.
+ *
+ * @param base ENET peripheral base address.
+ * @param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_LeaveMulticastGroup(ENET_Type *base, uint8_t *address);
+
+/* @} */
+
+/*!
+ * @name Other basic operation
+ * @{
+ */
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+/*!
+ * @brief Sets the ENET AVB feature.
+ *
+ * ENET AVB feature configuration, set the Receive classification match and transmit
+ * bandwidth. This API is called when the AVB feature is required.
+ *
+ * Note: The AVB frames transmission scheme is credit-based tx scheme and it's only supported
+ * with the Enhanced buffer descriptors. so the AVB configuration should only done with
+ * Enhanced buffer descriptor. so when the AVB feature is required, please make sure the
+ * the "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" is defined.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle ENET handler pointer.
+ * @param config The ENET AVB feature configuration structure.
+ */
+void ENET_AVBConfigure(ENET_Type *base, enet_handle_t *handle, const enet_avb_config_t *config);
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*!
+ * @brief Activates frame reception for multiple rings.
+ *
+ * This function is to active the enet read process.
+ * @note This must be called after the MAC configuration and
+ * state are ready. It must be called after the ENET_Init().
+ * This should be called when the frame reception is required.
+ *
+ * @param base ENET peripheral base address.
+ */
+static inline void ENET_ActiveRead(ENET_Type *base)
+{
+ base->RDAR = ENET_RDAR_RDAR_MASK;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ if (FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) > 1)
+ {
+ base->RDAR1 = ENET_RDAR1_RDAR_MASK;
+ base->RDAR2 = ENET_RDAR2_RDAR_MASK;
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+}
+
+/*!
+ * @brief Enables/disables the MAC to enter sleep mode.
+ * This function is used to set the MAC enter sleep mode.
+ * When entering sleep mode, the magic frame wakeup interrupt should be enabled
+ * to wake up MAC from the sleep mode and reset it to normal mode.
+ *
+ * @param base ENET peripheral base address.
+ * @param enable True enable sleep mode, false disable sleep mode.
+ */
+static inline void ENET_EnableSleepMode(ENET_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* When this field is set, MAC enters sleep mode. */
+ base->ECR |= ENET_ECR_SLEEP_MASK | ENET_ECR_MAGICEN_MASK;
+ }
+ else
+ { /* MAC exits sleep mode. */
+ base->ECR &= ~(ENET_ECR_SLEEP_MASK | ENET_ECR_MAGICEN_MASK);
+ }
+}
+
+/*!
+ * @brief Gets ENET transmit and receive accelerator functions from MAC controller.
+ *
+ * @param base ENET peripheral base address.
+ * @param txAccelOption The transmit accelerator option. The "enet_tx_accelerator_t" is
+ * recommended to be used to as the mask to get the exact the accelerator option.
+ * @param rxAccelOption The receive accelerator option. The "enet_rx_accelerator_t" is
+ * recommended to be used to as the mask to get the exact the accelerator option.
+ */
+static inline void ENET_GetAccelFunction(ENET_Type *base, uint32_t *txAccelOption, uint32_t *rxAccelOption)
+{
+ assert(txAccelOption != NULL);
+ assert(txAccelOption != NULL);
+
+ *txAccelOption = base->TACC;
+ *rxAccelOption = base->RACC;
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts.
+ * @{
+ */
+
+/*!
+ * @brief Enables the ENET interrupt.
+ *
+ * This function enables the ENET interrupt according to the provided mask. The mask
+ * is a logical OR of enumeration members. See ::enet_interrupt_enable_t.
+ * For example, to enable the TX frame interrupt and RX frame interrupt, do the following.
+ * @code
+ * ENET_EnableInterrupts(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt);
+ * @endcode
+ *
+ * @param base ENET peripheral base address.
+ * @param mask ENET interrupts to enable. This is a logical OR of the
+ * enumeration ::enet_interrupt_enable_t.
+ */
+static inline void ENET_EnableInterrupts(ENET_Type *base, uint32_t mask)
+{
+ base->EIMR |= mask;
+}
+
+/*!
+ * @brief Disables the ENET interrupt.
+ *
+ * This function disables the ENET interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members. See ::enet_interrupt_enable_t.
+ * For example, to disable the TX frame interrupt and RX frame interrupt, do the following.
+ * @code
+ * ENET_DisableInterrupts(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt);
+ * @endcode
+ *
+ * @param base ENET peripheral base address.
+ * @param mask ENET interrupts to disable. This is a logical OR of the
+ * enumeration ::enet_interrupt_enable_t.
+ */
+static inline void ENET_DisableInterrupts(ENET_Type *base, uint32_t mask)
+{
+ base->EIMR &= ~mask;
+}
+
+/*!
+ * @brief Gets the ENET interrupt status flag.
+ *
+ * @param base ENET peripheral base address.
+ * @return The event status of the interrupt source. This is the logical OR of members
+ * of the enumeration ::enet_interrupt_enable_t.
+ */
+static inline uint32_t ENET_GetInterruptStatus(ENET_Type *base)
+{
+ return base->EIR;
+}
+
+/*!
+ * @brief Clears the ENET interrupt events status flag.
+ *
+ * This function clears enabled ENET interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members. See the ::enet_interrupt_enable_t.
+ * For example, to clear the TX frame interrupt and RX frame interrupt, do the following.
+ * @code
+ * ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt);
+ * @endcode
+ *
+ * @param base ENET peripheral base address.
+ * @param mask ENET interrupt source to be cleared.
+ * This is the logical OR of members of the enumeration ::enet_interrupt_enable_t.
+ */
+static inline void ENET_ClearInterruptStatus(ENET_Type *base, uint32_t mask)
+{
+ base->EIR = mask;
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * @brief Set the second level Rx IRQ handler
+ *
+ * @param base ENET peripheral base address.
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler);
+
+/*!
+ * @brief Set the second level Tx IRQ handler
+ *
+ * @param base ENET peripheral base address.
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler);
+
+#else
+/*!
+ * @brief Set the second level Rx IRQ handler
+ *
+ * @param base ENET peripheral base address.
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_t ISRHandler);
+
+/*!
+ * @brief Set the second level Tx IRQ handler
+ *
+ * @param base ENET peripheral base address.
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_t ISRHandler);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+/*!
+ * @brief Set the second level Err IRQ handler
+ *
+ * @param base ENET peripheral base address.
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetErrISRHandler(ENET_Type *base, enet_isr_t ISRHandler);
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * @brief Set the second level Ts IRQ handler
+ *
+ * @param ISRHandler The handler to install.
+ */
+void ENET_SetTsISRHandler(ENET_Type *base, enet_isr_t ISRHandler);
+
+/*!
+ * @brief Set the second level 1588 Timer IRQ handler
+ *
+ * @param ISRHandler The handler to install.
+ */
+void ENET_Set1588TimerISRHandler(ENET_Type *base, enet_isr_t ISRHandler);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/* @} */
+
+/*!
+ * @name Transactional operation
+ * @{
+ */
+
+/*!
+ * @brief Sets the callback function.
+ * @deprecated Do not use this function. It has been superceded by the config param in @ref ENET_Init.
+ * This API is provided for the application callback required case when ENET
+ * interrupt is enabled. This API should be called after calling ENET_Init.
+ *
+ * @param handle ENET handler pointer. Should be provided by application.
+ * @param callback The ENET callback function.
+ * @param userData The callback function parameter.
+ */
+void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData);
+
+/*!
+ * @brief Gets the error statistics of a received frame for ENET specified ring.
+ *
+ * This API must be called after the ENET_GetRxFrameSize and before the ENET_ReadFrame().
+ * If the ENET_GetRxFrameSize returns kStatus_ENET_RxFrameError,
+ * the ENET_GetRxErrBeforeReadFrame can be used to get the exact error statistics.
+ * This is an example.
+ * @code
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (status == kStatus_ENET_RxFrameError)
+ * {
+ * Comments: Get the error information of the received frame.
+ * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic, 0);
+ * Comments: update the receive buffer.
+ * ENET_ReadFrame(EXAMPLE_ENET, &g_handle, NULL, 0);
+ * }
+ * @endcode
+ * @param handle The ENET handler structure pointer. This is the same handler pointer used in the ENET_Init.
+ * @param eErrorStatic The error statistics structure pointer.
+ * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ */
+void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId);
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * @brief Gets the ENET transmit frame statistics after the data send for specified ring.
+ *
+ * This interface gets the error statistics of the transmit frame.
+ * Because the error information is reported by the uDMA after the data delivery, this interface
+ * should be called after the data transmit API. It is recommended to call this function on
+ * transmit interrupt handler. After calling the ENET_SendFrame, the
+ * transmit interrupt notifies the transmit completion.
+ *
+ * @param handle The PTP handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param eErrorStatic The error statistics structure pointer.
+ * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ * @return The execute status.
+ */
+status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*!
+ * @brief Gets statistical data in transfer.
+ *
+ * @param base ENET peripheral base address.
+ * @param statistics The statistics structure pointer.
+ */
+void ENET_GetStatistics(ENET_Type *base, enet_transfer_stats_t *statistics);
+
+/*!
+ * @brief Gets the size of the read frame for specified ring.
+ *
+ * This function gets a received frame size from the ENET buffer descriptors.
+ * @note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS.
+ * After calling ENET_GetRxFrameSize, ENET_ReadFrame() should be called to receive frame and update the BD
+ * if the result is not "kStatus_ENET_RxFrameEmpty".
+ *
+ * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * @param length The length of the valid frame received.
+ * @param ringId The ring index or ring number.
+ * @retval kStatus_ENET_RxFrameEmpty No frame received. Should not call ENET_ReadFrame to read frame.
+ * @retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrame should be called with NULL data
+ * and NULL length to update the receive buffers.
+ * @retval kStatus_Success Receive a frame Successfully then the ENET_ReadFrame
+ * should be called with the right data buffer and the captured data length input.
+ */
+status_t ENET_GetRxFrameSize(enet_handle_t *handle, uint32_t *length, uint8_t ringId);
+
+/*!
+ * @brief Reads a frame from the ENET device.
+ * This function reads a frame (both the data and the length) from the ENET buffer descriptors.
+ * User can get timestamp through ts pointer if the ts is not NULL.
+ * @note It doesn't store the timestamp in the receive timestamp queue.
+ * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer.
+ * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer
+ * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time
+ * consumption.
+ * This is an example:
+ * @code
+ * uint32_t length;
+ * enet_handle_t g_handle;
+ * Comments: Get the received frame size firstly.
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (length != 0)
+ * {
+ * Comments: Allocate memory here with the size of "length"
+ * uint8_t *data = memory allocate interface;
+ * if (!data)
+ * {
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * Comments: Add the console warning log.
+ * }
+ * else
+ * {
+ * status = ENET_ReadFrame(ENET, &g_handle, data, length, 0, NULL);
+ * Comments: Call stack input API to deliver the data to stack
+ * }
+ * }
+ * else if (status == kStatus_ENET_RxFrameError)
+ * {
+ * Comments: Update the received buffer when a error frame is received.
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * }
+ * @endcode
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * @param data The data buffer provided by user to store the frame which memory size should be at least "length".
+ * @param length The size of the data buffer which is still the length of the received frame.
+ * @param ringId The ring index or ring number.
+ * @param ts The timestamp address to store received timestamp.
+ * @return The execute status, successful or failure.
+ */
+status_t ENET_ReadFrame(
+ ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t ringId, uint32_t *ts);
+
+/*!
+ * @brief Transmits an ENET frame for specified ring.
+ * @note The CRC is automatically appended to the data. Input the data to send without the CRC.
+ * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer
+ * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time
+ * consumption.
+ *
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param data The data buffer provided by user to send.
+ * @param length The length of the data to send.
+ * @param ringId The ring index or ring number.
+ * @param tsFlag Timestamp enable flag.
+ * @param context Used by user to handle some events after transmit over.
+ * @retval kStatus_Success Send frame succeed.
+ * @retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ * The waiting mechanism is recommended to be added after each call return with
+ * kStatus_ENET_TxFrameBusy.
+ */
+status_t ENET_SendFrame(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context);
+
+/*!
+ * @brief Enable or disable tx descriptors reclaim mechanism.
+ * @note This function must be called when no pending send frame action.
+ * Set enable if you want to reclaim context or timestamp in interrupt.
+ *
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param isEnable Enable or disable flag.
+ * @param ringId The ring index or ring number.
+ * @retval kStatus_Success Succeed to enable/disable Tx reclaim.
+ * @retval kStatus_Fail Fail to enable/disable Tx reclaim.
+ */
+status_t ENET_SetTxReclaim(enet_handle_t *handle, bool isEnable, uint8_t ringId);
+
+/*!
+ * @brief Reclaim tx descriptors.
+ * This function is used to update the tx descriptor status and
+ * store the tx timestamp when the 1588 feature is enabled.
+ * This is called by the transmit interupt IRQ handler after the
+ * complete of a frame transmission.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param ringId The ring index or ring number.
+ */
+void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId);
+
+/*!
+ * @brief Get a receive buffer pointer of the ENET device for specified ring.
+ * @deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame.
+ *
+ * This function can get the data address which stores frame. Then can analyze these data directly without doing any
+ * memory copy. When the frame locates in multiple BD buffer, need to repeat calling this function until isLastBuff=true
+ * (need to store the temp buf pointer everytime call this function). After finishing the analysis of this frame,
+ * call ENET_ReleaseRxBuffer to release rxbuff memory to DMA.
+ * This is an example:
+ * @code
+ * uint32_t length;
+ * uint8_t *buf = NULL;
+ * uint32_t data_len = 0;
+ * bool isLastBuff = false;
+ * enet_handle_t g_handle;
+ * status_t status;
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (length != 0)
+ * {
+ * ENET_GetRxBuffer(EXAMPLE_ENET, &g_handle, &buf, &data_len, 0, &isLastBuff, NULL);
+ * ENET_ReleaseRxBuffer(EXAMPLE_ENET, &g_handle, buf, 0);
+ * }
+ * @endcode
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * @param buffer The data buffer pointer to store the frame.
+ * @param length The size of the data buffer. If isLastBuff=false, it represents data length of this buffer. If
+ * isLastBuff=true, it represents data length of total frame.
+ * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ * @param isLastBuff The flag represents whether this buffer is the last buffer to store frame.
+ * @param ts The 1588 timestamp value, vaild in last buffer.
+ * @retval kStatus_Success Get receive buffer succeed.
+ * @retval kStatus_ENET_RxFrameFail Get receive buffer fails, it's owned by application, should wait app to release this
+ * buffer.
+ */
+status_t ENET_GetRxBuffer(ENET_Type *base,
+ enet_handle_t *handle,
+ void **buffer,
+ uint32_t *length,
+ uint8_t ringId,
+ bool *isLastBuff,
+ uint32_t *ts);
+
+/*!
+ * @brief Release receive buffer descriptor to DMA.
+ * @deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame.
+ *
+ * This function can release specified BD owned by application, meanwhile it may rearrange the BD to let the no-owned
+ * BDs always in back of the index of DMA transfer. So for the situation that releasing order is not same as the getting
+ * order, the rearrangement makes all ready BDs can be used by DMA.
+ * @note This function can't be interrupted by ENET_GetRxBuffer, so in application must make sure ENET_GetRxBuffer is
+ * called before or after this function. And this function itself isn't thread safe due to BD content exchanging.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * @param buffer The buffer address to store frame, using it to find the correspond BD and release it.
+ * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1).
+ */
+void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId);
+
+/*!
+ * @brief Receives one frame in specified BD ring with zero copy.
+ *
+ * This function will use the user-defined allocate and free callback. Every time application gets one frame through
+ * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application.
+ * @note This function will drop current frame and update related BDs as available for DMA if new buffers allocating
+ * fails. Application must provide a memory pool including at least BD number + 1 buffers to make this function work
+ * normally. If user calls this function in Rx interrupt handler, be careful that this function makes Rx BD ready with
+ * allocating new buffer(normal) or updating current BD(out of memory). If there's always new Rx frame input, Rx
+ * interrupt will be triggered forever. Application need to disable Rx interrupt according to specific design in this
+ * case.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param rxFrame The received frame information structure provided by user.
+ * @param ringId The ring index or ring number.
+ * @retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer.
+ * @retval kStatus_ENET_RxFrameEmpty There's no Rx frame in the BD.
+ * @retval kStatus_ENET_RxFrameError There's issue in this receiving.
+ * @retval kStatus_ENET_RxFrameDrop There's no new buffer memory for BD, drop this frame.
+ */
+status_t ENET_GetRxFrame(ENET_Type *base, enet_handle_t *handle, enet_rx_frame_struct_t *rxFrame, uint8_t ringId);
+
+/*!
+ * @brief Sends one frame in specified BD ring with zero copy.
+ *
+ * This function supports scattered buffer transmit, user needs to provide the buffer array.
+ * @note Tx reclaim should be enabled to ensure the Tx buffer ownership can be given back to
+ * application after Tx is over.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param txFrame The Tx frame structure.
+ * @param ringId The ring index or ring number.
+ * @retval kStatus_Success Succeed to send one frame.
+ * @retval kStatus_ENET_TxFrameBusy The BD is not ready for Tx or the reclaim operation still not finishs.
+ * @retval kStatus_ENET_TxFrameOverLen The Tx frame length is over max ethernet frame length.
+ */
+status_t ENET_StartTxFrame(ENET_Type *base, enet_handle_t *handle, enet_tx_frame_struct_t *txFrame, uint8_t ringId);
+
+/*!
+ * @brief Transmits an ENET frame for specified ring with zero-copy.
+ * @deprecated Do not use this function. It has been superseded by @ref ENET_StartTxFrame.
+ * @note The CRC is automatically appended to the data. Input the data
+ * to send without the CRC. The frame must store in continuous memory
+ * and need to check the buffer start address alignment based on your
+ * device, otherwise it has issue or can't get highest DMA transmit speed.
+ *
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * @param data The data buffer provided by user to send.
+ * @param length The length of the data to send.
+ * @param ringId The ring index or ring number.
+ * @param tsFlag Timestamp enable flag.
+ * @param context Used by user to handle some events after transmit over.
+ * @retval kStatus_Success Send frame succeed.
+ * @retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ * The waiting mechanism is recommended to be added after each call return with
+ * kStatus_ENET_TxFrameBusy.
+ */
+status_t ENET_SendFrameZeroCopy(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context);
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * @brief The transmit IRQ handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer.
+ * @param ringId The ring id or ring number.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId);
+
+/*!
+ * @brief The receive IRQ handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer.
+ * @param ringId The ring id or ring number.
+ */
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId);
+
+/*!
+ * @brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 1).
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_CommonFrame1IRQHandler(ENET_Type *base);
+
+/*!
+ * @brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 2).
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_CommonFrame2IRQHandler(ENET_Type *base);
+#else
+/*!
+ * @brief The transmit IRQ handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle);
+
+/*!
+ * @brief The receive IRQ handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer.
+ */
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+/*!
+ * @brief Some special IRQ handler including the error, mii, wakeup irq handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handler pointer.
+ */
+void ENET_ErrorIRQHandler(ENET_Type *base, enet_handle_t *handle);
+
+/*!
+ * @brief the common IRQ handler for the 1588 irq handler.
+ *
+ * This is used for the 1588 timer interrupt.
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_Ptp1588IRQHandler(ENET_Type *base);
+
+/*!
+ * @brief the common IRQ handler for the tx/rx/error etc irq handler.
+ *
+ * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0).
+ *
+ * @param base ENET peripheral base address.
+ */
+void ENET_CommonFrame0IRQHandler(ENET_Type *base);
+/* @} */
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * @name ENET PTP 1588 function operation
+ * @{
+ */
+void ENET_Ptp1588ConfigureHandler(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig);
+
+/*!
+ * @brief Configures the ENET PTP IEEE 1588 feature with the basic configuration.
+ * The function sets the clock for PTP 1588 timer and enables
+ * time stamp interrupts and transmit interrupts for PTP 1588 features.
+ * This API should be called when the 1588 feature is enabled
+ * or the ENET_ENHANCEDBUFFERDESCRIPTOR_MODE is defined.
+ * ENET_Init should be called before calling this API.
+ *
+ * @note The PTP 1588 time-stamp second increase though time-stamp interrupt handler
+ * and the transmit time-stamp store is done through transmit interrupt handler.
+ * As a result, the TS interrupt and TX interrupt are enabled when you call this API.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle ENET handler pointer.
+ * @param ptpConfig The ENET PTP1588 configuration.
+ */
+void ENET_Ptp1588Configure(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig);
+
+/*!
+ * @brief Starts the ENET PTP 1588 Timer.
+ * This function is used to initialize the PTP timer. After the PTP starts,
+ * the PTP timer starts running.
+ *
+ * @param base ENET peripheral base address.
+ * @param ptpClkSrc The clock source of the PTP timer.
+ */
+void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc);
+
+/*!
+ * @brief Stops the ENET PTP 1588 Timer.
+ * This function is used to stops the ENET PTP timer.
+ *
+ * @param base ENET peripheral base address.
+ */
+static inline void ENET_Ptp1588StopTimer(ENET_Type *base)
+{
+ /* Disable PTP timer and reset the timer. */
+ base->ATCR &= ~ENET_ATCR_EN_MASK;
+ base->ATCR |= ENET_ATCR_RESTART_MASK;
+}
+
+/*!
+ * @brief Adjusts the ENET PTP 1588 timer.
+ *
+ * @param base ENET peripheral base address.
+ * @param corrIncrease The correction increment value. This value is added every time the correction
+ * timer expires. A value less than the PTP timer frequency(1/ptpClkSrc) slows down the timer,
+ * a value greater than the 1/ptpClkSrc speeds up the timer.
+ * @param corrPeriod The PTP timer correction counter wrap-around value. This defines after how
+ * many timer clock the correction counter should be reset and trigger a correction
+ * increment on the timer. A value of 0 disables the correction counter and no correction occurs.
+ */
+void ENET_Ptp1588AdjustTimer(ENET_Type *base, uint32_t corrIncrease, uint32_t corrPeriod);
+
+/*!
+ * @brief Sets the ENET PTP 1588 timer channel mode.
+ *
+ * @param base ENET peripheral base address.
+ * @param channel The ENET PTP timer channel number.
+ * @param mode The PTP timer channel mode, see "enet_ptp_timer_channel_mode_t".
+ * @param intEnable Enables or disables the interrupt.
+ */
+static inline void ENET_Ptp1588SetChannelMode(ENET_Type *base,
+ enet_ptp_timer_channel_t channel,
+ enet_ptp_timer_channel_mode_t mode,
+ bool intEnable)
+{
+ uint32_t tcrReg = 0;
+
+ tcrReg = ENET_TCSR_TMODE(mode) | (intEnable ? ENET_TCSR_TIE_MASK : 0U);
+
+ /* Disable channel mode first. */
+ base->CHANNEL[channel].TCSR = 0;
+ base->CHANNEL[channel].TCSR = tcrReg;
+}
+
+#if defined(FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL) && FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL
+/*!
+ * @brief Sets ENET PTP 1588 timer channel mode pulse width.
+ *
+ * For the input "mode" in ENET_Ptp1588SetChannelMode, the kENET_PtpChannelPulseLowonCompare
+ * kENET_PtpChannelPulseHighonCompare only support the pulse width for one 1588 clock.
+ * this function is extended for control the pulse width from 1 to 32 1588 clock cycles.
+ * so call this function if you need to set the timer channel mode for
+ * kENET_PtpChannelPulseLowonCompare or kENET_PtpChannelPulseHighonCompare
+ * with pulse width more than one 1588 clock,
+ *
+ * @param base ENET peripheral base address.
+ * @param channel The ENET PTP timer channel number.
+ * @param isOutputLow True --- timer channel is configured for output compare
+ * pulse output low.
+ * false --- timer channel is configured for output compare
+ * pulse output high.
+ * @param pulseWidth The pulse width control value, range from 0 ~ 31.
+ * 0 --- pulse width is one 1588 clock cycle.
+ * 31 --- pulse width is thirty two 1588 clock cycles.
+ * @param intEnable Enables or disables the interrupt.
+ */
+static inline void ENET_Ptp1588SetChannelOutputPulseWidth(
+ ENET_Type *base, enet_ptp_timer_channel_t channel, bool isOutputLow, uint8_t pulseWidth, bool intEnable)
+{
+ uint32_t tcrReg;
+
+ tcrReg = ENET_TCSR_TIE(intEnable) | ENET_TCSR_TPWC(pulseWidth);
+
+ if (isOutputLow)
+ {
+ tcrReg |= ENET_TCSR_TMODE(kENET_PtpChannelPulseLowonCompare);
+ }
+ else
+ {
+ tcrReg |= ENET_TCSR_TMODE(kENET_PtpChannelPulseHighonCompare);
+ }
+
+ /* Disable channel mode first. */
+ base->CHANNEL[channel].TCSR = 0;
+ base->CHANNEL[channel].TCSR = tcrReg;
+}
+#endif /* FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL */
+
+/*!
+ * @brief Sets the ENET PTP 1588 timer channel comparison value.
+ *
+ * @param base ENET peripheral base address.
+ * @param channel The PTP timer channel, see "enet_ptp_timer_channel_t".
+ * @param cmpValue The compare value for the compare setting.
+ */
+static inline void ENET_Ptp1588SetChannelCmpValue(ENET_Type *base, enet_ptp_timer_channel_t channel, uint32_t cmpValue)
+{
+ base->CHANNEL[channel].TCCR = cmpValue;
+}
+
+/*!
+ * @brief Gets the ENET PTP 1588 timer channel status.
+ *
+ * @param base ENET peripheral base address.
+ * @param channel The IEEE 1588 timer channel number.
+ * @return True or false, Compare or capture operation status
+ */
+static inline bool ENET_Ptp1588GetChannelStatus(ENET_Type *base, enet_ptp_timer_channel_t channel)
+{
+ return (0U != (base->CHANNEL[channel].TCSR & ENET_TCSR_TF_MASK));
+}
+
+/*!
+ * @brief Clears the ENET PTP 1588 timer channel status.
+ *
+ * @param base ENET peripheral base address.
+ * @param channel The IEEE 1588 timer channel number.
+ */
+static inline void ENET_Ptp1588ClearChannelStatus(ENET_Type *base, enet_ptp_timer_channel_t channel)
+{
+ base->CHANNEL[channel].TCSR |= ENET_TCSR_TF_MASK;
+ base->TGSR = (1UL << (uint32_t)channel);
+}
+
+/*!
+ * @brief Get the ENET PTP 1588 timer global status.
+ *
+ * @param base ENET peripheral base address.
+ */
+static inline uint32_t ENET_Ptp1588GetGlobalStatus(ENET_Type *base)
+{
+ return base->TGSR;
+}
+
+/*!
+ * @brief Gets the current ENET time from the PTP 1588 timer.
+ * A variant of ENET_Ptp1588GetTimer() which does not disable interrupts.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * @param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime);
+
+/*!
+ * @brief Gets the current ENET time from the PTP 1588 timer.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * @param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime);
+
+/*!
+ * @brief Sets the ENET PTP 1588 timer to the assigned time.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * @param ptpTime The timer to be set to the PTP timer.
+ */
+void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime);
+
+/*!
+ * @brief The IEEE 1588 PTP time stamp interrupt handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ */
+void ENET_TimeStampIRQHandler(ENET_Type *base, enet_handle_t *handle);
+
+/* @} */
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_ENET_H_ */ \ No newline at end of file
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.c b/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.c
new file mode 100644
index 0000000000..593cf87a50
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_ewm.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.ewm"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Initializes the EWM peripheral.
+ *
+ * This function is used to initialize the EWM. After calling, the EWM
+ * runs immediately according to the configuration.
+ * Note that, except for the interrupt enable control bit, other control bits and registers are write once after a
+ * CPU reset. Modifying them more than once generates a bus transfer error.
+ *
+ * This is an example.
+ * code
+ * ewm_config_t config;
+ * EWM_GetDefaultConfig(&config);
+ * config.compareHighValue = 0xAAU;
+ * EWM_Init(ewm_base,&config);
+ * endcode
+ *
+ * param base EWM peripheral base address
+ * param config The configuration of the EWM
+ */
+void EWM_Init(EWM_Type *base, const ewm_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t value = 0U;
+
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif
+ value = EWM_CTRL_EWMEN(config->enableEwm) | EWM_CTRL_ASSIN(config->setInputAssertLogic) |
+ EWM_CTRL_INEN(config->enableEwmInput) | EWM_CTRL_INTEN(config->enableInterrupt);
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ base->CLKPRESCALER = config->prescaler;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ base->CLKCTRL = (uint8_t)config->clockSource;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+
+ base->CMPL = config->compareLowValue;
+ base->CMPH = config->compareHighValue;
+ base->CTRL = value;
+}
+
+/*!
+ * brief Deinitializes the EWM peripheral.
+ *
+ * This function is used to shut down the EWM.
+ *
+ * param base EWM peripheral base address
+ */
+void EWM_Deinit(EWM_Type *base)
+{
+ EWM_DisableInterrupts(base, (uint32_t)kEWM_InterruptEnable);
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif /* FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE */
+}
+
+/*!
+ * brief Initializes the EWM configuration structure.
+ *
+ * This function initializes the EWM configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * ewmConfig->enableEwm = true;
+ * ewmConfig->enableEwmInput = false;
+ * ewmConfig->setInputAssertLogic = false;
+ * ewmConfig->enableInterrupt = false;
+ * ewmConfig->ewm_lpo_clock_source_t = kEWM_LpoClockSource0;
+ * ewmConfig->prescaler = 0;
+ * ewmConfig->compareLowValue = 0;
+ * ewmConfig->compareHighValue = 0xFEU;
+ * endcode
+ *
+ * param config Pointer to the EWM configuration structure.
+ * see ewm_config_t
+ */
+void EWM_GetDefaultConfig(ewm_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableEwm = true;
+ config->enableEwmInput = false;
+ config->setInputAssertLogic = false;
+ config->enableInterrupt = false;
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ config->clockSource = kEWM_LpoClockSource0;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ config->prescaler = 0U;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+ config->compareLowValue = 0U;
+ config->compareHighValue = 0xFEU;
+}
+
+/*!
+ * brief Services the EWM.
+ *
+ * This function resets the EWM counter to zero.
+ *
+ * param base EWM peripheral base address
+ */
+void EWM_Refresh(EWM_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->SERV = (uint8_t)0xB4U;
+ base->SERV = (uint8_t)0x2CU;
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.h b/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.h
new file mode 100644
index 0000000000..dbef1b3d07
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ewm/fsl_ewm.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_EWM_H_
+#define _FSL_EWM_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup ewm
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief EWM driver version 2.0.3. */
+#define FSL_EWM_DRIVER_VERSION (MAKE_VERSION(2, 0, 3))
+/*@}*/
+
+/*! @brief Describes EWM clock source. */
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+typedef enum _ewm_lpo_clock_source
+{
+ kEWM_LpoClockSource0 = 0U, /*!< EWM clock sourced from lpo_clk[0]*/
+ kEWM_LpoClockSource1 = 1U, /*!< EWM clock sourced from lpo_clk[1]*/
+ kEWM_LpoClockSource2 = 2U, /*!< EWM clock sourced from lpo_clk[2]*/
+ kEWM_LpoClockSource3 = 3U, /*!< EWM clock sourced from lpo_clk[3]*/
+} ewm_lpo_clock_source_t;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT */
+
+/*!
+ * @brief Data structure for EWM configuration.
+ *
+ * This structure is used to configure the EWM.
+ */
+typedef struct _ewm_config
+{
+ bool enableEwm; /*!< Enable EWM module */
+ bool enableEwmInput; /*!< Enable EWM_in input */
+ bool setInputAssertLogic; /*!< EWM_in signal assertion state */
+ bool enableInterrupt; /*!< Enable EWM interrupt */
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ ewm_lpo_clock_source_t clockSource; /*!< Clock source select */
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT */
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ uint8_t prescaler; /*!< Clock prescaler value */
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+ uint8_t compareLowValue; /*!< Compare low-register value */
+ uint8_t compareHighValue; /*!< Compare high-register value */
+} ewm_config_t;
+
+/*!
+ * @brief EWM interrupt configuration structure with default settings all disabled.
+ *
+ * This structure contains the settings for all of EWM interrupt configurations.
+ */
+enum _ewm_interrupt_enable_t
+{
+ kEWM_InterruptEnable = EWM_CTRL_INTEN_MASK, /*!< Enable the EWM to generate an interrupt*/
+};
+
+/*!
+ * @brief EWM status flags.
+ *
+ * This structure contains the constants for the EWM status flags for use in the EWM functions.
+ */
+enum _ewm_status_flags_t
+{
+ kEWM_RunningFlag = EWM_CTRL_EWMEN_MASK, /*!< Running flag, set when EWM is enabled*/
+};
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name EWM initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the EWM peripheral.
+ *
+ * This function is used to initialize the EWM. After calling, the EWM
+ * runs immediately according to the configuration.
+ * Note that, except for the interrupt enable control bit, other control bits and registers are write once after a
+ * CPU reset. Modifying them more than once generates a bus transfer error.
+ *
+ * This is an example.
+ * @code
+ * ewm_config_t config;
+ * EWM_GetDefaultConfig(&config);
+ * config.compareHighValue = 0xAAU;
+ * EWM_Init(ewm_base,&config);
+ * @endcode
+ *
+ * @param base EWM peripheral base address
+ * @param config The configuration of the EWM
+ */
+void EWM_Init(EWM_Type *base, const ewm_config_t *config);
+
+/*!
+ * @brief Deinitializes the EWM peripheral.
+ *
+ * This function is used to shut down the EWM.
+ *
+ * @param base EWM peripheral base address
+ */
+void EWM_Deinit(EWM_Type *base);
+
+/*!
+ * @brief Initializes the EWM configuration structure.
+ *
+ * This function initializes the EWM configuration structure to default values. The default
+ * values are as follows.
+ * @code
+ * ewmConfig->enableEwm = true;
+ * ewmConfig->enableEwmInput = false;
+ * ewmConfig->setInputAssertLogic = false;
+ * ewmConfig->enableInterrupt = false;
+ * ewmConfig->ewm_lpo_clock_source_t = kEWM_LpoClockSource0;
+ * ewmConfig->prescaler = 0;
+ * ewmConfig->compareLowValue = 0;
+ * ewmConfig->compareHighValue = 0xFEU;
+ * @endcode
+ *
+ * @param config Pointer to the EWM configuration structure.
+ * @see ewm_config_t
+ */
+void EWM_GetDefaultConfig(ewm_config_t *config);
+
+/* @} */
+
+/*!
+ * @name EWM functional Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables the EWM interrupt.
+ *
+ * This function enables the EWM interrupt.
+ *
+ * @param base EWM peripheral base address
+ * @param mask The interrupts to enable
+ * The parameter can be combination of the following source if defined
+ * @arg kEWM_InterruptEnable
+ */
+static inline void EWM_EnableInterrupts(EWM_Type *base, uint32_t mask)
+{
+ base->CTRL |= (uint8_t)mask;
+}
+
+/*!
+ * @brief Disables the EWM interrupt.
+ *
+ * This function enables the EWM interrupt.
+ *
+ * @param base EWM peripheral base address
+ * @param mask The interrupts to disable
+ * The parameter can be combination of the following source if defined
+ * @arg kEWM_InterruptEnable
+ */
+static inline void EWM_DisableInterrupts(EWM_Type *base, uint32_t mask)
+{
+ base->CTRL &= (uint8_t)(~mask);
+}
+
+/*!
+ * @brief Gets all status flags.
+ *
+ * This function gets all status flags.
+ *
+ * This is an example for getting the running flag.
+ * @code
+ * uint32_t status;
+ * status = EWM_GetStatusFlags(ewm_base) & kEWM_RunningFlag;
+ * @endcode
+ * @param base EWM peripheral base address
+ * @return State of the status flag: asserted (true) or not-asserted (false).@see _ewm_status_flags_t
+ * - True: a related status flag has been set.
+ * - False: a related status flag is not set.
+ */
+static inline uint32_t EWM_GetStatusFlags(EWM_Type *base)
+{
+ return ((uint32_t)base->CTRL & EWM_CTRL_EWMEN_MASK);
+}
+
+/*!
+ * @brief Services the EWM.
+ *
+ * This function resets the EWM counter to zero.
+ *
+ * @param base EWM peripheral base address
+ */
+void EWM_Refresh(EWM_Type *base);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/
+
+#endif /* _FSL_EWM_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.c
new file mode 100644
index 0000000000..280a472e65
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.c
@@ -0,0 +1,4613 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2023 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexcan.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexcan"
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+#define RXINTERMISSION (CAN_DBG1_CFSM(0x2f))
+#define TXINTERMISSION (CAN_DBG1_CFSM(0x14))
+#define BUSIDLE (CAN_DBG1_CFSM(0x02))
+#define CBN_VALUE3 (CAN_DBG1_CBN(0x03))
+#define DELAY_BUSIDLE (200)
+#endif
+
+/* According to CiA doc 1301 v1.0.0, specified data/nominal phase sample point postion for CAN FD at 80 MHz. */
+#define IDEAL_DATA_SP_1 (800U)
+#define IDEAL_DATA_SP_2 (750U)
+#define IDEAL_DATA_SP_3 (700U)
+#define IDEAL_DATA_SP_4 (625U)
+#define IDEAL_NOMINAL_SP (800U)
+
+/* According to CiA doc 301 v4.2.0 and previous version. */
+#define IDEAL_SP_LOW (750U)
+#define IDEAL_SP_MID (800U)
+#define IDEAL_SP_HIGH (875U)
+
+#define IDEAL_SP_FACTOR (1000U)
+
+/* Define the max value of bit timing segments when use different timing register. */
+#define MAX_PROPSEG (CAN_CTRL1_PROPSEG_MASK >> CAN_CTRL1_PROPSEG_SHIFT)
+#define MAX_PSEG1 (CAN_CTRL1_PSEG1_MASK >> CAN_CTRL1_PSEG1_SHIFT)
+#define MAX_PSEG2 (CAN_CTRL1_PSEG2_MASK >> CAN_CTRL1_PSEG2_SHIFT)
+#define MAX_RJW (CAN_CTRL1_RJW_MASK >> CAN_CTRL1_RJW_SHIFT)
+#define MAX_PRESDIV (CAN_CTRL1_PRESDIV_MASK >> CAN_CTRL1_PRESDIV_SHIFT)
+#define CTRL1_MAX_TIME_QUANTA (1U + MAX_PROPSEG + 1U + MAX_PSEG1 + 1U + MAX_PSEG2 + 1U)
+#define CTRL1_MIN_TIME_QUANTA (8U)
+
+#define MAX_EPROPSEG (CAN_CBT_EPROPSEG_MASK >> CAN_CBT_EPROPSEG_SHIFT)
+#define MAX_EPSEG1 (CAN_CBT_EPSEG1_MASK >> CAN_CBT_EPSEG1_SHIFT)
+#define MAX_EPSEG2 (CAN_CBT_EPSEG2_MASK >> CAN_CBT_EPSEG2_SHIFT)
+#define MAX_ERJW (CAN_CBT_ERJW_MASK >> CAN_CBT_ERJW_SHIFT)
+#define MAX_EPRESDIV (CAN_CBT_EPRESDIV_MASK >> CAN_CBT_EPRESDIV_SHIFT)
+#define CBT_MAX_TIME_QUANTA (1U + MAX_EPROPSEG + 1U + MAX_EPSEG1 + 1U + MAX_EPSEG2 + 1U)
+#define CBT_MIN_TIME_QUANTA (8U)
+
+#define MAX_FPROPSEG (CAN_FDCBT_FPROPSEG_MASK >> CAN_FDCBT_FPROPSEG_SHIFT)
+#define MAX_FPSEG1 (CAN_FDCBT_FPSEG1_MASK >> CAN_FDCBT_FPSEG1_SHIFT)
+#define MAX_FPSEG2 (CAN_FDCBT_FPSEG2_MASK >> CAN_FDCBT_FPSEG2_SHIFT)
+#define MAX_FRJW (CAN_FDCBT_FRJW_MASK >> CAN_FDCBT_FRJW_SHIFT)
+#define MAX_FPRESDIV (CAN_FDCBT_FPRESDIV_MASK >> CAN_FDCBT_FPRESDIV_SHIFT)
+#define FDCBT_MAX_TIME_QUANTA (1U + MAX_FPROPSEG + 0U + MAX_FPSEG1 + 1U + MAX_FPSEG2 + 1U)
+#define FDCBT_MIN_TIME_QUANTA (5U)
+
+#define MAX_TDCOFF ((uint32_t)CAN_FDCTRL_TDCOFF_MASK >> CAN_FDCTRL_TDCOFF_SHIFT)
+
+#define MAX_NTSEG1 (CAN_ENCBT_NTSEG1_MASK >> CAN_ENCBT_NTSEG1_SHIFT)
+#define MAX_NTSEG2 (CAN_ENCBT_NTSEG2_MASK >> CAN_ENCBT_NTSEG2_SHIFT)
+#define MAX_NRJW (CAN_ENCBT_NRJW_MASK >> CAN_ENCBT_NRJW_SHIFT)
+#define MAX_ENPRESDIV (CAN_EPRS_ENPRESDIV_MASK >> CAN_EPRS_ENPRESDIV_SHIFT)
+#define ENCBT_MAX_TIME_QUANTA (1U + MAX_NTSEG1 + 1U + MAX_NTSEG2 + 1U)
+#define ENCBT_MIN_TIME_QUANTA (8U)
+
+#define MAX_DTSEG1 (CAN_EDCBT_DTSEG1_MASK >> CAN_EDCBT_DTSEG1_SHIFT)
+#define MAX_DTSEG2 (CAN_EDCBT_DTSEG2_MASK >> CAN_EDCBT_DTSEG2_SHIFT)
+#define MAX_DRJW (CAN_EDCBT_DRJW_MASK >> CAN_EDCBT_DRJW_SHIFT)
+#define MAX_EDPRESDIV (CAN_EPRS_EDPRESDIV_MASK >> CAN_EPRS_EDPRESDIV_SHIFT)
+#define EDCBT_MAX_TIME_QUANTA (1U + MAX_DTSEG1 + 1U + MAX_DTSEG2 + 1U)
+#define EDCBT_MIN_TIME_QUANTA (5U)
+
+#define MAX_ETDCOFF ((uint32_t)CAN_ETDC_ETDCOFF_MASK >> CAN_ETDC_ETDCOFF_SHIFT)
+
+/* TSEG1 corresponds to the sum of xPROPSEG and xPSEG1, TSEG2 corresponds to the xPSEG2 value. */
+#define MIN_TIME_SEGMENT1 (2U)
+#define MIN_TIME_SEGMENT2 (2U)
+
+/* Define maximum CAN and CAN FD bit rate supported by FLEXCAN. */
+#define MAX_CANFD_BITRATE (8000000U)
+#define MAX_CAN_BITRATE (1000000U)
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595)
+#define CAN_ESR1_FLTCONF_BUSOFF CAN_ESR1_FLTCONF(2U)
+#endif
+
+/* Define the range of memory that needs to be initialized when the device has memory error detection feature. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+#define CAN_INIT_RXFIR ((uintptr_t)base + 0x4Cu)
+#define CAN_INIT_MEMORY_BASE_1 (uint32_t *)((uintptr_t)base + (uintptr_t)FSL_FEATURE_FLEXCAN_INIT_MEMORY_BASE_1)
+#define CAN_INIT_MEMORY_SIZE_1 FSL_FEATURE_FLEXCAN_INIT_MEMORY_SIZE_1
+#define CAN_INIT_MEMORY_BASE_2 (uint32_t *)((uintptr_t)base + (uintptr_t)FSL_FEATURE_FLEXCAN_INIT_MEMORY_BASE_2)
+#define CAN_INIT_MEMORY_SIZE_2 FSL_FEATURE_FLEXCAN_INIT_MEMORY_SIZE_2
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#ifndef CAN_CLOCK_CHECK_NO_AFFECTS
+/* If no define such MACRO, it mean that the CAN in current device have no clock affect issue. */
+#define CAN_CLOCK_CHECK_NO_AFFECTS (true)
+#endif /* CAN_CLOCK_CHECK_NO_AFFECTS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief FlexCAN Internal State. */
+enum _flexcan_state
+{
+ kFLEXCAN_StateIdle = 0x0, /*!< MB/RxFIFO idle.*/
+ kFLEXCAN_StateRxData = 0x1, /*!< MB receiving.*/
+ kFLEXCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
+ kFLEXCAN_StateTxData = 0x3, /*!< MB transmitting.*/
+ kFLEXCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
+ kFLEXCAN_StateRxFifo = 0x5, /*!< RxFIFO receiving.*/
+};
+
+/*! @brief FlexCAN message buffer CODE for Rx buffers. */
+enum _flexcan_mb_code_rx
+{
+ kFLEXCAN_RxMbInactive = 0x0, /*!< MB is not active.*/
+ kFLEXCAN_RxMbFull = 0x2, /*!< MB is full.*/
+ kFLEXCAN_RxMbEmpty = 0x4, /*!< MB is active and empty.*/
+ kFLEXCAN_RxMbOverrun = 0x6, /*!< MB is overwritten into a full buffer.*/
+ kFLEXCAN_RxMbBusy = 0x8, /*!< FlexCAN is updating the contents of the MB, The CPU must not access the MB.*/
+ kFLEXCAN_RxMbRanswer = 0xA, /*!< A frame was configured to recognize a Remote Request Frame and transmit a
+ Response Frame in return.*/
+ kFLEXCAN_RxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/*! @brief FlexCAN message buffer CODE FOR Tx buffers. */
+enum _flexcan_mb_code_tx
+{
+ kFLEXCAN_TxMbInactive = 0x8, /*!< MB is not active.*/
+ kFLEXCAN_TxMbAbort = 0x9, /*!< MB is aborted.*/
+ kFLEXCAN_TxMbDataOrRemote = 0xC, /*!< MB is a TX Data Frame(when MB RTR = 0) or MB is a TX Remote Request
+ Frame (when MB RTR = 1).*/
+ kFLEXCAN_TxMbTanswer = 0xE, /*!< MB is a TX Response Request Frame from an incoming Remote Request Frame.*/
+ kFLEXCAN_TxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*flexcan_isr_t)(CAN_Type *base, flexcan_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if !defined(NDEBUG)
+/*!
+ * @brief Check if Message Buffer is occupied by Rx FIFO.
+ *
+ * This function check if Message Buffer is occupied by Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @return TRUE if the index MB is occupied by Rx FIFO, FALSE if the index MB not occupied by Rx FIFO.
+ */
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx);
+#endif
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+/*!
+ * @brief Get the first valid Message buffer ID of give FlexCAN instance.
+ *
+ * This function is a helper function for Errata 5641 workaround.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return The first valid Message Buffer Number.
+ */
+static uint8_t FLEXCAN_GetFirstValidMb(CAN_Type *base);
+#endif
+
+/*!
+ * @brief Reset the FlexCAN Instance.
+ *
+ * Restores the FlexCAN module to reset state, notice that this function
+ * will set all the registers to reset state so the FlexCAN module can not work
+ * after calling this API.
+ *
+ * @param base FlexCAN peripheral base address.
+ */
+static void FLEXCAN_Reset(CAN_Type *base);
+
+/*!
+ * @brief Calculates the segment values for a single bit time for classical CAN.
+ *
+ * This function use to calculates the Classical CAN segment values which will be set in CTRL1/CBT/ENCBT register.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param tqNum Number of time quantas per bit, range in 8 ~ 25 when use CTRL1, range in 8 ~ 129 when use CBT, range in
+ * 8 ~ 385 when use ENCBT. param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ */
+static void FLEXCAN_GetSegments(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t tqNum,
+ flexcan_timing_config_t *pTimingConfig);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Get Mailbox offset number by dword.
+ *
+ * This function gets the offset number of the specified mailbox.
+ * Mailbox is not consecutive between memory regions when payload is not 8 bytes
+ * so need to calculate the specified mailbox address.
+ * For example, in the first memory region, MB[0].CS address is 0x4002_4080. For 32 bytes
+ * payload frame, the second mailbox is ((1/12)*512 + 1%12*40)/4 = 10, meaning 10 dword
+ * after the 0x4002_4080, which is actually the address of mailbox MB[1].CS.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx Mailbox index.
+ */
+static uint32_t FLEXCAN_GetFDMailboxOffset(CAN_Type *base, uint8_t mbIdx);
+
+/*!
+ * @brief Calculates the segment values for a single bit time for CAN FD data phase.
+ *
+ * This function use to calculates the CAN FD data phase segment values which will be set in CFDCBT/EDCBT
+ * register.
+ *
+ * @param bitRateFD Data phase bit rate
+ * @param tqNum Number of time quanta per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ */
+static void FLEXCAN_FDGetSegments(uint32_t bitRateFD, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig);
+
+/*!
+ * @brief Calculates the improved timing values by specific bit rate for CAN FD nominal phase.
+ *
+ * This function use to calculates the CAN FD nominal phase timing values according to the given nominal phase bit rate.
+ * The Calculated timing values will be set in CBT/ENCBT registers. The calculation is based on the recommendation of
+ * the CiA 1301 v1.0.0 document.
+ *
+ * @param bitRate The CAN FD nominal phase speed in bps defined by user, should be less than or equal to 1Mbps.
+ * @param sourceClock_Hz The Source clock frequency in Hz.
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration.
+ */
+static bool FLEXCAN_CalculateImprovedNominalTimingValues(uint32_t bitRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig);
+
+#endif
+
+/*!
+ * @brief Check unhandle interrupt events
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return TRUE if unhandled interrupt action exist, FALSE if no unhandlered interrupt action exist.
+ */
+static bool FLEXCAN_CheckUnhandleInterruptEvents(CAN_Type *base);
+
+/*!
+ * @brief Sub Handler Data Trasfered Events
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pResult Pointer to the Handle result.
+ *
+ * @return the status after handle each data transfered event.
+ */
+static status_t FLEXCAN_SubHandlerForDataTransfered(CAN_Type *base, flexcan_handle_t *handle, uint32_t *pResult);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Sub Handler Ehanced Rx FIFO event
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param flags FlexCAN interrupt flags.
+ *
+ * @return the status after handle Ehanced Rx FIFO event.
+ */
+static status_t FLEXCAN_SubHandlerForEhancedRxFifo(CAN_Type *base, flexcan_handle_t *handle, uint64_t flags);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of FlexCAN peripheral base address. */
+static CAN_Type *const s_flexcanBases[] = CAN_BASE_PTRS;
+
+/* Array of FlexCAN IRQ number. */
+static const IRQn_Type s_flexcanRxWarningIRQ[] = CAN_Rx_Warning_IRQS;
+static const IRQn_Type s_flexcanTxWarningIRQ[] = CAN_Tx_Warning_IRQS;
+static const IRQn_Type s_flexcanWakeUpIRQ[] = CAN_Wake_Up_IRQS;
+static const IRQn_Type s_flexcanErrorIRQ[] = CAN_Error_IRQS;
+static const IRQn_Type s_flexcanBusOffIRQ[] = CAN_Bus_Off_IRQS;
+static const IRQn_Type s_flexcanMbIRQ[] = CAN_ORed_Message_buffer_IRQS;
+
+/* Array of FlexCAN handle. */
+static flexcan_handle_t *s_flexcanHandle[ARRAY_SIZE(s_flexcanBases)];
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of FlexCAN clock name. */
+static const clock_ip_name_t s_flexcanClock[] = FLEXCAN_CLOCKS;
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+/* Array of FlexCAN serial clock name. */
+static const clock_ip_name_t s_flexcanPeriphClock[] = FLEXCAN_PERIPH_CLOCKS;
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* FlexCAN ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static flexcan_isr_t s_flexcanIsr = (flexcan_isr_t)DefaultISR;
+#else
+static flexcan_isr_t s_flexcanIsr;
+#endif
+
+/*******************************************************************************
+ * Implementation of 32-bit memset
+ ******************************************************************************/
+
+static void flexcan_memset(void *s, uint32_t c, size_t n)
+{
+ size_t m;
+ uint32_t *ptr = s;
+
+ m = n / sizeof(*ptr);
+
+ while ((m--) != (size_t)0)
+ {
+ *ptr++ = c;
+ }
+}
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Get the FlexCAN instance from peripheral base address.
+ *
+ * param base FlexCAN peripheral base address.
+ * return FlexCAN instance.
+ */
+uint32_t FLEXCAN_GetInstance(CAN_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexcanBases); instance++)
+ {
+ if (s_flexcanBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexcanBases));
+
+ return instance;
+}
+
+/*!
+ * brief Enter FlexCAN Freeze Mode.
+ *
+ * This function makes the FlexCAN work under Freeze Mode.
+ *
+ * param base FlexCAN peripheral base address.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595)
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ uint32_t u32TimeoutCount = 0U;
+ uint32_t u32TempMCR = 0U;
+ uint32_t u32TempIMASK1 = 0U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint32_t u32TempIMASK2 = 0U;
+#endif
+
+ /* Step1: set FRZ enable in MCR. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+
+ /* Step2: to check if MDIS bit set in MCR. if yes, clear it. */
+ if (0U != (base->MCR & CAN_MCR_MDIS_MASK))
+ {
+ base->MCR &= ~CAN_MCR_MDIS_MASK;
+ }
+
+ /* Step3: polling LPMACK. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((0U == (base->MCR & CAN_MCR_LPMACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step4: to check FLTCONF in ESR1 register */
+ if (0U == (base->ESR1 & CAN_ESR1_FLTCONF_BUSOFF))
+ {
+ /* Step5B: Set Halt bits. */
+ base->MCR |= CAN_MCR_HALT_MASK;
+
+ /* Step6B: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set, timeout need more than 178
+ * CAN bit length, so 20 multiply timeout is enough. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT * 20U;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+ }
+ else
+ {
+ /* backup MCR and IMASK register. Errata document not descript it, but we need backup for step 8A and 9A. */
+ u32TempMCR = base->MCR;
+ u32TempIMASK1 = base->IMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ u32TempIMASK2 = base->IMASK2;
+#endif
+
+ /* Step5A: Set the Soft Reset bit ((SOFTRST) in the MCR.*/
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+
+ /* Step6A: Poll the MCR register until the Soft Reset (SOFTRST) bit is cleared. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((CAN_MCR_SOFTRST_MASK == (base->MCR & CAN_MCR_SOFTRST_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step7A: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step8A: reconfig MCR. */
+ base->MCR = u32TempMCR;
+
+ /* Step9A: reconfig IMASK. */
+ base->IMASK1 = u32TempIMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK2 = u32TempIMASK2;
+#endif
+ }
+}
+#elif (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_8341) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_8341)
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ uint32_t u32TimeoutCount = 0U;
+ uint32_t u32TempMCR = 0U;
+ uint32_t u32TempIMASK1 = 0U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint32_t u32TempIMASK2 = 0U;
+#endif
+
+ /* Step1: set FRZ and HALT bit enable in MCR. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+ base->MCR |= CAN_MCR_HALT_MASK;
+
+ /* Step2: to check if MDIS bit set in MCR. if yes, clear it. */
+ if (0U != (base->MCR & CAN_MCR_MDIS_MASK))
+ {
+ base->MCR &= ~CAN_MCR_MDIS_MASK;
+ }
+
+ /* Step3: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT * 100U;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step4: check whether the timeout reached. if no skip step5 to step8. */
+ if (0U == u32TimeoutCount)
+ {
+ /* backup MCR and IMASK register. Errata document not descript it, but we need backup for step 8A and 9A. */
+ u32TempMCR = base->MCR;
+ u32TempIMASK1 = base->IMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ u32TempIMASK2 = base->IMASK2;
+#endif
+ /* Step5: Set the Soft Reset bit ((SOFTRST) in the MCR.*/
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+
+ /* Step6: Poll the MCR register until the Soft Reset (SOFTRST) bit is cleared. */
+ while (CAN_MCR_SOFTRST_MASK == (base->MCR & CAN_MCR_SOFTRST_MASK))
+ {
+ }
+
+ /* Step7: reconfig MCR. */
+ base->MCR = u32TempMCR;
+
+ /* Step8: reconfig IMASK. */
+ base->IMASK1 = u32TempIMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK2 = u32TempIMASK2;
+#endif
+ }
+}
+#else
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ /* Set Freeze, Halt bits. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+ base->MCR |= CAN_MCR_HALT_MASK;
+ while (0U == (base->MCR & CAN_MCR_FRZACK_MASK))
+ {
+ }
+}
+#endif
+
+/*!
+ * brief Exit FlexCAN Freeze Mode.
+ *
+ * This function makes the FlexCAN leave Freeze Mode.
+ *
+ * param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_ExitFreezeMode(CAN_Type *base)
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Clean FlexCAN Access With Non-Correctable Error Interrupt Flag to avoid be put in freeze mode. */
+ FLEXCAN_ClearStatusFlags(base, (uint64_t)kFLEXCAN_FlexCanAccessNonCorrectableErrorIntFlag |
+ (uint64_t)kFLEXCAN_FlexCanAccessNonCorrectableErrorOverrunFlag);
+#endif
+
+ /* Clear Freeze, Halt bits. */
+ base->MCR &= ~CAN_MCR_HALT_MASK;
+ base->MCR &= ~CAN_MCR_FRZ_MASK;
+
+ /* Wait until the FlexCAN Module exit freeze mode. */
+ while (0U != (base->MCR & CAN_MCR_FRZACK_MASK))
+ {
+ }
+}
+
+#if !defined(NDEBUG)
+/*!
+ * brief Check if Message Buffer is occupied by Rx FIFO.
+ *
+ * This function check if Message Buffer is occupied by Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * return TRUE if the index MB is occupied by Rx FIFO, FALSE if the index MB not occupied by Rx FIFO.
+ */
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx)
+{
+ uint8_t lastOccupiedMb;
+ bool fgRet;
+
+ /* Is Rx FIFO enabled? */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Get RFFN value. */
+ lastOccupiedMb = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ /* Calculate the number of last Message Buffer occupied by Rx FIFO. */
+ lastOccupiedMb = ((lastOccupiedMb + 1U) * 2U) + 5U;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ /* the first valid MB should be occupied by ERRATA 5461 or 5829. */
+ lastOccupiedMb += 1U;
+#endif
+ fgRet = (mbIdx <= lastOccupiedMb);
+ }
+ else
+ {
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ if (0U == mbIdx)
+ {
+ fgRet = true;
+ }
+ else
+#endif
+ {
+ fgRet = false;
+ }
+ }
+
+ return fgRet;
+}
+#endif
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+/*!
+ * brief Get the first valid Message buffer ID of give FlexCAN instance.
+ *
+ * This function is a helper function for Errata 5641 workaround.
+ *
+ * param base FlexCAN peripheral base address.
+ * return The first valid Message Buffer Number.
+ */
+static uint8_t FLEXCAN_GetFirstValidMb(CAN_Type *base)
+{
+ uint8_t firstValidMbNum;
+
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ firstValidMbNum = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ firstValidMbNum = ((firstValidMbNum + 1U) * 2U) + 6U;
+ }
+ else
+ {
+ firstValidMbNum = 0U;
+ }
+
+ return firstValidMbNum;
+}
+#endif
+
+/*!
+ * brief Reset the FlexCAN Instance.
+ *
+ * Restores the FlexCAN module to reset state, notice that this function
+ * will set all the registers to reset state so the FlexCAN module can not work
+ * after calling this API.
+ *
+ * param base FlexCAN peripheral base address.
+ */
+static void FLEXCAN_Reset(CAN_Type *base)
+{
+ /* The module must should be first exit from low power
+ * mode, and then soft reset can be applied.
+ */
+ assert(0U == (base->MCR & CAN_MCR_MDIS_MASK));
+
+ uint8_t i;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ if (0 != (FSL_FEATURE_FLEXCAN_INSTANCE_HAS_DOZE_MODE_SUPPORTn(base)))
+ {
+ /* De-assert DOZE Enable Bit. */
+ base->MCR &= ~CAN_MCR_DOZE_MASK;
+ }
+#endif
+
+ /* Wait until FlexCAN exit from any Low Power Mode. */
+ while (0U != (base->MCR & CAN_MCR_LPMACK_MASK))
+ {
+ }
+
+ /* Assert Soft Reset Signal. */
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+ /* Wait until FlexCAN reset completes. */
+ while (0U != (base->MCR & CAN_MCR_SOFTRST_MASK))
+ {
+ }
+
+/* Reset MCR register. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER) && FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER)
+ base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_WAKSRC_MASK |
+ CAN_MCR_MAXMB((uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1U);
+#else
+ base->MCR |=
+ CAN_MCR_WRNEN_MASK | CAN_MCR_MAXMB((uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1U);
+#endif
+
+ /* Reset CTRL1 and CTRL2 register, default to eanble SMP feature which enable three sample point to determine the
+ * received bit's value of the. */
+ base->CTRL1 = CAN_CTRL1_SMP_MASK;
+ base->CTRL2 = CAN_CTRL2_TASD(0x16) | CAN_CTRL2_RRS_MASK | CAN_CTRL2_EACEN_MASK;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Enable unrestricted write access to FlexCAN memory. */
+ base->CTRL2 |= CAN_CTRL2_WRMFRZ_MASK;
+ /* Do memory initialization for all FlexCAN RAM in order to have the parity bits in memory properly
+ updated. */
+ *(volatile uint32_t *)CAN_INIT_RXFIR = 0x0U;
+ flexcan_memset(CAN_INIT_MEMORY_BASE_1, 0, CAN_INIT_MEMORY_SIZE_1);
+ flexcan_memset(CAN_INIT_MEMORY_BASE_2, 0, CAN_INIT_MEMORY_SIZE_2);
+ /* Disable unrestricted write access to FlexCAN memory. */
+ base->CTRL2 &= ~CAN_CTRL2_WRMFRZ_MASK;
+
+ /* Clean all memory error flags. */
+ FLEXCAN_ClearStatusFlags(base, (uint64_t)kFLEXCAN_AllMemoryErrorFlag);
+#else
+ /* Only need clean all Message Buffer memory. */
+ flexcan_memset((void *)&base->MB[0], 0, sizeof(base->MB));
+#endif
+
+ /* Clean all individual Rx Mask of Message Buffers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); i++)
+ {
+ base->RXIMR[i] = 0x3FFFFFFF;
+ }
+
+ /* Clean Global Mask of Message Buffers. */
+ base->RXMGMASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 14. */
+ base->RX14MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 15. */
+ base->RX15MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Rx FIFO. */
+ base->RXFGMASK = 0x3FFFFFFF;
+}
+
+/*!
+ * brief Set bit rate of FlexCAN classical CAN frame or CAN FD frame nominal phase.
+ *
+ * This function set the bit rate of classical CAN frame or CAN FD frame nominal phase base on
+ * FLEXCAN_CalculateImprovedTimingValues() API calculated timing values.
+ *
+ * note Calling FLEXCAN_SetBitRate() overrides the bit rate set in FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param sourceClock_Hz Source Clock in Hz.
+ * param bitRate_Bps Bit rate in Bps.
+ * return kStatus_Success - Set CAN baud rate (only Nominal phase) successfully.
+ */
+status_t FLEXCAN_SetBitRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t bitRate_Bps)
+{
+ flexcan_timing_config_t timingCfg;
+ status_t result = kStatus_Fail;
+
+ if (FLEXCAN_CalculateImprovedTimingValues(base, bitRate_Bps, sourceClock_Hz, &timingCfg))
+ {
+ FLEXCAN_SetTimingConfig(base, &timingCfg);
+ result = kStatus_Success;
+ }
+
+ return result;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Set bit rate of FlexCAN FD frame.
+ *
+ * This function set the baud rate of FLEXCAN FD base on FLEXCAN_FDCalculateImprovedTimingValues() API calculated timing
+ * values.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param bitRateN_Bps Nominal bit Rate in Bps.
+ * @param bitRateD_Bps Data bit Rate in Bps.
+ * @return kStatus_Success - Set CAN FD bit rate (include Nominal and Data phase) successfully.
+ */
+status_t FLEXCAN_SetFDBitRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t bitRateN_Bps, uint32_t bitRateD_Bps)
+{
+ flexcan_timing_config_t timingCfg;
+ status_t result = kStatus_Fail;
+
+ if (FLEXCAN_FDCalculateImprovedTimingValues(base, bitRateN_Bps, bitRateD_Bps, sourceClock_Hz, &timingCfg))
+ {
+ FLEXCAN_SetFDTimingConfig(base, &timingCfg);
+ result = kStatus_Success;
+ }
+
+ return result;
+}
+#endif
+
+/*!
+ * brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_Init function by passing in these parameters.
+ * code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.bitRate = 1000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_Init(CAN0, &flexcanConfig, 40000000UL);
+ * endcode
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the user-defined configuration structure.
+ * param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ */
+void FLEXCAN_Init(CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+ assert((pConfig->maxMbNum > 0U) &&
+ (pConfig->maxMbNum <= (uint8_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)));
+
+ uint32_t mcrTemp;
+ uint32_t ctrl1Temp;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+ flexcan_timing_config_t timingCfg = pConfig->timingConfig;
+ /* FlexCAN classical CAN frame or CAN FD frame nominal phase timing setting formula:
+ * quantum = 1 + (phaseSeg1 + 1) + (phaseSeg2 + 1) + (propSeg + 1);
+ */
+ uint32_t quantum = (1U + ((uint32_t)timingCfg.phaseSeg1 + 1U) + ((uint32_t)timingCfg.phaseSeg2 + 1U) +
+ ((uint32_t)timingCfg.propSeg + 1U));
+ uint32_t tqFre = pConfig->bitRate * quantum;
+ uint16_t maxDivider;
+
+ /* Assertion: Check bit rate value. */
+ assert((pConfig->bitRate != 0U) && (pConfig->bitRate <= 1000000U) && (tqFre <= sourceClock_Hz));
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ assert((tqFre * MAX_ENPRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_ENPRESDIV;
+#else
+ assert((tqFre * MAX_EPRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_EPRESDIV;
+#endif
+ }
+ else
+ {
+ assert((tqFre * MAX_PRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_PRESDIV;
+ }
+#else
+ assert((tqFre * MAX_PRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_PRESDIV;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+ /* Enable FlexCAN clock. */
+ (void)CLOCK_EnableClock(s_flexcanClock[instance]);
+ /*
+ * Check the CAN clock in this device whether affected by Other clock gate
+ * If it affected, we'd better to change other clock source,
+ * If user insist on using that clock source, user need open these gate at same time,
+ * In this scene, User need to care the power consumption.
+ */
+ assert(CAN_CLOCK_CHECK_NO_AFFECTS);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Enable FlexCAN serial clock. */
+ (void)CLOCK_EnableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(CAN_CTRL1_CLKSRC_MASK)
+#if (defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE) && FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)
+ if (0 == FSL_FEATURE_FLEXCAN_INSTANCE_SUPPORT_ENGINE_CLK_SEL_REMOVEn(base))
+#endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */
+ {
+ /* Disable FlexCAN Module. */
+ FLEXCAN_Enable(base, false);
+
+ /* Protocol-Engine clock source selection, This bit must be set
+ * when FlexCAN Module in Disable Mode.
+ */
+ base->CTRL1 = (kFLEXCAN_ClkSrc0 == pConfig->clkSrc) ? (base->CTRL1 & ~CAN_CTRL1_CLKSRC_MASK) :
+ (base->CTRL1 | CAN_CTRL1_CLKSRC_MASK);
+ }
+#endif /* CAN_CTRL1_CLKSRC_MASK */
+
+ /* Enable FlexCAN Module for configuration. */
+ FLEXCAN_Enable(base, true);
+
+ /* Reset to known status. */
+ FLEXCAN_Reset(base);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Enable to update in MCER. */
+ base->CTRL2 |= CAN_CTRL2_ECRWRE_MASK;
+ base->MECR &= ~CAN_MECR_ECRWRDIS_MASK;
+
+ /* Enable/Disable Memory Error Detection and Correction.*/
+ base->MECR = (pConfig->enableMemoryErrorControl) ? (base->MECR & ~CAN_MECR_ECCDIS_MASK) :
+ (base->MECR | CAN_MECR_ECCDIS_MASK);
+
+ /* Enable/Disable Non-Correctable Errors In FlexCAN Access Put Device In Freeze Mode. */
+ base->MECR = (pConfig->enableNonCorrectableErrorEnterFreeze) ? (base->MECR | CAN_MECR_NCEFAFRZ_MASK) :
+ (base->MECR & ~CAN_MECR_NCEFAFRZ_MASK);
+ /* Lock MCER register. */
+ base->CTRL2 &= ~CAN_CTRL2_ECRWRE_MASK;
+#endif
+
+ /* Save current CTRL1 value and enable to enter Freeze mode(enabled by default). */
+ ctrl1Temp = base->CTRL1;
+
+ /* Save current MCR value and enable to enter Freeze mode(enabled by default). */
+ mcrTemp = base->MCR;
+
+ /* Enable Loop Back Mode? */
+ ctrl1Temp = (pConfig->enableLoopBack) ? (ctrl1Temp | CAN_CTRL1_LPB_MASK) : (ctrl1Temp & ~CAN_CTRL1_LPB_MASK);
+
+ /* Enable Timer Sync? */
+ ctrl1Temp = (pConfig->enableTimerSync) ? (ctrl1Temp | CAN_CTRL1_TSYN_MASK) : (ctrl1Temp & ~CAN_CTRL1_TSYN_MASK);
+
+ /* Enable Listen Only Mode? */
+ ctrl1Temp = (pConfig->enableListenOnlyMode) ? ctrl1Temp | CAN_CTRL1_LOM_MASK : ctrl1Temp & ~CAN_CTRL1_LOM_MASK;
+
+#if !(defined(FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT)
+ /* Enable Supervisor Mode? */
+ mcrTemp = (pConfig->enableSupervisorMode) ? mcrTemp | CAN_MCR_SUPV_MASK : mcrTemp & ~CAN_MCR_SUPV_MASK;
+#endif
+
+ /* Set the maximum number of Message Buffers */
+ mcrTemp = (mcrTemp & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB((uint32_t)pConfig->maxMbNum - 1U);
+
+ /* Enable Self Wake Up Mode and configure the wake up source. */
+ mcrTemp = (pConfig->enableSelfWakeup) ? (mcrTemp | CAN_MCR_SLFWAK_MASK) : (mcrTemp & ~CAN_MCR_SLFWAK_MASK);
+ mcrTemp = (kFLEXCAN_WakeupSrcFiltered == pConfig->wakeupSrc) ? (mcrTemp | CAN_MCR_WAKSRC_MASK) :
+ (mcrTemp & ~CAN_MCR_WAKSRC_MASK);
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /* Enable Pretended Networking Mode? When Pretended Networking mode is set, Self Wake Up feature must be disabled.*/
+ mcrTemp = (pConfig->enablePretendedeNetworking) ? ((mcrTemp & ~CAN_MCR_SLFWAK_MASK) | CAN_MCR_PNET_EN_MASK) :
+ (mcrTemp & ~CAN_MCR_PNET_EN_MASK);
+#endif
+
+ /* Enable Individual Rx Masking and Queue feature? */
+ mcrTemp = (pConfig->enableIndividMask) ? (mcrTemp | CAN_MCR_IRMQ_MASK) : (mcrTemp & ~CAN_MCR_IRMQ_MASK);
+
+ /* Disable Self Reception? */
+ mcrTemp = (pConfig->disableSelfReception) ? mcrTemp | CAN_MCR_SRXDIS_MASK : mcrTemp & ~CAN_MCR_SRXDIS_MASK;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_DOZE_MODE_SUPPORTn(base))
+ {
+ /* Enable Doze Mode? */
+ mcrTemp = (pConfig->enableDoze) ? (mcrTemp | CAN_MCR_DOZE_MASK) : (mcrTemp & ~CAN_MCR_DOZE_MASK);
+ }
+#endif
+
+ /* Write back CTRL1 Configuration to register. */
+ base->CTRL1 = ctrl1Temp;
+
+ /* Write back MCR Configuration to register. */
+ base->MCR = mcrTemp;
+
+ /* Check whether Nominal Bit Rate Prescaler is overflow. */
+ if ((sourceClock_Hz / tqFre - 1U) > maxDivider)
+ {
+ timingCfg.preDivider = maxDivider;
+ }
+ else
+ {
+ timingCfg.preDivider = (uint16_t)(sourceClock_Hz / tqFre) - 1U;
+ }
+
+ /* Update actual timing characteristic. */
+ FLEXCAN_SetTimingConfig(base, &timingCfg);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_FDInit function by passing in these parameters.
+ * code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.bitRate = 1000000U;
+ * flexcanConfig.bitRateFD = 2000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_FDInit(CAN0, &flexcanConfig, 80000000UL, kFLEXCAN_16BperMB, true);
+ * endcode
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the user-defined configuration structure.
+ * param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ * param dataSize FlexCAN Message Buffer payload size. The actual transmitted or received CAN FD frame data size needs
+ * to be less than or equal to this value.
+ * param brs True if bit rate switch is enabled in FD mode.
+ */
+void FLEXCAN_FDInit(
+ CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz, flexcan_mb_size_t dataSize, bool brs)
+{
+ assert((uint32_t)dataSize <= 3U);
+ assert(((pConfig->bitRate < pConfig->bitRateFD) && brs) || ((pConfig->bitRate == pConfig->bitRateFD) && (!brs)));
+
+ uint32_t fdctrl = 0U;
+ flexcan_timing_config_t timingCfg = pConfig->timingConfig;
+ /* FlexCAN FD frame data phase timing setting formula:
+ * quantum = 1 + (fphaseSeg1 + 1) + (fphaseSeg2 + 1) + fpropSeg;
+ */
+ uint32_t quantum = (1U + ((uint32_t)timingCfg.fphaseSeg1 + 1U) + ((uint32_t)timingCfg.fphaseSeg2 + 1U) +
+ (uint32_t)timingCfg.fpropSeg);
+ uint32_t tqFre = pConfig->bitRateFD * quantum;
+ uint16_t maxDivider;
+
+ /* Check bit rate value. */
+ assert((pConfig->bitRateFD <= 8000000U) && (tqFre <= sourceClock_Hz));
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ assert((tqFre * MAX_EDPRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_EDPRESDIV;
+#else
+ assert((tqFre * MAX_FPRESDIV) >= sourceClock_Hz);
+ maxDivider = MAX_FPRESDIV;
+#endif
+
+ /* Initialization of classical CAN. */
+ FLEXCAN_Init(base, pConfig, sourceClock_Hz);
+
+ /* Check whether Data Bit Rate Prescaler is overflow. */
+ if ((sourceClock_Hz / tqFre - 1U) > maxDivider)
+ {
+ timingCfg.fpreDivider = maxDivider;
+ }
+ else
+ {
+ timingCfg.fpreDivider = (uint16_t)(sourceClock_Hz / tqFre) - 1U;
+ }
+
+ /* Update actual timing characteristic. */
+ FLEXCAN_SetFDTimingConfig(base, &timingCfg);
+
+ /* read FDCTRL register. */
+ fdctrl = base->FDCTRL;
+
+ /* Enable FD operation and set bit rate switch. */
+ if (brs)
+ {
+ fdctrl |= CAN_FDCTRL_FDRATE_MASK;
+ }
+ else
+ {
+ fdctrl &= ~CAN_FDCTRL_FDRATE_MASK;
+ }
+
+ /* Before use "|=" operation for multi-bits field, CPU should clean previous Setting. */
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR0_MASK) | CAN_FDCTRL_MBDSR0(dataSize);
+#if defined(CAN_FDCTRL_MBDSR1_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR1_MASK) | CAN_FDCTRL_MBDSR1(dataSize);
+#endif
+#if defined(CAN_FDCTRL_MBDSR2_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR2_MASK) | CAN_FDCTRL_MBDSR2(dataSize);
+#endif
+#if defined(CAN_FDCTRL_MBDSR3_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR3_MASK) | CAN_FDCTRL_MBDSR3(dataSize);
+#endif
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+ /* Enable CAN FD operation. */
+ base->MCR |= CAN_MCR_FDEN_MASK;
+ /* Clear SMP bit when CAN FD is enabled (CAN FD only can use one regular sample point plus one optional secondary
+ * sampling point). */
+ base->CTRL1 &= ~CAN_CTRL1_SMP_MASK;
+
+ if (brs && !(pConfig->enableLoopBack))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* The TDC offset should be configured as shown in this equation : offset = DTSEG1 + 2 */
+ if (((uint32_t)pConfig->timingConfig.fphaseSeg1 + pConfig->timingConfig.fpropSeg + 2U) *
+ (pConfig->timingConfig.fpreDivider + 1U) <
+ MAX_ETDCOFF)
+ {
+ base->ETDC =
+ CAN_ETDC_ETDCEN_MASK | CAN_ETDC_TDMDIS(!pConfig->enableTransceiverDelayMeasure) |
+ CAN_ETDC_ETDCOFF(((uint32_t)pConfig->timingConfig.fphaseSeg1 + pConfig->timingConfig.fpropSeg + 2U) *
+ (pConfig->timingConfig.fpreDivider + 1U));
+ }
+ else
+ {
+ /* Enable the Transceiver Delay Compensation */
+ base->ETDC = CAN_ETDC_ETDCEN_MASK | CAN_ETDC_TDMDIS(!pConfig->enableTransceiverDelayMeasure) |
+ CAN_ETDC_ETDCOFF(MAX_ETDCOFF);
+ }
+#else
+ /* The TDC offset should be configured as shown in this equation : offset = PSEG1 + PROPSEG + 2 */
+ if (((uint32_t)pConfig->timingConfig.fphaseSeg1 + pConfig->timingConfig.fpropSeg + 2U) *
+ (pConfig->timingConfig.fpreDivider + 1U) <
+ MAX_TDCOFF)
+ {
+ fdctrl =
+ (fdctrl & ~CAN_FDCTRL_TDCOFF_MASK) |
+ CAN_FDCTRL_TDCOFF(((uint32_t)pConfig->timingConfig.fphaseSeg1 + pConfig->timingConfig.fpropSeg + 2U) *
+ (pConfig->timingConfig.fpreDivider + 1U));
+ }
+ else
+ {
+ fdctrl = (fdctrl & ~CAN_FDCTRL_TDCOFF_MASK) | CAN_FDCTRL_TDCOFF(MAX_TDCOFF);
+ }
+ /* Enable the Transceiver Delay Compensation */
+ fdctrl = (fdctrl & ~CAN_FDCTRL_TDCEN_MASK) | CAN_FDCTRL_TDCEN_MASK;
+#endif
+ }
+
+ /* update the FDCTL register. */
+ base->FDCTRL = fdctrl;
+
+ /* Enable CAN FD ISO mode by default. */
+ base->CTRL2 |= CAN_CTRL2_ISOCANFDEN_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+#endif
+
+/*!
+ * brief De-initializes a FlexCAN instance.
+ *
+ * This function disables the FlexCAN module clock and sets all register values
+ * to the reset value.
+ *
+ * param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_Deinit(CAN_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+ /* Reset all Register Contents. */
+ FLEXCAN_Reset(base);
+
+ /* Disable FlexCAN module. */
+ FLEXCAN_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Disable FlexCAN serial clock. */
+ (void)CLOCK_DisableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+ /* Disable FlexCAN clock. */
+ (void)CLOCK_DisableClock(s_flexcanClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the FlexCAN configuration structure to default values. The default
+ * values are as follows.
+ * flexcanConfig->clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig->bitRate = 1000000U;
+ * flexcanConfig->bitRateFD = 2000000U;
+ * flexcanConfig->maxMbNum = 16;
+ * flexcanConfig->enableLoopBack = false;
+ * flexcanConfig->enableSelfWakeup = false;
+ * flexcanConfig->enableIndividMask = false;
+ * flexcanConfig->disableSelfReception = false;
+ * flexcanConfig->enableListenOnlyMode = false;
+ * flexcanConfig->enableDoze = false;
+ * flexcanConfig->enablePretendedeNetworking = false;
+ * flexcanConfig->enableMemoryErrorControl = true;
+ * flexcanConfig->enableNonCorrectableErrorEnterFreeze = true;
+ * flexcanConfig->enableTransceiverDelayMeasure = true;
+ * flexcanConfig.timingConfig = timingConfig;
+ *
+ * param pConfig Pointer to the FlexCAN configuration structure.
+ */
+void FLEXCAN_GetDefaultConfig(flexcan_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(pConfig, 0, sizeof(*pConfig));
+
+ /* Initialize FlexCAN Module config struct with default value. */
+ pConfig->clkSrc = kFLEXCAN_ClkSrc0;
+ pConfig->bitRate = 1000000U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ pConfig->bitRateFD = 2000000U;
+#endif
+ pConfig->maxMbNum = 16;
+ pConfig->enableLoopBack = false;
+ pConfig->enableTimerSync = true;
+ pConfig->enableSelfWakeup = false;
+ pConfig->wakeupSrc = kFLEXCAN_WakeupSrcUnfiltered;
+ pConfig->enableIndividMask = false;
+ pConfig->disableSelfReception = false;
+ pConfig->enableListenOnlyMode = false;
+#if !(defined(FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT)
+ pConfig->enableSupervisorMode = true;
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ pConfig->enableDoze = false;
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ pConfig->enablePretendedeNetworking = false;
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ pConfig->enableMemoryErrorControl = true;
+ pConfig->enableNonCorrectableErrorEnterFreeze = true;
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ pConfig->enableTransceiverDelayMeasure = true;
+#endif
+
+ /* Default protocol timing configuration, nominal bit time quantum is 10 (80% SP), data bit time quantum is 5
+ * (60%). Suggest use FLEXCAN_CalculateImprovedTimingValues/FLEXCAN_FDCalculateImprovedTimingValues to get the
+ * improved timing configuration.*/
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ pConfig->timingConfig.phaseSeg1 = 1;
+ pConfig->timingConfig.phaseSeg2 = 1;
+ pConfig->timingConfig.propSeg = 4;
+ pConfig->timingConfig.rJumpwidth = 1;
+ pConfig->timingConfig.fphaseSeg1 = 1;
+ pConfig->timingConfig.fphaseSeg2 = 1;
+ pConfig->timingConfig.fpropSeg = 0;
+ pConfig->timingConfig.frJumpwidth = 1;
+#else
+ pConfig->timingConfig.phaseSeg1 = 1;
+ pConfig->timingConfig.phaseSeg2 = 1;
+ pConfig->timingConfig.propSeg = 4;
+ pConfig->timingConfig.rJumpwidth = 1;
+#endif
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*!
+ * brief Configures the FlexCAN Pretended Networking mode.
+ *
+ * This function configures the FlexCAN Pretended Networking mode with given configuration.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the FlexCAN Rx FIFO configuration structure.
+ */
+void FLEXCAN_SetPNConfig(CAN_Type *base, const flexcan_pn_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+ assert(0U != pConfig->matchNum);
+ uint32_t pnctrl;
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+ pnctrl = (pConfig->matchNum > 1U) ? CAN_CTRL1_PN_FCS(0x2U | (uint32_t)pConfig->matchSrc) :
+ CAN_CTRL1_PN_FCS(pConfig->matchSrc);
+ pnctrl |= (pConfig->enableMatch) ? (CAN_CTRL1_PN_WUMF_MSK_MASK) : 0U;
+ pnctrl |= (pConfig->enableTimeout) ? (CAN_CTRL1_PN_WTOF_MSK_MASK) : 0U;
+ pnctrl |= CAN_CTRL1_PN_NMATCH(pConfig->matchNum) | CAN_CTRL1_PN_IDFS(pConfig->idMatchMode) |
+ CAN_CTRL1_PN_PLFS(pConfig->dataMatchMode);
+ base->CTRL1_PN = pnctrl;
+ base->CTRL2_PN = CAN_CTRL2_PN_MATCHTO(pConfig->timeoutValue);
+ base->FLT_ID1 = pConfig->idLower;
+ base->FLT_ID2_IDMASK = pConfig->idUpper;
+ base->FLT_DLC = CAN_FLT_DLC_FLT_DLC_LO(pConfig->lengthLower) | CAN_FLT_DLC_FLT_DLC_HI(pConfig->lengthUpper);
+ base->PL1_LO = pConfig->lowerWord0;
+ base->PL1_HI = pConfig->lowerWord1;
+ base->PL2_PLMASK_LO = pConfig->upperWord0;
+ base->PL2_PLMASK_HI = pConfig->upperWord1;
+
+ FLEXCAN_ClearStatusFlags(base, (uint64_t)kFLEXCAN_PNMatchIntFlag | (uint64_t)kFLEXCAN_PNTimeoutIntFlag);
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Reads a FlexCAN Message from Wake Up MB.
+ *
+ * This function reads a CAN message from the FlexCAN Wake up Message Buffers. There are four Wake up Message Buffers
+ * (WMBs) used to store incoming messages in Pretended Networking mode. The WMB index indicates the arrival order. The
+ * last message is stored in WMB3.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * param mbIdx The FlexCAN Wake up Message Buffer index. Range in 0x0 ~ 0x3.
+ * retval kStatus_Success - Read Message from Wake up Message Buffer successfully.
+ * retval kStatus_Fail - Wake up Message Buffer has no valid content.
+ */
+status_t FLEXCAN_ReadPNWakeUpMB(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(NULL != pRxFrame);
+ assert(mbIdx <= 0x3U);
+
+ uint32_t cs_temp;
+ status_t status;
+
+ /* Check if Wake Up MB has valid content. */
+ if (CAN_WU_MTC_MCOUNTER(mbIdx) < (base->WU_MTC & CAN_WU_MTC_MCOUNTER_MASK))
+ {
+ /* Read CS field of wake up Message Buffer. */
+ cs_temp = base->WMB[mbIdx].CS;
+
+ /* Store Message ID. */
+ pRxFrame->id = base->WMB[mbIdx].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Messages received during Pretended Networking mode don't have time stamps, and the respective field in the
+ WMB structure must be ignored. */
+ pRxFrame->timestamp = 0x0;
+
+ /* Store Message Payload. */
+ pRxFrame->dataWord0 = base->WMB[mbIdx].D03;
+ pRxFrame->dataWord1 = base->WMB[mbIdx].D47;
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Sets the FlexCAN classical protocol timing characteristic.
+ *
+ * This function gives user settings to classical CAN or CAN FD nominal phase timing characteristic.
+ * The function is for an experienced user. For less experienced users, call the FLEXCAN_GetDefaultConfig()
+ * and get the default timing characteristicsthe, then call FLEXCAN_Init() and fill the
+ * bit rate field.
+ *
+ * note Calling FLEXCAN_SetTimingConfig() overrides the bit rate set
+ * in FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Enable extended Bit Timing register ENCBT. */
+ base->CTRL2 |= CAN_CTRL2_BTE_MASK;
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->EPRS = (base->EPRS & (~CAN_EPRS_ENPRESDIV_MASK)) | CAN_EPRS_ENPRESDIV(pConfig->preDivider);
+ base->ENCBT = CAN_ENCBT_NRJW(pConfig->rJumpwidth) |
+ CAN_ENCBT_NTSEG1((uint32_t)pConfig->phaseSeg1 + pConfig->propSeg + 1U) |
+ CAN_ENCBT_NTSEG2(pConfig->phaseSeg2);
+#else
+ /* On RT106x devices, a single write may be ignored, so it is necessary to read back the register value to
+ * determine whether the value is written successfully. */
+
+ do
+ {
+ /* Enable Bit Timing register CBT, updating Timing Setting according to configuration structure. */
+ base->CBT = CAN_CBT_BTF_MASK | CAN_CBT_EPRESDIV(pConfig->preDivider) | CAN_CBT_ERJW(pConfig->rJumpwidth) |
+ CAN_CBT_EPSEG1(pConfig->phaseSeg1) | CAN_CBT_EPSEG2(pConfig->phaseSeg2) |
+ CAN_CBT_EPROPSEG(pConfig->propSeg);
+
+ } while ((CAN_CBT_EPRESDIV(pConfig->preDivider) | CAN_CBT_ERJW(pConfig->rJumpwidth) |
+ CAN_CBT_EPSEG1(pConfig->phaseSeg1) | CAN_CBT_EPSEG2(pConfig->phaseSeg2) |
+ CAN_CBT_EPROPSEG(pConfig->propSeg)) !=
+ (base->CBT & (CAN_CBT_EPRESDIV_MASK | CAN_CBT_ERJW_MASK | CAN_CBT_EPSEG1_MASK | CAN_CBT_EPSEG2_MASK |
+ CAN_CBT_EPROPSEG_MASK)));
+#endif
+ }
+ else
+ {
+ /* Cleaning previous Timing Setting. */
+ base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK | CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
+ CAN_CTRL1_PROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CTRL1 |= (CAN_CTRL1_PRESDIV(pConfig->preDivider) | CAN_CTRL1_RJW(pConfig->rJumpwidth) |
+ CAN_CTRL1_PSEG1(pConfig->phaseSeg1) | CAN_CTRL1_PSEG2(pConfig->phaseSeg2) |
+ CAN_CTRL1_PROPSEG(pConfig->propSeg));
+ }
+#else
+ /* Cleaning previous Timing Setting. */
+ base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK | CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
+ CAN_CTRL1_PROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CTRL1 |= (CAN_CTRL1_PRESDIV(pConfig->preDivider) | CAN_CTRL1_RJW(pConfig->rJumpwidth) |
+ CAN_CTRL1_PSEG1(pConfig->phaseSeg1) | CAN_CTRL1_PSEG2(pConfig->phaseSeg2) |
+ CAN_CTRL1_PROPSEG(pConfig->propSeg));
+#endif
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Sets the FlexCAN FD data phase timing characteristic.
+ *
+ * This function gives user settings to CAN FD data phase timing characteristic.
+ * The function is for an experienced user. For less experienced users, call the FLEXCAN_GetDefaultConfig()
+ * and get the default timing characteristicsthe, then call FLEXCAN_FDInit() and fill the
+ * data phase bit rate field.
+ *
+ * note Calling FLEXCAN_SetFDTimingConfig() overrides the bit rate set
+ * in FLEXCAN_FDInit().
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetFDTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Enable extended Bit Timing register EDCBT. */
+ base->CTRL2 |= CAN_CTRL2_BTE_MASK;
+
+ base->EPRS = (base->EPRS & (~CAN_EPRS_EDPRESDIV_MASK)) | CAN_EPRS_EDPRESDIV(pConfig->fpreDivider);
+ base->EDCBT = CAN_EDCBT_DRJW(pConfig->frJumpwidth) | CAN_EDCBT_DTSEG2(pConfig->fphaseSeg2) |
+ CAN_EDCBT_DTSEG1((uint32_t)pConfig->fphaseSeg1 + pConfig->fpropSeg);
+#else
+ /* Enable Bit Timing register FDCBT,*/
+ base->CBT |= CAN_CBT_BTF_MASK;
+
+ /* On RT106x devices, a single write may be ignored, so it is necessary to read back the register value to determine
+ * whether the value is written successfully. */
+ do
+ {
+ /* Updating Timing Setting according to configuration structure. */
+ base->FDCBT = (CAN_FDCBT_FPRESDIV(pConfig->fpreDivider) | CAN_FDCBT_FRJW(pConfig->frJumpwidth) |
+ CAN_FDCBT_FPSEG1(pConfig->fphaseSeg1) | CAN_FDCBT_FPSEG2(pConfig->fphaseSeg2) |
+ CAN_FDCBT_FPROPSEG(pConfig->fpropSeg));
+ } while ((CAN_FDCBT_FPRESDIV(pConfig->fpreDivider) | CAN_FDCBT_FRJW(pConfig->frJumpwidth) |
+ CAN_FDCBT_FPSEG1(pConfig->fphaseSeg1) | CAN_FDCBT_FPSEG2(pConfig->fphaseSeg2) |
+ CAN_FDCBT_FPROPSEG(pConfig->fpropSeg)) !=
+ (base->FDCBT & (CAN_FDCBT_FPRESDIV_MASK | CAN_FDCBT_FRJW_MASK | CAN_FDCBT_FPSEG1_MASK |
+ CAN_FDCBT_FPSEG2_MASK | CAN_FDCBT_FPROPSEG_MASK)));
+#endif
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+#endif
+
+/*!
+ * brief Sets the FlexCAN receive message buffer global mask.
+ *
+ * This function sets the global mask for the FlexCAN message buffer in a matching process.
+ * The configuration is only effective when the Rx individual mask is disabled in the FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param mask Rx Message Buffer Global Mask value.
+ */
+void FLEXCAN_SetRxMbGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Message Buffer Global Mask value. */
+ base->RXMGMASK = mask;
+ base->RX14MASK = mask;
+ base->RX15MASK = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Sets the FlexCAN receive FIFO global mask.
+ *
+ * This function sets the global mask for FlexCAN FIFO in a matching process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mask Rx Fifo Global Mask value.
+ */
+void FLEXCAN_SetRxFifoGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx FIFO Global Mask value. */
+ base->RXFGMASK = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Sets the FlexCAN receive individual mask.
+ *
+ * This function sets the individual mask for the FlexCAN matching process.
+ * The configuration is only effective when the Rx individual mask is enabled in the FLEXCAN_Init().
+ * If the Rx FIFO is disabled, the individual mask is applied to the corresponding Message Buffer.
+ * If the Rx FIFO is enabled, the individual mask for Rx FIFO occupied Message Buffer is applied to
+ * the Rx Filter with the same index. Note that only the first 32
+ * individual masks can be used as the Rx FIFO filter mask.
+ *
+ * param base FlexCAN peripheral base address.
+ * param maskIdx The Index of individual Mask.
+ * param mask Rx Individual Mask value.
+ */
+void FLEXCAN_SetRxIndividualMask(CAN_Type *base, uint8_t maskIdx, uint32_t mask)
+{
+ assert(maskIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Individual Mask value. */
+ base->RXIMR[maskIdx] = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ /* Inactivate Message Buffer. */
+ if (enable)
+ {
+ base->MB[mbIdx].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ }
+ else
+ {
+ base->MB[mbIdx].CS = 0;
+ }
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+}
+
+/*!
+ * brief Calculates the segment values for a single bit time for classical CAN.
+ *
+ * This function use to calculates the Classical CAN segment values which will be set in CTRL1/CBT/ENCBT register.
+ *
+ * param bitRate The classical CAN bit rate in bps.
+ * param base FlexCAN peripheral base address.
+ * param tqNum Number of time quantas per bit, range in 8 ~ 25 when use CTRL1, range in 8 ~ 129 when use CBT, range in
+ * 8 ~ 385 when use ENCBT. param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ */
+static void FLEXCAN_GetSegments(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t tqNum,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ uint32_t ideal_sp;
+ uint32_t seg1Max, proSegMax;
+ uint32_t seg1Temp;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Maximum value allowed in ENCBT register. */
+ seg1Max = MAX_NTSEG2 + 1U;
+ proSegMax = MAX_NTSEG1 - MAX_NTSEG2;
+#else
+ /* Maximum value allowed in CBT register. */
+ seg1Max = MAX_EPSEG1 + 1U;
+ proSegMax = MAX_EPROPSEG + 1U;
+#endif
+ }
+ else
+ {
+ /* Maximum value allowed in CTRL1 register. */
+ seg1Max = MAX_PSEG1 + 1U;
+ proSegMax = MAX_PROPSEG + 1U;
+ }
+#else
+ /* Maximum value allowed in CTRL1 register. */
+ seg1Max = MAX_PSEG1 + 1U;
+ proSegMax = MAX_PROPSEG + 1U;
+#endif
+
+ /* Try to find the ideal sample point, according to CiA 301 doc.*/
+ if (bitRate == 1000000U)
+ {
+ ideal_sp = IDEAL_SP_LOW;
+ }
+ else if (bitRate >= 800000U)
+ {
+ ideal_sp = IDEAL_SP_MID;
+ }
+ else
+ {
+ ideal_sp = IDEAL_SP_HIGH;
+ }
+ /* Calculates phaseSeg2. */
+ pTimingConfig->phaseSeg2 = (uint8_t)(tqNum - (tqNum * ideal_sp) / (uint32_t)IDEAL_SP_FACTOR);
+ if (pTimingConfig->phaseSeg2 < MIN_TIME_SEGMENT2)
+ {
+ pTimingConfig->phaseSeg2 = MIN_TIME_SEGMENT2;
+ }
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+#if !(defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ if (pTimingConfig->phaseSeg2 > (uint8_t)(MAX_EPSEG2 + 1U))
+ {
+ pTimingConfig->phaseSeg2 = (uint8_t)(MAX_EPSEG2 + 1U);
+ }
+#endif
+ }
+#endif
+
+ /* Calculates phaseSeg1 and propSeg and try to make phaseSeg1 equal to phaseSeg2. */
+ if ((tqNum - pTimingConfig->phaseSeg2 - 1U) > (seg1Max + proSegMax))
+ {
+ seg1Temp = seg1Max + proSegMax;
+ pTimingConfig->phaseSeg2 = (uint8_t)(tqNum - 1U - seg1Temp);
+ }
+ else
+ {
+ seg1Temp = tqNum - pTimingConfig->phaseSeg2 - 1U;
+ }
+ if (seg1Temp > (pTimingConfig->phaseSeg2 + proSegMax))
+ {
+ pTimingConfig->propSeg = (uint8_t)proSegMax;
+ pTimingConfig->phaseSeg1 = (uint8_t)(seg1Temp - proSegMax);
+ }
+ else
+ {
+ pTimingConfig->propSeg = (uint8_t)(seg1Temp - pTimingConfig->phaseSeg2);
+ pTimingConfig->phaseSeg1 = pTimingConfig->phaseSeg2;
+ }
+
+ /* rJumpwidth (sjw) is the minimum value of phaseSeg1 and phaseSeg2. */
+ pTimingConfig->rJumpwidth =
+ (pTimingConfig->phaseSeg1 > pTimingConfig->phaseSeg2) ? pTimingConfig->phaseSeg2 : pTimingConfig->phaseSeg1;
+#if !(defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (pTimingConfig->rJumpwidth > (MAX_RJW + 1U))
+ {
+ pTimingConfig->rJumpwidth = (uint8_t)(MAX_RJW + 1U);
+ }
+#else
+ if (0 == FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+ if (pTimingConfig->rJumpwidth > (MAX_RJW + 1U))
+ {
+ pTimingConfig->rJumpwidth = (uint8_t)(MAX_RJW + 1U);
+ }
+ }
+#endif
+
+ pTimingConfig->phaseSeg1 -= 1U;
+ pTimingConfig->phaseSeg2 -= 1U;
+ pTimingConfig->propSeg -= 1U;
+ pTimingConfig->rJumpwidth -= 1U;
+}
+
+/*!
+ * brief Calculates the improved timing values by specific bit Rates for classical CAN.
+ *
+ * This function use to calculates the Classical CAN timing values according to the given bit rate. The Calculated
+ * timing values will be set in CTRL1/CBT/ENCBT register. The calculation is based on the recommendation of the CiA 301
+ * v4.2.0 and previous version document.
+ *
+ * param base FlexCAN peripheral base address.
+ * param bitRate The classical CAN speed in bps defined by user, should be less than or equal to 1Mbps.
+ * param sourceClock_Hz The Source clock frequency in Hz.
+ * param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * return TRUE if timing configuration found, FALSE if failed to find configuration.
+ */
+bool FLEXCAN_CalculateImprovedTimingValues(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* Observe bit rate maximums. */
+ assert(bitRate <= MAX_CAN_BITRATE);
+
+ uint32_t clk;
+ uint32_t tqNum, tqMin, pdivMAX;
+ uint32_t spTemp = 1000U;
+ flexcan_timing_config_t configTemp = {0};
+ bool fgRet = false;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Auto Improved Protocal timing for ENCBT. */
+ tqNum = ENCBT_MAX_TIME_QUANTA;
+ tqMin = ENCBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_ENPRESDIV;
+#else
+ /* Auto Improved Protocal timing for CBT. */
+ tqNum = CBT_MAX_TIME_QUANTA;
+ tqMin = CBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_PRESDIV;
+#endif
+ }
+ else
+ {
+ /* Auto Improved Protocal timing for CTRL1. */
+ tqNum = CTRL1_MAX_TIME_QUANTA;
+ tqMin = CTRL1_MIN_TIME_QUANTA;
+ pdivMAX = MAX_PRESDIV;
+ }
+#else
+ /* Auto Improved Protocal timing for CTRL1. */
+ tqNum = CTRL1_MAX_TIME_QUANTA;
+ tqMin = CTRL1_MIN_TIME_QUANTA;
+ pdivMAX = MAX_PRESDIV;
+#endif
+ do
+ {
+ clk = bitRate * tqNum;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* Non-supporting: the frequency of clock source is not divisible by target bit rate, the user
+ should change a divisible bit rate. */
+ }
+
+ configTemp.preDivider = (uint16_t)(sourceClock_Hz / clk) - 1U;
+ if (configTemp.preDivider > pdivMAX)
+ {
+ break; /* The frequency of source clock is too large or the bit rate is too small, the pre-divider could
+ not handle it. */
+ }
+
+ /* Calculates the best timing configuration under current tqNum. */
+ FLEXCAN_GetSegments(base, bitRate, tqNum, &configTemp);
+ /* Determine whether the calculated timing configuration can get the optimal sampling point. */
+ if (((((uint32_t)configTemp.phaseSeg2 + 1U) * 1000U) / tqNum) < spTemp)
+ {
+ spTemp = (((uint32_t)configTemp.phaseSeg2 + 1U) * 1000U) / tqNum;
+ pTimingConfig->preDivider = configTemp.preDivider;
+ pTimingConfig->rJumpwidth = configTemp.rJumpwidth;
+ pTimingConfig->phaseSeg1 = configTemp.phaseSeg1;
+ pTimingConfig->phaseSeg2 = configTemp.phaseSeg2;
+ pTimingConfig->propSeg = configTemp.propSeg;
+ }
+ fgRet = true;
+ } while (--tqNum >= tqMin);
+
+ return fgRet;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Get Mailbox offset number by dword.
+ *
+ * This function gets the offset number of the specified mailbox.
+ * Mailbox is not consecutive between memory regions when payload is not 8 bytes
+ * so need to calculate the specified mailbox address.
+ * For example, in the first memory region, MB[0].CS address is 0x4002_4080. For 32 bytes
+ * payload frame, the second mailbox is ((1/12)*512 + 1%12*40)/4 = 10, meaning 10 dword
+ * after the 0x4002_4080, which is actually the address of mailbox MB[1].CS.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx Mailbox index.
+ */
+static uint32_t FLEXCAN_GetFDMailboxOffset(CAN_Type *base, uint8_t mbIdx)
+{
+ uint32_t offset = 0;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ if (dataSize == (uint32_t)kFLEXCAN_8BperMB)
+ {
+ offset = (((uint32_t)mbIdx / 32U) * 512U + ((uint32_t)mbIdx % 32U) * 16U);
+ }
+ else if (dataSize == (uint32_t)kFLEXCAN_16BperMB)
+ {
+ offset = (((uint32_t)mbIdx / 21U) * 512U + ((uint32_t)mbIdx % 21U) * 24U);
+ }
+ else if (dataSize == (uint32_t)kFLEXCAN_32BperMB)
+ {
+ offset = (((uint32_t)mbIdx / 12U) * 512U + ((uint32_t)mbIdx % 12U) * 40U);
+ }
+ else
+ {
+ offset = (((uint32_t)mbIdx / 7U) * 512U + ((uint32_t)mbIdx % 7U) * 72U);
+ }
+
+ /* To get the dword aligned offset, need to divide by 4. */
+ offset = offset / 4U;
+ return offset;
+}
+
+/*!
+ * brief Calculates the segment values for a single bit time for CAN FD data phase.
+ *
+ * This function use to calculates the CAN FD data phase segment values which will be set in CFDCBT/EDCBT
+ * register.
+ *
+ * param bitRateFD CAN FD data phase bit rate.
+ * param tqNum Number of time quanta per bit
+ * param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ */
+static void FLEXCAN_FDGetSegments(uint32_t bitRateFD, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig)
+{
+ uint32_t ideal_sp;
+ uint32_t seg1Max, proSegMax, seg2Max;
+ uint32_t seg1Temp;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Maximum value allowed in EDCBT register. */
+ seg1Max = MAX_DTSEG2 + 1U;
+ proSegMax = MAX_DTSEG1 - MAX_DTSEG2;
+ seg2Max = MAX_DTSEG2 + 1U;
+#else
+ /* Maximum value allowed in FDCBT register. */
+ seg1Max = MAX_FPSEG1 + 1U;
+ proSegMax = MAX_FPROPSEG;
+ seg2Max = MAX_FPSEG2 + 1U;
+#endif
+
+ /* According to CiA doc 1301 v1.0.0, which specified data phase sample point postion for CAN FD at 80 MHz. */
+ if (bitRateFD <= 1000000U)
+ {
+ ideal_sp = IDEAL_DATA_SP_1;
+ }
+ else if (bitRateFD <= 2000000U)
+ {
+ ideal_sp = IDEAL_DATA_SP_2;
+ }
+ else if (bitRateFD <= 4000000U)
+ {
+ ideal_sp = IDEAL_DATA_SP_3;
+ }
+ else
+ {
+ ideal_sp = IDEAL_DATA_SP_4;
+ }
+
+ /* Calculates fphaseSeg2. */
+ pTimingConfig->fphaseSeg2 = (uint8_t)(tqNum - (tqNum * ideal_sp) / (uint32_t)IDEAL_SP_FACTOR);
+ if (pTimingConfig->fphaseSeg2 < MIN_TIME_SEGMENT2)
+ {
+ pTimingConfig->fphaseSeg2 = MIN_TIME_SEGMENT2;
+ }
+ else if (pTimingConfig->fphaseSeg2 > seg2Max)
+ {
+ pTimingConfig->fphaseSeg2 = (uint8_t)seg2Max;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Calculates fphaseSeg1 and fpropSeg and try to make phaseSeg1 equal to phaseSeg2 */
+ if ((tqNum - pTimingConfig->fphaseSeg2 - 1U) > (seg1Max + proSegMax))
+ {
+ seg1Temp = seg1Max + proSegMax;
+ pTimingConfig->fphaseSeg2 = (uint8_t)(tqNum - 1U - seg1Temp);
+ }
+ else
+ {
+ seg1Temp = tqNum - pTimingConfig->fphaseSeg2 - 1U;
+ }
+ if (seg1Temp > (pTimingConfig->fphaseSeg2 + proSegMax))
+ {
+ pTimingConfig->fpropSeg = (uint8_t)proSegMax;
+ pTimingConfig->fphaseSeg1 = (uint8_t)(seg1Temp - proSegMax);
+ }
+ else if (seg1Temp > pTimingConfig->fphaseSeg2)
+ {
+ pTimingConfig->fpropSeg = (uint8_t)(seg1Temp - pTimingConfig->fphaseSeg2);
+ pTimingConfig->fphaseSeg1 = pTimingConfig->fphaseSeg2;
+ }
+ else
+ {
+ pTimingConfig->fpropSeg = 0U;
+ pTimingConfig->fphaseSeg1 = (uint8_t)seg1Temp;
+ }
+
+ /* rJumpwidth (sjw) is the minimum value of phaseSeg1 and phaseSeg2. */
+ pTimingConfig->frJumpwidth =
+ (pTimingConfig->fphaseSeg1 > pTimingConfig->fphaseSeg2) ? pTimingConfig->fphaseSeg2 : pTimingConfig->fphaseSeg1;
+
+ pTimingConfig->fphaseSeg1 -= 1U;
+ pTimingConfig->fphaseSeg2 -= 1U;
+ pTimingConfig->frJumpwidth -= 1U;
+}
+
+/*!
+ * brief Calculates the improved timing values by specific bit rate for CAN FD nominal phase.
+ *
+ * This function use to calculates the CAN FD nominal phase timing values according to the given nominal phase bit rate.
+ * The Calculated timing values will be set in CBT/ENCBT registers. The calculation is based on the recommendation of
+ * the CiA 1301 v1.0.0 document.
+ *
+ * param bitRate The CAN FD nominal phase speed in bps defined by user, should be less than or equal to 1Mbps.
+ * param sourceClock_Hz The Source clock frequency in Hz.
+ * param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * return TRUE if timing configuration found, FALSE if failed to find configuration.
+ */
+static bool FLEXCAN_CalculateImprovedNominalTimingValues(uint32_t bitRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* Observe bit rate maximums. */
+ assert(bitRate <= MAX_CAN_BITRATE);
+
+ uint32_t clk;
+ uint32_t tqNum, tqMin, pdivMAX, seg1Max, proSegMax, seg1Temp;
+ uint32_t spTemp = 1000U;
+ flexcan_timing_config_t configTemp = {0};
+ bool fgRet = false;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Auto Improved Protocal timing for ENCBT. */
+ tqNum = ENCBT_MAX_TIME_QUANTA;
+ tqMin = ENCBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_ENPRESDIV;
+ seg1Max = MAX_NTSEG2 + 1U;
+ proSegMax = MAX_NTSEG1 - MAX_NTSEG2;
+#else
+ /* Auto Improved Protocal timing for CBT. */
+ tqNum = CBT_MAX_TIME_QUANTA;
+ tqMin = CBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_PRESDIV;
+ seg1Max = MAX_EPSEG1 + 1U;
+ proSegMax = MAX_EPROPSEG + 1U;
+#endif
+
+ do
+ {
+ clk = bitRate * tqNum;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* Non-supporting: the frequency of clock source is not divisible by target bit rate, the user
+ should change a divisible bit rate. */
+ }
+
+ configTemp.preDivider = (uint16_t)(sourceClock_Hz / clk) - 1U;
+ if (configTemp.preDivider > pdivMAX)
+ {
+ break; /* The frequency of source clock is too large or the bit rate is too small, the pre-divider could
+ not handle it. */
+ }
+
+ /* Calculates the best timing configuration under current tqNum. */
+ configTemp.phaseSeg2 = (uint8_t)(tqNum - (tqNum * IDEAL_NOMINAL_SP) / (uint32_t)IDEAL_SP_FACTOR);
+
+ /* Calculates phaseSeg1 and propSeg and try to make phaseSeg1 equal to phaseSeg2. */
+ if ((tqNum - configTemp.phaseSeg2 - 1U) > (seg1Max + proSegMax))
+ {
+ seg1Temp = seg1Max + proSegMax;
+ configTemp.phaseSeg2 = (uint8_t)(tqNum - 1U - seg1Temp);
+ }
+ else
+ {
+ seg1Temp = tqNum - configTemp.phaseSeg2 - 1U;
+ }
+ if (seg1Temp > (configTemp.phaseSeg2 + proSegMax))
+ {
+ configTemp.propSeg = (uint8_t)proSegMax;
+ configTemp.phaseSeg1 = (uint8_t)(seg1Temp - proSegMax);
+ }
+ else
+ {
+ configTemp.propSeg = (uint8_t)(seg1Temp - configTemp.phaseSeg2);
+ configTemp.phaseSeg1 = configTemp.phaseSeg2;
+ }
+
+ /* rJumpwidth (sjw) is the minimum value of phaseSeg1 and phaseSeg2. */
+ configTemp.rJumpwidth =
+ (configTemp.phaseSeg1 > configTemp.phaseSeg2) ? configTemp.phaseSeg2 : configTemp.phaseSeg1;
+ configTemp.phaseSeg1 -= 1U;
+ configTemp.phaseSeg2 -= 1U;
+ configTemp.propSeg -= 1U;
+ configTemp.rJumpwidth -= 1U;
+
+ if (((((uint32_t)configTemp.phaseSeg2 + 1U) * 1000U) / tqNum) < spTemp)
+ {
+ spTemp = (((uint32_t)configTemp.phaseSeg2 + 1U) * 1000U) / tqNum;
+ pTimingConfig->preDivider = configTemp.preDivider;
+ pTimingConfig->rJumpwidth = configTemp.rJumpwidth;
+ pTimingConfig->phaseSeg1 = configTemp.phaseSeg1;
+ pTimingConfig->phaseSeg2 = configTemp.phaseSeg2;
+ pTimingConfig->propSeg = configTemp.propSeg;
+ }
+ fgRet = true;
+ } while (--tqNum >= tqMin);
+
+ return fgRet;
+}
+
+/*!
+ * brief Calculates the improved timing values by specific bit rates for CAN FD.
+ *
+ * This function use to calculates the CAN FD timing values according to the given nominal phase bit rate and data phase
+ * bit rate. The Calculated timing values will be set in CBT/ENCBT and FDCBT/EDCBT registers. The calculation is based
+ * on the recommendation of the CiA 1301 v1.0.0 document.
+ *
+ * param bitRate The CAN FD nominal phase speed in bps defined by user.
+ * param bitRateFD The CAN FD data phase speed in bps defined by user. Equal to bitRate means disable bit rate
+ * switching. param sourceClock_Hz The Source clock frequency in Hz. param pTimingConfig Pointer to the FlexCAN timing
+ * configuration structure.
+ *
+ * return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+bool FLEXCAN_FDCalculateImprovedTimingValues(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t bitRateFD,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* Observe bit rate maximums */
+ assert(bitRate <= MAX_CANFD_BITRATE);
+ assert(bitRateFD <= MAX_CANFD_BITRATE);
+ /* Data phase bit rate need greater or equal to nominal phase bit rate. */
+ assert(bitRate <= bitRateFD);
+
+ uint32_t clk;
+ uint32_t tqMin, pdivMAX, tqTemp;
+ bool fgRet = false;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ /* Auto Improved Protocal timing for EDCBT. */
+ tqTemp = EDCBT_MAX_TIME_QUANTA;
+ tqMin = EDCBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_EDPRESDIV;
+#else
+ /* Auto Improved Protocal timing for FDCBT. */
+ tqTemp = FDCBT_MAX_TIME_QUANTA;
+ tqMin = FDCBT_MIN_TIME_QUANTA;
+ pdivMAX = MAX_FPRESDIV;
+#endif
+
+ if (bitRate != bitRateFD)
+ {
+ /* To minimize errors when processing FD frames, try to get the same bit rate prescaler value for nominal phase
+ and data phase. */
+ do
+ {
+ clk = bitRateFD * tqTemp;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqTemp too large, clk x tqTemp has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* the frequency of clock source is not divisible by target bit rate. */
+ }
+
+ pTimingConfig->fpreDivider = (uint16_t)(sourceClock_Hz / clk) - 1U;
+
+ if (pTimingConfig->fpreDivider > pdivMAX)
+ {
+ break; /* The frequency of source clock is too large or the bit rate is too small, the pre-divider
+ could not handle it. */
+ }
+
+ /* Calculates the best data phase timing configuration. */
+ FLEXCAN_FDGetSegments(bitRateFD, tqTemp, pTimingConfig);
+
+ if (FLEXCAN_CalculateImprovedNominalTimingValues(
+ bitRate, sourceClock_Hz / ((uint32_t)pTimingConfig->fpreDivider + 1U), pTimingConfig))
+ {
+ fgRet = true;
+ if (pTimingConfig->preDivider == 0U)
+ {
+ pTimingConfig->preDivider = pTimingConfig->fpreDivider;
+ break;
+ }
+ else
+ {
+ pTimingConfig->preDivider =
+ (pTimingConfig->preDivider + 1U) * (pTimingConfig->fpreDivider + 1U) - 1U;
+ continue;
+ }
+ }
+ } while (--tqTemp >= tqMin);
+ }
+ else
+ {
+ if (FLEXCAN_CalculateImprovedNominalTimingValues(bitRate, sourceClock_Hz, pTimingConfig))
+ {
+ /* No need data phase timing configuration, data phase rate equal to nominal phase rate, user don't use Brs
+ feature. */
+ pTimingConfig->fpreDivider = 0U;
+ pTimingConfig->frJumpwidth = 0U;
+ pTimingConfig->fphaseSeg1 = 0U;
+ pTimingConfig->fphaseSeg2 = 0U;
+ pTimingConfig->fpropSeg = 0U;
+ fgRet = true;
+ }
+ }
+ return fgRet;
+}
+
+/*!
+ * brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetFDTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint8_t cnt = 0;
+ uint8_t payload_dword = 1;
+ uint32_t dataSize;
+ dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ uint32_t availoffset = FLEXCAN_GetFDMailboxOffset(base, FLEXCAN_GetFirstValidMb(base));
+#endif
+
+ /* Inactivate Message Buffer. */
+ if (enable)
+ {
+ /* Inactivate by writing CS. */
+ mbAddr[offset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ }
+ else
+ {
+ mbAddr[offset] = 0x0;
+ }
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Clean ID. */
+ mbAddr[offset + 1U] = 0x0U;
+ /* Clean Message Buffer content, DWORD by DWORD. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = 0x0U;
+ }
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+}
+#endif /* FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE */
+
+/*!
+ * brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(((NULL != pRxMbConfig) || (false == enable)));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+
+ /* Inactivate Message Buffer. */
+ base->MB[mbIdx].CS = 0;
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+
+ if (enable)
+ {
+ /* Setup Message Buffer ID. */
+ base->MB[mbIdx].ID = pRxMbConfig->id;
+
+ /* Setup Message Buffer format. */
+ if (kFLEXCAN_FrameFormatExtend == pRxMbConfig->format)
+ {
+ cs_temp |= CAN_CS_IDE_MASK;
+ }
+
+ /* Setup Message Buffer type. */
+ if (kFLEXCAN_FrameTypeRemote == pRxMbConfig->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ /* Activate Rx Message Buffer. */
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty);
+ base->MB[mbIdx].CS = cs_temp;
+ }
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetFDRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(((NULL != pRxMbConfig) || (false == enable)));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+ uint8_t cnt = 0;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ uint8_t payload_dword;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+
+ /* Inactivate Message Buffer. */
+ mbAddr[offset] = 0U;
+
+ /* Clean Message Buffer content. */
+ mbAddr[offset + 1U] = 0U;
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ payload_dword = (2U << dataSize);
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = 0x0;
+ }
+
+ if (enable)
+ {
+ /* Setup Message Buffer ID. */
+ mbAddr[offset + 1U] = pRxMbConfig->id;
+
+ /* Setup Message Buffer format. */
+ if (kFLEXCAN_FrameFormatExtend == pRxMbConfig->format)
+ {
+ cs_temp |= CAN_CS_IDE_MASK;
+ }
+
+ /* Setup Message Buffer type. */
+ if (kFLEXCAN_FrameTypeRemote == pRxMbConfig->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ /* Activate Rx Message Buffer. */
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty);
+ mbAddr[offset] = cs_temp;
+ }
+}
+#endif
+
+/*!
+ * brief Configures the FlexCAN Legacy Rx FIFO.
+ *
+ * This function configures the FlexCAN Rx FIFO with given configuration.
+ * note Legacy Rx FIFO only can receive classic CAN message.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFifoConfig Pointer to the FlexCAN Legacy Rx FIFO configuration structure. Can be NULL when enable parameter
+ * is false.
+ * param enable Enable/disable Legacy Rx FIFO.
+ * - true: Enable Legacy Rx FIFO.
+ * - false: Disable Legacy Rx FIFO.
+ */
+void FLEXCAN_SetRxFifoConfig(CAN_Type *base, const flexcan_rx_fifo_config_t *pRxFifoConfig, bool enable)
+{
+ /* Assertion. */
+ assert((NULL != pRxFifoConfig) || (false == enable));
+
+ volatile uint32_t *mbAddr;
+ uint8_t i, j, k, rffn = 0, numMbOccupy;
+ uint32_t setup_mb = 0;
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ if (enable)
+ {
+ assert(pRxFifoConfig->idFilterNum <= 128U);
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /* Legacy Rx FIFO and Enhanced Rx FIFO cannot be enabled at the same time. */
+ assert((base->ERFCR & CAN_ERFCR_ERFEN_MASK) == 0U);
+#endif
+
+ /* Get the setup_mb value. */
+ setup_mb = (uint8_t)((base->MCR & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT);
+ setup_mb = (setup_mb < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)) ?
+ setup_mb :
+ (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base);
+
+ /* Determine RFFN value. */
+ for (i = 0; i <= 0xFU; i++)
+ {
+ if ((8U * (i + 1U)) >= pRxFifoConfig->idFilterNum)
+ {
+ rffn = i;
+ assert(((setup_mb - 8U) - (2U * rffn)) > 0U);
+
+ base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_RFFN_MASK) | CAN_CTRL2_RFFN(rffn);
+ break;
+ }
+ }
+
+ /* caculate the Number of Mailboxes occupied by RX Legacy FIFO and the filter. */
+ numMbOccupy = 6U + (rffn + 1U) * 2U;
+
+ /* Copy ID filter table to Message Buffer Region (Fix MISRA_C-2012 Rule 18.1). */
+ j = 0U;
+ for (i = 6U; i < numMbOccupy; i++)
+ {
+ /* Get address for current mail box. */
+ mbAddr = &(base->MB[i].CS);
+
+ /* One Mail box contain 4U DWORD registers. */
+ for (k = 0; k < 4U; k++)
+ {
+ /* Fill all valid filter in the mail box occupied by filter.
+ * Disable unused Rx FIFO Filter, the other rest of register in the last Mail box occupied by fiter set
+ * as 0xffffffff.
+ */
+ mbAddr[k] = (j < pRxFifoConfig->idFilterNum) ? (pRxFifoConfig->idFilterTable[j]) : 0xFFFFFFFFU;
+
+ /* Try to fill next filter in current Mail Box. */
+ j++;
+ }
+ }
+
+ /* Setup ID Fitlter Type. */
+ switch (pRxFifoConfig->idFilterType)
+ {
+ case kFLEXCAN_RxFifoFilterTypeA:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x0);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeB:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x1);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeC:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x2);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeD:
+ /* All frames rejected. */
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x3);
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ /* Setting Message Reception Priority. */
+ base->CTRL2 = (pRxFifoConfig->priority == kFLEXCAN_RxFifoPrioHigh) ? (base->CTRL2 & ~CAN_CTRL2_MRP_MASK) :
+ (base->CTRL2 | CAN_CTRL2_MRP_MASK);
+
+ /* Enable Rx Message FIFO. */
+ base->MCR |= CAN_MCR_RFEN_MASK;
+ }
+ else
+ {
+ rffn = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ /* caculate the Number of Mailboxes occupied by RX Legacy FIFO and the filter. */
+ numMbOccupy = 6U + (rffn + 1U) * 2U;
+
+ /* Disable Rx Message FIFO. */
+ base->MCR &= ~CAN_MCR_RFEN_MASK;
+
+ /* Clean MB0 ~ MB5 and all MB occupied by ID filters (Fix MISRA_C-2012 Rule 18.1). */
+
+ for (i = 0; i < numMbOccupy; i++)
+ {
+ FLEXCAN_SetRxMbConfig(base, i, NULL, false);
+ }
+ }
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Configures the FlexCAN Enhanced Rx FIFO.
+ *
+ * This function configures the Enhanced Rx FIFO with given configuration.
+ * note Enhanced Rx FIFO support receive classic CAN or CAN FD messages, Legacy Rx FIFO and Enhanced Rx FIFO
+ * cannot be enabled at the same time.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the FlexCAN Enhanced Rx FIFO configuration structure. Can be NULL when enable parameter
+ * is false.
+ * param enable Enable/disable Enhanced Rx FIFO.
+ * - true: Enable Enhanced Rx FIFO.
+ * - false: Disable Enhanced Rx FIFO.
+ */
+void FLEXCAN_SetEnhancedRxFifoConfig(CAN_Type *base, const flexcan_enhanced_rx_fifo_config_t *pConfig, bool enable)
+{
+ /* Assertion. */
+ assert((NULL != pConfig) || (false == enable));
+ uint32_t i;
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ if (enable)
+ {
+ /* Each pair of filter elements occupies 2 words and can consist of one extended ID filter element or two
+ * standard ID filter elements. */
+ assert((((uint32_t)pConfig->idFilterPairNum * 2UL) <
+ (uint32_t)FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO_FILTER_MAX_NUMBER) &&
+ (pConfig->extendIdFilterNum <= pConfig->idFilterPairNum) && (0UL != pConfig->idFilterPairNum));
+
+ /* The Enhanced Rx FIFO Watermark cannot be greater than the enhanced Rx FIFO size. */
+ assert(pConfig->fifoWatermark < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO_SIZE);
+
+ /* Legacy Rx FIFO and Enhanced Rx FIFO cannot be enabled at the same time. */
+ assert((base->MCR & CAN_MCR_RFEN_MASK) == 0U);
+
+ /* Reset Enhanced Rx FIFO engine and clear flags. */
+ base->ERFSR |= CAN_ERFSR_ERFCLR_MASK | CAN_ERFSR_ERFUFW_MASK | CAN_ERFSR_ERFOVF_MASK | CAN_ERFSR_ERFWMI_MASK |
+ CAN_ERFSR_ERFDA_MASK;
+ /* Setting Enhanced Rx FIFO. */
+ base->ERFCR = CAN_ERFCR_DMALW(pConfig->dmaPerReadLength) | CAN_ERFCR_NEXIF(pConfig->extendIdFilterNum) |
+ CAN_ERFCR_NFE((uint32_t)pConfig->idFilterPairNum - 1UL) | CAN_ERFCR_ERFWM(pConfig->fifoWatermark);
+ /* Copy ID filter table to Enhanced Rx FIFO Filter Element registers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO_FILTER_MAX_NUMBER; i++)
+ {
+ base->ERFFEL[i] = (i < ((uint32_t)pConfig->idFilterPairNum * 2U)) ? pConfig->idFilterTable[i] : 0xFFFFFFFFU;
+ }
+
+ /* Setting Message Reception Priority. */
+ base->CTRL2 = (pConfig->priority == kFLEXCAN_RxFifoPrioHigh) ? (base->CTRL2 & ~CAN_CTRL2_MRP_MASK) :
+ (base->CTRL2 | CAN_CTRL2_MRP_MASK);
+ /* Enable Enhanced Rx FIFO. */
+ base->ERFCR |= CAN_ERFCR_ERFEN_MASK;
+ }
+ else
+ {
+ /* Disable Enhanced Rx FIFO. */
+ base->ERFCR = 0U;
+ /* Reset Enhanced Rx FIFO engine and clear flags. */
+ base->ERFSR |= CAN_ERFSR_ERFCLR_MASK | CAN_ERFSR_ERFUFW_MASK | CAN_ERFSR_ERFOVF_MASK | CAN_ERFSR_ERFWMI_MASK |
+ CAN_ERFSR_ERFDA_MASK;
+ /* Clean all Enhanced Rx FIFO Filter Element registers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO_FILTER_MAX_NUMBER; i++)
+ {
+ base->ERFFEL[i] = 0xFFFFFFFFU;
+ }
+ }
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA) && FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA)
+/*!
+ * brief Enables or disables the FlexCAN Legacy/Enhanced Rx FIFO DMA request.
+ *
+ * This function enables or disables the DMA feature of FlexCAN build-in Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param enable true to enable, false to disable.
+ */
+void FLEXCAN_EnableRxFifoDMA(CAN_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Enable FlexCAN DMA. */
+ base->MCR |= CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+ else
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Disable FlexCAN DMA. */
+ base->MCR &= ~CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+}
+#endif /* FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA */
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+/*!
+ * brief Gets the FlexCAN Memory Error Report registers status.
+ *
+ * This function gets the FlexCAN Memory Error Report registers status.
+ *
+ * param base FlexCAN peripheral base address.
+ * param errorStatus Pointer to FlexCAN Memory Error Report registers status structure.
+ */
+void FLEXCAN_GetMemoryErrorReportStatus(CAN_Type *base, flexcan_memory_error_report_status_t *errorStatus)
+{
+ uint32_t temp;
+ /* Disable updates of the error report registers. */
+ base->MECR |= CAN_MECR_RERRDIS_MASK;
+
+ errorStatus->accessAddress = (uint16_t)(base->RERRAR & CAN_RERRAR_ERRADDR_MASK);
+ errorStatus->errorData = base->RERRDR;
+ errorStatus->errorType =
+ (base->RERRAR & CAN_RERRAR_NCE_MASK) == 0U ? kFLEXCAN_CorrectableError : kFLEXCAN_NonCorrectableError;
+
+ temp = (base->RERRAR & CAN_RERRAR_SAID_MASK) >> CAN_RERRAR_SAID_SHIFT;
+ switch (temp)
+ {
+ case (uint32_t)kFLEXCAN_MoveOutFlexCanAccess:
+ case (uint32_t)kFLEXCAN_MoveInAccess:
+ case (uint32_t)kFLEXCAN_TxArbitrationAccess:
+ case (uint32_t)kFLEXCAN_RxMatchingAccess:
+ case (uint32_t)kFLEXCAN_MoveOutHostAccess:
+ errorStatus->accessType = (flexcan_memory_access_type_t)temp;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ for (uint32_t i = 0; i < 4U; i++)
+ {
+ temp = (base->RERRSYNR & ((uint32_t)CAN_RERRSYNR_SYND0_MASK << (i * 8U))) >> (i * 8U);
+ errorStatus->byteStatus[i].byteIsRead = (base->RERRSYNR & ((uint32_t)CAN_RERRSYNR_BE0_MASK << (i * 8U))) != 0U;
+ switch (temp)
+ {
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_NoError):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_ParityBits0Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_ParityBits1Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_ParityBits2Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_ParityBits3Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_ParityBits4Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits0Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits1Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits2Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits3Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits4Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits5Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits6Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_DataBits7Error):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_AllZeroError):
+ case CAN_RERRSYNR_SYND0(kFLEXCAN_AllOneError):
+ errorStatus->byteStatus[i].bitAffected = (flexcan_byte_error_syndrome_t)temp;
+ break;
+ default:
+ errorStatus->byteStatus[i].bitAffected = kFLEXCAN_NonCorrectableErrors;
+ break;
+ }
+ }
+
+ /* Re-enable updates of the error report registers. */
+ base->MECR &= CAN_MECR_RERRDIS_MASK;
+}
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+/*!
+ * FlexCAN: A frame with wrong ID or payload is transmitted into
+ * the CAN bus when the Message Buffer under transmission is
+ * either aborted or deactivated while the CAN bus is in the Bus Idle state
+ *
+ * This function to do workaround for ERR006032
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+static void FLEXCAN_ERRATA_6032(CAN_Type *base, volatile uint32_t *mbCSAddr)
+{
+ uint32_t dbg_temp = 0U;
+ uint32_t u32TempCS = 0U;
+ uint32_t u32Timeout = DELAY_BUSIDLE;
+ /*disable ALL interrupts to prevent any context switching*/
+ uint32_t irqMask = DisableGlobalIRQ();
+ dbg_temp = (uint32_t)(base->DBG1);
+ switch (dbg_temp & CAN_DBG1_CFSM_MASK)
+ {
+ case RXINTERMISSION:
+ if (CBN_VALUE3 == (dbg_temp & CAN_DBG1_CBN_MASK))
+ {
+ /*wait until CFSM is different from RXINTERMISSION */
+ while (RXINTERMISSION == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ __NOP();
+ }
+ }
+ break;
+ case TXINTERMISSION:
+ if (CBN_VALUE3 == (dbg_temp & CAN_DBG1_CBN_MASK))
+ {
+ /*wait until CFSM is different from TXINTERMISSION*/
+ while (TXINTERMISSION == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ __NOP();
+ }
+ }
+ break;
+ default:
+ /* To avoid MISRA-C 2012 rule 16.4 issue. */
+ break;
+ }
+ /*Anyway, BUSIDLE need to delay*/
+ if (BUSIDLE == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ while (u32Timeout-- > 0U)
+ {
+ __NOP();
+ }
+
+ /*Write 0x0 into Code field of CS word.*/
+ u32TempCS = (uint32_t)(*mbCSAddr);
+ u32TempCS &= ~CAN_CS_CODE_MASK;
+ *mbCSAddr = u32TempCS;
+ }
+ /*restore interruption*/
+ EnableGlobalIRQ(irqMask);
+}
+#endif
+
+/*!
+ * brief Writes a FlexCAN Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN Message transmit. After
+ * that the function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pTxFrame Pointer to CAN message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_frame_t *pTxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pTxFrame);
+ assert(pTxFrame->length <= 8U);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+ status_t status;
+
+ /* Check if Message Buffer is available. */
+ if (CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) != (base->MB[mbIdx].CS & CAN_CS_CODE_MASK))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+ FLEXCAN_ERRATA_6032(base, &(base->MB[mbIdx].CS));
+#endif
+ /* Inactive Tx Message Buffer. */
+ base->MB[mbIdx].CS = (base->MB[mbIdx].CS & ~CAN_CS_CODE_MASK) | CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+
+ /* Fill Message ID field. */
+ base->MB[mbIdx].ID = pTxFrame->id;
+
+ /* Fill Message Format field. */
+ if ((uint32_t)kFLEXCAN_FrameFormatExtend == pTxFrame->format)
+ {
+ cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
+ }
+
+ /* Fill Message Type field. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pTxFrame->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(pTxFrame->length);
+
+ /* Load Message Payload. */
+ base->MB[mbIdx].WORD0 = pTxFrame->dataWord0;
+ base->MB[mbIdx].WORD1 = pTxFrame->dataWord1;
+
+ /* Activate Tx Message Buffer. */
+ base->MB[mbIdx].CS = cs_temp;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ base->MB[FLEXCAN_GetFirstValidMb(base)].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ base->MB[FLEXCAN_GetFirstValidMb(base)].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Tx Message Buffer is activated, return immediately. */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Writes a FlexCAN FD Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN FD Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN FD Message transmit. After
+ * that the function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pTxFrame Pointer to CAN FD message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteFDTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_fd_frame_t *pTxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pTxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ status_t status;
+ uint32_t cs_temp = 0;
+ uint8_t cnt = 0;
+ uint32_t can_cs = 0;
+ uint8_t payload_dword = 1;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ uint32_t availoffset = FLEXCAN_GetFDMailboxOffset(base, FLEXCAN_GetFirstValidMb(base));
+#endif
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+
+ can_cs = mbAddr[offset];
+ /* Check if Message Buffer is available. */
+ if (CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) != (can_cs & CAN_CS_CODE_MASK))
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+ FLEXCAN_ERRATA_6032(base, &(mbAddr[offset]));
+#endif
+ /* Inactive Tx Message Buffer and Fill Message ID field. */
+ mbAddr[offset] = (can_cs & ~CAN_CS_CODE_MASK) | CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ mbAddr[offset + 1U] = pTxFrame->id;
+
+ /* Fill Message Format field. */
+ if ((uint32_t)kFLEXCAN_FrameFormatExtend == pTxFrame->format)
+ {
+ cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
+ }
+
+ /* Fill Message Type field. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pTxFrame->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(pTxFrame->length) | CAN_CS_EDL(1) |
+ CAN_CS_BRS(pTxFrame->brs);
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Load Message Payload and Activate Tx Message Buffer. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = pTxFrame->dataWord[cnt];
+ }
+ mbAddr[offset] = cs_temp;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Tx Message Buffer is activated, return immediately. */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Reads a FlexCAN Message from Receive Message Buffer.
+ *
+ * This function reads a CAN message from a specified Receive Message Buffer.
+ * The function fills a receive CAN message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pRxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp;
+ uint32_t rx_code;
+ status_t status;
+
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[mbIdx].CS;
+ /* Get Rx Message Buffer Code field. */
+ rx_code = (cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT;
+
+ /* Check to see if Rx Message Buffer is full. */
+ if (((uint32_t)kFLEXCAN_RxMbFull == rx_code) || ((uint32_t)kFLEXCAN_RxMbOverrun == rx_code))
+ {
+ /* Store Message ID. */
+ pRxFrame->id = base->MB[mbIdx].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Store Message Payload. */
+ pRxFrame->dataWord0 = base->MB[mbIdx].WORD0;
+ pRxFrame->dataWord1 = base->MB[mbIdx].WORD1;
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ if ((uint32_t)kFLEXCAN_RxMbFull == rx_code)
+ {
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxOverflow;
+ }
+ }
+ else
+ {
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Reads a FlexCAN FD Message from Receive Message Buffer.
+ *
+ * This function reads a CAN FD message from a specified Receive Message Buffer.
+ * The function fills a receive CAN FD message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadFDRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pRxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ status_t status;
+ uint32_t cs_temp;
+ uint8_t rx_code;
+ uint8_t cnt = 0;
+ uint32_t can_id = 0;
+ uint32_t dataSize;
+ dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ uint8_t payload_dword = 1;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = mbAddr[offset];
+ can_id = mbAddr[offset + 1U];
+
+ /* Get Rx Message Buffer Code field. */
+ rx_code = (uint8_t)((cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT);
+
+ /* Check to see if Rx Message Buffer is full. */
+ if (((uint8_t)kFLEXCAN_RxMbFull == rx_code) || ((uint8_t)kFLEXCAN_RxMbOverrun == rx_code))
+ {
+ /* Store Message ID. */
+ pRxFrame->id = can_id & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Store Message Payload. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ pRxFrame->dataWord[cnt] = mbAddr[offset + 2U + cnt];
+ }
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ if ((uint32_t)kFLEXCAN_RxMbFull == rx_code)
+ {
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxOverflow;
+ }
+ }
+ else
+ {
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Reads a FlexCAN Message from Legacy Rx FIFO.
+ *
+ * This function reads a CAN message from the FlexCAN Legacy Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_ReadRxFifo(CAN_Type *base, flexcan_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(NULL != pRxFrame);
+
+ uint32_t cs_temp;
+ status_t status;
+
+ /* Check if Legacy Rx FIFO is Enabled. */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[0].CS;
+
+ /* Read data from Rx FIFO output port. */
+ /* Store Message ID. */
+ pRxFrame->id = base->MB[0].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Store Message Payload. */
+ pRxFrame->dataWord0 = base->MB[0].WORD0;
+ pRxFrame->dataWord1 = base->MB[0].WORD1;
+
+ /* Store ID Filter Hit Index. */
+ pRxFrame->idhit = (uint16_t)(base->RXFIR & CAN_RXFIR_IDHIT_MASK);
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Reads a FlexCAN Message from Enhanced Rx FIFO.
+ *
+ * This function reads a CAN or CAN FD message from the FlexCAN Enhanced Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_ReadEnhancedRxFifo(CAN_Type *base, flexcan_fd_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(NULL != pRxFrame);
+
+ status_t status;
+ uint32_t idHitOff;
+
+ /* Check if Enhanced Rx FIFO is Enabled. */
+ if (0U != (base->ERFCR & CAN_ERFCR_ERFEN_MASK))
+ {
+ /* Enhanced Rx FIFO ID HIT offset is changed dynamically according to data length code (DLC) . */
+ idHitOff = (DLC_LENGTH_DECODE(((flexcan_fd_frame_t *)E_RX_FIFO(base))->length) + 3U) / 4U + 3U;
+ /* Copy CAN FD Message from Enhanced Rx FIFO, should use the DLC value to identify the bytes that belong to the
+ * message which is being read. */
+ (void)memcpy((void *)pRxFrame, (void *)(uint32_t *)E_RX_FIFO(base), sizeof(uint32_t) * idHitOff);
+ pRxFrame->idhit = pRxFrame->dataWord[idHitOff - 3U];
+ /* Clear the unused frame data. */
+ for (uint32_t i = (idHitOff - 3U); i < 16U; i++)
+ {
+ pRxFrame->dataWord[i] = 0x0;
+ }
+
+ /* Clear data available flag to let FlexCAN know one frame has been read from the Enhanced Rx FIFO. */
+ base->ERFSR = CAN_ERFSR_ERFDA_MASK;
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Performs a polling send transaction on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pTxFrame Pointer to CAN message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pTxFrame)
+{
+ status_t status;
+
+ /* Write Tx Message Buffer to initiate a data sending. */
+ if (kStatus_Success == FLEXCAN_WriteTxMb(base, mbIdx, (const flexcan_frame_t *)(uintptr_t)pTxFrame))
+ {
+/* Wait until CAN Message send out. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Tx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+ /*After TX MB tranfered success, update the Timestamp from MB[mbIdx].CS register*/
+ pTxFrame->timestamp = (uint16_t)((base->MB[mbIdx].CS & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Performs a polling receive transaction on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame)
+{
+/* Wait until Rx Message Buffer non-empty. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Rx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+
+ /* Read Received CAN Message. */
+ return FLEXCAN_ReadRxMb(base, mbIdx, pRxFrame);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Performs a polling send transaction on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pTxFrame Pointer to CAN FD message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferFDSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pTxFrame)
+{
+ status_t status;
+
+ /* Write Tx Message Buffer to initiate a data sending. */
+ if (kStatus_Success == FLEXCAN_WriteFDTxMb(base, mbIdx, (const flexcan_fd_frame_t *)(uintptr_t)pTxFrame))
+ {
+/* Wait until CAN Message send out. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Tx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+ /*After TX MB tranfered success, update the Timestamp from base->MB[offset for CAN FD].CS register*/
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ pTxFrame->timestamp = (uint16_t)((mbAddr[offset] & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Performs a polling receive transaction on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferFDReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame)
+{
+/* Wait until Rx Message Buffer non-empty. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Rx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+
+ /* Read Received CAN Message. */
+ return FLEXCAN_ReadFDRxMb(base, mbIdx, pRxFrame);
+}
+#endif
+
+/*!
+ * brief Performs a polling receive transaction from Legacy Rx FIFO on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_TransferReceiveFifoBlocking(CAN_Type *base, flexcan_frame_t *pRxFrame)
+{
+ status_t rxFifoStatus;
+
+ /* Wait until Legacy Rx FIFO non-empty. */
+ while (0U == FLEXCAN_GetMbStatusFlags(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag))
+ {
+ }
+
+ /* Read data from Legacy Rx FIFO. */
+ rxFifoStatus = FLEXCAN_ReadRxFifo(base, pRxFrame);
+
+ /* Clean Rx Fifo available flag. */
+ FLEXCAN_ClearMbStatusFlags(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+
+ return rxFifoStatus;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Performs a polling receive transaction from Enhanced Rx FIFO on the CAN bus.
+ *
+ * note A transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_TransferReceiveEnhancedFifoBlocking(CAN_Type *base, flexcan_fd_frame_t *pRxFrame)
+{
+ status_t rxFifoStatus;
+
+ /* Wait until Enhanced Rx FIFO non-empty. */
+ while (0U == (FLEXCAN_GetStatusFlags(base) & (uint64_t)kFLEXCAN_ERxFifoDataAvlIntFlag))
+ {
+ }
+
+ /* Read data from Enhanced Rx FIFO */
+ rxFifoStatus = FLEXCAN_ReadEnhancedRxFifo(base, pRxFrame);
+
+ return rxFifoStatus;
+}
+#endif
+
+/*!
+ * brief Initializes the FlexCAN handle.
+ *
+ * This function initializes the FlexCAN handle, which can be used for other FlexCAN
+ * transactional APIs. Usually, for a specified FlexCAN instance,
+ * call this API once to get the initialized handle.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ */
+void FLEXCAN_TransferCreateHandle(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint8_t instance;
+
+ /* Clean FlexCAN transfer handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Get instance from peripheral base address. */
+ instance = (uint8_t)FLEXCAN_GetInstance(base);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_flexcanHandle[instance] = handle;
+
+ /* Register Callback function. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ s_flexcanIsr = FLEXCAN_TransferHandleIRQ;
+
+ /* We Enable Error & Status interrupt here, because this interrupt just
+ * report current status of FlexCAN module through Callback function.
+ * It is insignificance without a available callback function.
+ */
+ if (handle->callback != NULL)
+ {
+ FLEXCAN_EnableInterrupts(
+ base, (uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable |
+ (uint32_t)kFLEXCAN_WakeUpInterruptEnable
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ | (uint64_t)kFLEXCAN_PNMatchWakeUpInterruptEnable |
+ (uint64_t)kFLEXCAN_PNTimeoutWakeUpInterruptEnable
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ | (uint64_t)kFLEXCAN_HostAccessNCErrorInterruptEnable |
+ (uint64_t)kFLEXCAN_FlexCanAccessNCErrorInterruptEnable |
+ (uint64_t)kFLEXCAN_HostOrFlexCanCErrorInterruptEnable
+#endif
+ );
+ }
+ else
+ {
+ FLEXCAN_DisableInterrupts(
+ base, (uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable |
+ (uint32_t)kFLEXCAN_WakeUpInterruptEnable
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ | (uint64_t)kFLEXCAN_PNMatchWakeUpInterruptEnable |
+ (uint64_t)kFLEXCAN_PNTimeoutWakeUpInterruptEnable
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ | (uint64_t)kFLEXCAN_HostAccessNCErrorInterruptEnable |
+ (uint64_t)kFLEXCAN_FlexCanAccessNCErrorInterruptEnable |
+ (uint64_t)kFLEXCAN_HostOrFlexCanCErrorInterruptEnable
+#endif
+ );
+ }
+
+ /* Enable interrupts in NVIC. */
+ (void)EnableIRQ((IRQn_Type)(s_flexcanRxWarningIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanTxWarningIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanWakeUpIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanErrorIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanBusOffIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanMbIRQ[instance]));
+}
+
+/*!
+ * brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * retval kStatus_Fail Write Tx Message Buffer failed.
+ * retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ /* Distinguish transmit type. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pMbXfer->frame->type)
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxRemote;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxData;
+ }
+
+ if (kStatus_Success ==
+ FLEXCAN_WriteTxMb(base, pMbXfer->mbIdx, (const flexcan_frame_t *)(uintptr_t)pMbXfer->frame))
+ {
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+ status = kStatus_Success;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+ status = kStatus_Fail;
+ }
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_TxBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ status_t status;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateRxData;
+
+ /* Register Message Buffer. */
+ handle->mbFrameBuf[pMbXfer->mbIdx] = pMbXfer->frame;
+
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxBusy;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * retval kStatus_Fail Write Tx Message Buffer failed.
+ * retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ /* Distinguish transmit type. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pMbXfer->framefd->type)
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxRemote;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxData;
+ }
+
+ if (kStatus_Success ==
+ FLEXCAN_WriteFDTxMb(base, pMbXfer->mbIdx, (const flexcan_fd_frame_t *)(uintptr_t)pMbXfer->framefd))
+ {
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+ status = kStatus_Fail;
+ }
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_TxBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateRxData;
+
+ /* Register Message Buffer. */
+ handle->mbFDFrameBuf[pMbXfer->mbIdx] = pMbXfer->framefd;
+
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxBusy;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Receives a message from Legacy Rx FIFO using IRQ.
+ *
+ * This function receives a message using IRQ. This is a non-blocking function, which returns
+ * right away. When all messages have been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pFifoXfer FlexCAN Rx FIFO transfer structure. See the ref flexcan_fifo_transfer_t.
+ * retval kStatus_Success - Start Rx FIFO receiving process successfully.
+ * retval kStatus_FLEXCAN_RxFifoBusy - Rx FIFO is currently in use.
+ */
+status_t FLEXCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pFifoXfer);
+
+ status_t status;
+ uint32_t irqMask = (uint32_t)kFLEXCAN_RxFifoOverflowFlag | (uint32_t)kFLEXCAN_RxFifoWarningFlag;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->rxFifoState)
+ {
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateRxFifo;
+
+ /* Register Message Buffer. */
+ handle->rxFifoFrameBuf = pFifoXfer->frame;
+ handle->rxFifoFrameNum = pFifoXfer->frameNum;
+ handle->rxFifoTransferTotalNum = pFifoXfer->frameNum;
+
+ if (handle->rxFifoTransferTotalNum < 5U)
+ {
+ /* Enable data available interrupt. */
+ irqMask |= (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag;
+ }
+
+ /* Enable Message Buffer Interrupt. */
+ FLEXCAN_EnableMbInterrupts(base, irqMask);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets the Legacy Rx Fifo transfer status during a interrupt non-blocking receive.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param count Number of CAN messages receive so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_Success Successfully return the count.
+ */
+
+status_t FLEXCAN_TransferGetReceiveFifoCount(CAN_Type *base, flexcan_handle_t *handle, size_t *count)
+{
+ assert(NULL != handle);
+
+ status_t result = kStatus_Success;
+
+ if (handle->rxFifoState == (uint32_t)kFLEXCAN_StateIdle)
+ {
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->rxFifoTransferTotalNum - handle->rxFifoFrameNum;
+ }
+
+ return result;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Receives a message from Enhanced Rx FIFO using IRQ.
+ *
+ * This function receives a message using IRQ. This is a non-blocking function, which returns
+ * right away. When all messages have been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pFifoXfer FlexCAN Rx FIFO transfer structure. See the ref flexcan_fifo_transfer_t.
+ * retval kStatus_Success - Start Rx FIFO receiving process successfully.
+ * retval kStatus_FLEXCAN_RxFifoBusy - Rx FIFO is currently in use.
+ */
+status_t FLEXCAN_TransferReceiveEnhancedFifoNonBlocking(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pFifoXfer);
+
+ status_t status;
+ uint32_t watermark = ((base->ERFCR & CAN_ERFCR_ERFWM_MASK) >> CAN_ERFCR_ERFWM_SHIFT) + 1U;
+ uint64_t irqMask =
+ (uint64_t)kFLEXCAN_ERxFifoUnderflowInterruptEnable | (uint64_t)kFLEXCAN_ERxFifoOverflowInterruptEnable;
+
+ /* Check if Enhanced Rx FIFO is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->rxFifoState)
+ {
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateRxFifo;
+
+ /* Register Message Buffer. */
+ handle->rxFifoFDFrameBuf = pFifoXfer->framefd;
+ handle->rxFifoFrameNum = pFifoXfer->frameNum;
+ handle->rxFifoTransferTotalNum = pFifoXfer->frameNum;
+
+ if (handle->rxFifoTransferTotalNum >= watermark)
+ {
+ /* Enable watermark interrupt. */
+ irqMask |= (uint64_t)kFLEXCAN_ERxFifoWatermarkInterruptEnable;
+ }
+ else
+ {
+ /* Enable data available interrupt. */
+ irqMask |= (uint64_t)kFLEXCAN_ERxFifoDataAvlInterruptEnable;
+ }
+ /* Enable Enhanced Rx FIFO Interrupt. */
+ FLEXCAN_EnableInterrupts(base, irqMask);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ uint16_t timestamp;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Update the TX frame 's time stamp by MB[mbIdx].cs. */
+ timestamp = (uint16_t)((base->MB[mbIdx].CS & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+ handle->timestamp[mbIdx] = timestamp;
+
+ /* Clean Message Buffer. */
+ FLEXCAN_SetTxMbConfig(base, mbIdx, true);
+
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ volatile uint32_t *mbAddr;
+ uint32_t offset;
+ uint16_t timestamp;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Update the TX frame 's time stamp by base->MB[offset for CAN FD].CS. */
+ mbAddr = &(base->MB[0].CS);
+ offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ timestamp = (uint16_t)((mbAddr[offset] & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+ handle->timestamp[mbIdx] = timestamp;
+
+ /* Clean Message Buffer. */
+ FLEXCAN_SetFDTxMbConfig(base, mbIdx, true);
+
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+/*!
+ * brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Un-register handle. */
+ handle->mbFDFrameBuf[mbIdx] = NULL;
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+#endif
+
+/*!
+ * brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, (u64mask << mbIdx));
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, (u32mask << mbIdx));
+#endif
+
+ /* Un-register handle. */
+ handle->mbFrameBuf[mbIdx] = NULL;
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+/*!
+ * brief Aborts the interrupt driven message receive from Legacy Rx FIFO process.
+ *
+ * This function aborts the interrupt driven message receive from Legacy Rx FIFO process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferAbortReceiveFifo(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ /* Check if Rx FIFO is enabled. */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Disable Rx Message FIFO Interrupts. */
+ FLEXCAN_DisableMbInterrupts(base, (uint32_t)kFLEXCAN_RxFifoOverflowFlag | (uint32_t)kFLEXCAN_RxFifoWarningFlag |
+ (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+
+ /* Un-register handle. */
+ handle->rxFifoFrameBuf = NULL;
+ /* Clear transfer count. */
+ handle->rxFifoFrameNum = 0U;
+ handle->rxFifoTransferTotalNum = 0U;
+ }
+
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Aborts the interrupt driven message receive from Enhanced Rx FIFO process.
+ *
+ * This function aborts the interrupt driven message receive from Rx FIFO process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferAbortReceiveEnhancedFifo(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ /* Check if Enhanced Rx FIFO is enabled. */
+ if (0U != (base->ERFCR & CAN_ERFCR_ERFEN_MASK))
+ {
+ /* Disable all Rx Message FIFO interrupts. */
+ FLEXCAN_DisableInterrupts(base, (uint64_t)kFLEXCAN_ERxFifoUnderflowInterruptEnable |
+ (uint64_t)kFLEXCAN_ERxFifoOverflowInterruptEnable |
+ (uint64_t)kFLEXCAN_ERxFifoWatermarkInterruptEnable |
+ (uint64_t)kFLEXCAN_ERxFifoDataAvlInterruptEnable);
+
+ /* Un-register handle. */
+ handle->rxFifoFDFrameBuf = NULL;
+ /* Clear transfer count. */
+ handle->rxFifoFrameNum = 0U;
+ handle->rxFifoTransferTotalNum = 0U;
+ }
+
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateIdle;
+}
+#endif
+
+/*!
+ * brief Gets the detail index of Mailbox's Timestamp by handle.
+ *
+ * Then function can only be used when calling non-blocking Data transfer (TX/RX) API,
+ * After TX/RX data transfer done (User can get the status by handler's callback function),
+ * we can get the detail index of Mailbox's timestamp by handle,
+ * Detail non-blocking data transfer API (TX/RX) contain.
+ * -FLEXCAN_TransferSendNonBlocking
+ * -FLEXCAN_TransferFDSendNonBlocking
+ * -FLEXCAN_TransferReceiveNonBlocking
+ * -FLEXCAN_TransferFDReceiveNonBlocking
+ * -FLEXCAN_TransferReceiveFifoNonBlocking
+ *
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * return the index of mailbox 's timestamp stored in the handle.
+ *
+ */
+uint32_t FLEXCAN_GetTimeStamp(flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ return (uint32_t)(handle->timestamp[mbIdx]);
+}
+
+/*!
+ * brief Check unhandle interrupt events
+ *
+ * param base FlexCAN peripheral base address.
+ * return TRUE if unhandled interrupt action exist, FALSE if no unhandlered interrupt action exist.
+ */
+static bool FLEXCAN_CheckUnhandleInterruptEvents(CAN_Type *base)
+{
+ uint64_t tempmask;
+ uint64_t tempflag;
+ bool fgRet = false;
+
+ if (0U == (FLEXCAN_GetStatusFlags(base) &
+ (FLEXCAN_ERROR_AND_STATUS_INIT_FLAG | FLEXCAN_WAKE_UP_FLAG | FLEXCAN_MEMORY_ENHANCED_RX_FIFO_INIT_FLAG)))
+ {
+ /* If no error, wake_up or enhanced RX FIFO status, Checking whether exist MB interrupt status and legacy RX
+ * FIFO interrupt status */
+ tempmask = (uint64_t)base->IMASK1;
+ tempflag = (uint64_t)base->IFLAG1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ tempmask |= ((uint64_t)base->IMASK2) << 32;
+ tempflag |= ((uint64_t)base->IFLAG2) << 32;
+#endif
+ fgRet = (0U != (tempmask & tempflag));
+ }
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ else if (0U != (FLEXCAN_GetStatusFlags(base) & FLEXCAN_MEMORY_ENHANCED_RX_FIFO_INIT_FLAG))
+ {
+ /* Checking whether exist enhanced RX FIFO interrupt status. */
+ tempmask = (uint64_t)base->ERFIER;
+ tempflag = (uint64_t)base->ERFSR;
+ fgRet = (0U != (tempmask & tempflag));
+ }
+#endif
+ else
+ {
+ /* Exist error or wake up flag. */
+ fgRet = true;
+ }
+
+ return fgRet;
+}
+
+/*!
+ * brief Sub Handler Data Trasfered Events
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pResult Pointer to the Handle result.
+ *
+ * return the status after handle each data transfered event.
+ */
+static status_t FLEXCAN_SubHandlerForDataTransfered(CAN_Type *base, flexcan_handle_t *handle, uint32_t *pResult)
+{
+ status_t status = kStatus_FLEXCAN_UnHandled;
+ uint32_t result = 0xFFU;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t intflag = (((uint64_t)base->IMASK2 & base->IFLAG2) << 32UL) | (base->IMASK1 & base->IFLAG1);
+#else
+ uint32_t intflag = base->IMASK1 & base->IFLAG1;
+#endif
+ /* For this implementation, we solve the Message with lowest MB index first. */
+ for (result = 0U; result < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); result++)
+ {
+ /* Find the lowest unhandled Message Buffer */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ if (0UL != (intflag & ((uint64_t)1UL << result)))
+#else
+ if (0UL != (intflag & ((uint32_t)1UL << result)))
+#endif
+ {
+ break;
+ }
+ }
+
+ /* find Message to deal with. */
+ if (result < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base))
+ {
+ /* Solve Legacy Rx FIFO interrupt. */
+ if (((uint8_t)kFLEXCAN_StateIdle != handle->rxFifoState) && (result <= (uint32_t)CAN_IFLAG1_BUF7I_SHIFT) &&
+ ((base->MCR & CAN_MCR_RFEN_MASK) != 0U))
+ {
+ uint32_t u32mask = 1;
+ switch (u32mask << result)
+ {
+ case kFLEXCAN_RxFifoOverflowFlag:
+ status = kStatus_FLEXCAN_RxFifoOverflow;
+ break;
+
+ case kFLEXCAN_RxFifoWarningFlag:
+ if ((handle->rxFifoFrameNum > 5U) && (0U != (base->IFLAG1 & (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag)))
+ {
+ for (uint32_t i = 0; i < 5UL; i++)
+ {
+ status = FLEXCAN_ReadRxFifo(base, handle->rxFifoFrameBuf);
+
+ if (kStatus_Success == status)
+ {
+ /* Align the current rxfifo timestamp to the timestamp array by handle. */
+ handle->timestamp[i] = handle->rxFifoFrameBuf->timestamp;
+ handle->rxFifoFrameBuf++;
+ handle->rxFifoFrameNum--;
+ /* Clean Rx Fifo available flag to discard the frame that has been read. */
+ FLEXCAN_ClearMbStatusFlags(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxFifoDisabled;
+ }
+ }
+ if (handle->rxFifoFrameNum < 5UL)
+ {
+ /* Enable data avaliable interrupt. */
+ FLEXCAN_EnableMbInterrupts(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+ }
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+ else
+ {
+ /* Should enter case kFLEXCAN_RxFifoFrameAvlFlag but not, means previous transfer may have
+ * overflow*/
+ status = kStatus_FLEXCAN_RxFifoWarning;
+ }
+ break;
+
+ case kFLEXCAN_RxFifoFrameAvlFlag:
+ /* Whether still has CAN messages remaining to be received. */
+ if (handle->rxFifoFrameNum > 0U)
+ {
+ status = FLEXCAN_ReadRxFifo(base, handle->rxFifoFrameBuf);
+ if (kStatus_Success == status)
+ {
+ /* Align the current (index 0) rxfifo timestamp to the timestamp array by handle. */
+ handle->timestamp[0] = handle->rxFifoFrameBuf->timestamp;
+ handle->rxFifoFrameBuf++;
+ handle->rxFifoFrameNum--;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxFifoDisabled;
+ }
+ }
+ if (handle->rxFifoFrameNum == 0U)
+ {
+ /* Stop receiving Ehanced Rx FIFO when the transmission is over. */
+ FLEXCAN_TransferAbortReceiveFifo(base, handle);
+ status = kStatus_FLEXCAN_RxFifoIdle;
+ }
+ else
+ {
+ /* Continue use data avaliable interrupt. */
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+ else
+ {
+ /* Get current State of Message Buffer. */
+ switch (handle->mbState[result])
+ {
+ /* Solve Rx Data Frame. */
+ case (uint8_t)kFLEXCAN_StateRxData:
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ status = FLEXCAN_ReadFDRxMb(base, (uint8_t)result, handle->mbFDFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ /* Align the current index of RX MB timestamp to the timestamp array by handle. */
+ handle->timestamp[result] = handle->mbFDFrameBuf[result]->timestamp;
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ }
+ else
+#endif
+ {
+ status = FLEXCAN_ReadRxMb(base, (uint8_t)result, handle->mbFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ /* Align the current index of RX MB timestamp to the timestamp array by handle. */
+ handle->timestamp[result] = handle->mbFrameBuf[result]->timestamp;
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ }
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortReceive(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortReceive(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Sove Rx Remote Frame. User need to Read the frame in Mail box in time by Read from MB API. */
+ case (uint8_t)kFLEXCAN_StateRxRemote:
+ status = kStatus_FLEXCAN_RxRemote;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortReceive(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortReceive(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Solve Tx Data Frame. */
+ case (uint8_t)kFLEXCAN_StateTxData:
+ status = kStatus_FLEXCAN_TxIdle;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortSend(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortSend(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Solve Tx Remote Frame. */
+ case (uint8_t)kFLEXCAN_StateTxRemote:
+ handle->mbState[result] = (uint8_t)kFLEXCAN_StateRxRemote;
+ status = kStatus_FLEXCAN_TxSwitchToRx;
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+
+ /* Clear resolved Message Buffer IRQ. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << result);
+#else
+ uint32_t u32flag = 1;
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << result);
+#endif
+ }
+
+ *pResult = result;
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * brief Sub Handler Ehanced Rx FIFO event
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param flags FlexCAN interrupt flags.
+ *
+ * return the status after handle Ehanced Rx FIFO event.
+ */
+static status_t FLEXCAN_SubHandlerForEhancedRxFifo(CAN_Type *base, flexcan_handle_t *handle, uint64_t flags)
+{
+ uint32_t watermark = ((base->ERFCR & CAN_ERFCR_ERFWM_MASK) >> CAN_ERFCR_ERFWM_SHIFT) + 1U;
+ uint32_t transferFrames;
+
+ status_t status;
+ /* Solve Ehanced Rx FIFO interrupt. */
+ if ((0u != (flags & (uint64_t)kFLEXCAN_ERxFifoUnderflowIntFlag)) &&
+ (0u != (base->ERFIER & CAN_ERFIER_ERFUFWIE_MASK)))
+ {
+ status = kStatus_FLEXCAN_RxFifoUnderflow;
+ FLEXCAN_ClearStatusFlags(base, (uint64_t)kFLEXCAN_ERxFifoUnderflowIntFlag);
+ }
+ else if ((0u != (flags & (uint64_t)kFLEXCAN_ERxFifoOverflowIntFlag)) &&
+ (0u != (base->ERFIER & CAN_ERFIER_ERFOVFIE_MASK)))
+ {
+ status = kStatus_FLEXCAN_RxFifoOverflow;
+ FLEXCAN_ClearStatusFlags(base, (uint64_t)kFLEXCAN_ERxFifoOverflowIntFlag);
+ }
+ else if ((0u != (flags & (uint64_t)kFLEXCAN_ERxFifoWatermarkIntFlag)) &&
+ (0u != (base->ERFIER & CAN_ERFIER_ERFWMIIE_MASK)))
+ {
+ /* Whether the number of CAN messages remaining to be received is greater than the watermark. */
+ transferFrames = (handle->rxFifoFrameNum > watermark) ? watermark : handle->rxFifoFrameNum;
+
+ for (uint32_t i = 0; i < transferFrames; i++)
+ {
+ status = FLEXCAN_ReadEnhancedRxFifo(base, handle->rxFifoFDFrameBuf);
+
+ if (kStatus_Success == status)
+ {
+ handle->rxFifoFDFrameBuf++;
+ handle->rxFifoFrameNum--;
+ /* Clear data Watermark flag due to has read back one frame. */
+ base->ERFSR = CAN_ERFSR_ERFWMI_MASK;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxFifoDisabled;
+ }
+ }
+ if (handle->rxFifoFrameNum == 0U)
+ {
+ /* Stop receiving Ehanced Rx FIFO when the transmission is over. */
+ FLEXCAN_TransferAbortReceiveEnhancedFifo(base, handle);
+ status = kStatus_FLEXCAN_RxFifoIdle;
+ }
+ else if (handle->rxFifoFrameNum < watermark)
+ {
+ /* Disable watermark interrupt and enable data avaliable interrupt. */
+ FLEXCAN_DisableInterrupts(base, (uint64_t)kFLEXCAN_ERxFifoWatermarkInterruptEnable);
+ FLEXCAN_EnableInterrupts(base, (uint64_t)kFLEXCAN_ERxFifoDataAvlInterruptEnable);
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+ else
+ {
+ /* Continue use watermark interrupt. */
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+ }
+ else
+ {
+ /* Data available status, check Whether still has CAN messages remaining to be received. */
+ if (handle->rxFifoFrameNum > 0U)
+ {
+ status = FLEXCAN_ReadEnhancedRxFifo(base, handle->rxFifoFDFrameBuf);
+
+ if (kStatus_Success == status)
+ {
+ handle->rxFifoFDFrameBuf++;
+ handle->rxFifoFrameNum--;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxFifoDisabled;
+ }
+ }
+ if (handle->rxFifoFrameNum == 0U)
+ {
+ /* Stop receiving Ehanced Rx FIFO when the transmission is over. */
+ FLEXCAN_TransferAbortReceiveEnhancedFifo(base, handle);
+ status = kStatus_FLEXCAN_RxFifoIdle;
+ }
+ else
+ {
+ /* Continue use data avaliable interrupt. */
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+ }
+ return status;
+}
+#endif
+
+/*!
+ * brief FlexCAN IRQ handle function.
+ *
+ * This function handles the FlexCAN Error, the Message Buffer, and the Rx FIFO IRQ request.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferHandleIRQ(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ status_t status;
+ uint32_t mbNum = 0xFFU;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ uint64_t result = 0U;
+#else
+ uint32_t result = 0U;
+#endif
+ do
+ {
+ /* Get Current FlexCAN Module Error and Status. */
+ result = FLEXCAN_GetStatusFlags(base);
+
+ /* To handle FlexCAN Error and Status Interrupt first. */
+ if (0U != (result & FLEXCAN_ERROR_AND_STATUS_INIT_FLAG))
+ {
+ status = kStatus_FLEXCAN_ErrorStatus;
+ /* Clear FlexCAN Error and Status Interrupt. */
+ FLEXCAN_ClearStatusFlags(base, FLEXCAN_ERROR_AND_STATUS_INIT_FLAG);
+ }
+ else if (0U != (result & FLEXCAN_WAKE_UP_FLAG))
+ {
+ status = kStatus_FLEXCAN_WakeUp;
+ FLEXCAN_ClearStatusFlags(base, FLEXCAN_WAKE_UP_FLAG);
+ }
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ else if (0U != (FLEXCAN_EFIFO_STATUS_UNMASK(result & FLEXCAN_MEMORY_ENHANCED_RX_FIFO_INIT_FLAG) & base->ERFIER))
+ {
+ status = FLEXCAN_SubHandlerForEhancedRxFifo(base, handle, result);
+ }
+#endif
+ else
+ {
+ /* To handle Message Buffer or Legacy Rx FIFO transfer. */
+ status = FLEXCAN_SubHandlerForDataTransfered(base, handle, &mbNum);
+ result = mbNum;
+ }
+
+ /* Calling Callback Function if has one. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, status, result, handle->userData);
+ }
+ } while (FLEXCAN_CheckUnhandleInterruptEvents(base));
+}
+
+#if defined(CAN0)
+void CAN0_DriverIRQHandler(void);
+void CAN0_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[0]);
+
+ s_flexcanIsr(CAN0, s_flexcanHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN1)
+void CAN1_DriverIRQHandler(void);
+void CAN1_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[1]);
+
+ s_flexcanIsr(CAN1, s_flexcanHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN2)
+void CAN2_DriverIRQHandler(void);
+void CAN2_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[2]);
+
+ s_flexcanIsr(CAN2, s_flexcanHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN3)
+void CAN3_DriverIRQHandler(void);
+void CAN3_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[3]);
+
+ s_flexcanIsr(CAN3, s_flexcanHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN4)
+void CAN4_DriverIRQHandler(void);
+void CAN4_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[4]);
+
+ s_flexcanIsr(CAN4, s_flexcanHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN0)
+void DMA_FLEXCAN0_INT_DriverIRQHandler(void);
+void DMA_FLEXCAN0_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN0)]);
+
+ s_flexcanIsr(DMA__CAN0, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN1)
+void DMA_FLEXCAN1_INT_DriverIRQHandler(void);
+void DMA_FLEXCAN1_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN1)]);
+
+ s_flexcanIsr(DMA__CAN1, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN2)
+void DMA_FLEXCAN2_INT_DriverIRQHandler(void);
+void DMA_FLEXCAN2_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN2)]);
+
+ s_flexcanIsr(DMA__CAN2, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN0)
+void ADMA_FLEXCAN0_INT_DriverIRQHandler(void);
+void ADMA_FLEXCAN0_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN0)]);
+
+ s_flexcanIsr(ADMA__CAN0, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN1)
+void ADMA_FLEXCAN1_INT_DriverIRQHandler(void);
+void ADMA_FLEXCAN1_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN1)]);
+
+ s_flexcanIsr(ADMA__CAN1, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN2)
+void ADMA_FLEXCAN2_INT_DriverIRQHandler(void);
+void ADMA_FLEXCAN2_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN2)]);
+
+ s_flexcanIsr(ADMA__CAN2, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FLEXCAN1)
+void CAN_FD1_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[1]);
+
+ s_flexcanIsr(FLEXCAN1, s_flexcanHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FLEXCAN2)
+void CAN_FD2_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[2]);
+
+ s_flexcanIsr(FLEXCAN2, s_flexcanHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.h
new file mode 100644
index 0000000000..b3d1c46a33
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan.h
@@ -0,0 +1,2241 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXCAN_H_
+#define _FSL_FLEXCAN_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup flexcan_driver
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexCAN driver version. */
+#define FSL_FLEXCAN_DRIVER_VERSION (MAKE_VERSION(2, 9, 2))
+/*@}*/
+
+#if !(defined(FLEXCAN_WAIT_TIMEOUT) && FLEXCAN_WAIT_TIMEOUT)
+/* Define to 1000 means keep waiting 1000 times until the flag is assert/deassert. */
+#define FLEXCAN_WAIT_TIMEOUT (1000U)
+#endif
+
+/*! @brief FlexCAN frame length helper macro. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+#define DLC_LENGTH_DECODE(dlc) (((dlc) <= 8U) ? (dlc) : (((dlc) <= 12U) ? (((dlc)-6U) * 4U) : (((dlc)-11U) * 16U)))
+#endif
+
+/*! @brief FlexCAN Frame ID helper macro. */
+#define FLEXCAN_ID_STD(id) \
+ (((uint32_t)(((uint32_t)(id)) << CAN_ID_STD_SHIFT)) & CAN_ID_STD_MASK) /*!< Standard Frame ID helper macro. */
+#define FLEXCAN_ID_EXT(id) \
+ (((uint32_t)(((uint32_t)(id)) << CAN_ID_EXT_SHIFT)) & \
+ (CAN_ID_EXT_MASK | CAN_ID_STD_MASK)) /*!< Extend Frame ID helper macro. */
+
+/*! @brief FlexCAN Rx Message Buffer Mask helper macro. */
+#define FLEXCAN_RX_MB_STD_MASK(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ FLEXCAN_ID_STD(id)) /*!< Standard Rx Message Buffer Mask helper macro. */
+#define FLEXCAN_RX_MB_EXT_MASK(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ FLEXCAN_ID_EXT(id)) /*!< Extend Rx Message Buffer Mask helper macro. */
+
+/*! @brief FlexCAN Legacy Rx FIFO Mask helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_A(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ (FLEXCAN_ID_STD(id) << 1)) /*!< Standard Rx FIFO Mask helper macro Type A helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_B_HIGH(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ (((uint32_t)(id)&0x7FF) << 19)) /*!< Standard Rx FIFO Mask helper macro Type B upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_B_LOW(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 15) | (uint32_t)((uint32_t)(ide) << 14)) | \
+ (((uint32_t)(id)&0x7FF) << 3)) /*!< Standard Rx FIFO Mask helper macro Type B lower part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_HIGH(id) \
+ (((uint32_t)(id)&0x7F8) << 21) /*!< Standard Rx FIFO Mask helper macro Type C upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_MID_HIGH(id) \
+ (((uint32_t)(id)&0x7F8) << 13) /*!< Standard Rx FIFO Mask helper macro Type C mid-upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_MID_LOW(id) \
+ (((uint32_t)(id)&0x7F8) << 5) /*!< Standard Rx FIFO Mask helper macro Type C mid-lower part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_LOW(id) \
+ (((uint32_t)(id)&0x7F8) >> 3) /*!< Standard Rx FIFO Mask helper macro Type C lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_A(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ (FLEXCAN_ID_EXT(id) << 1)) /*!< Extend Rx FIFO Mask helper macro Type A helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_B_HIGH(id, rtr, ide) \
+ ( \
+ ((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
+ ((FLEXCAN_ID_EXT(id) & 0x1FFF8000) \
+ << 1)) /*!< Extend Rx FIFO Mask helper macro Type B upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_B_LOW(id, rtr, ide) \
+ (((uint32_t)((uint32_t)(rtr) << 15) | (uint32_t)((uint32_t)(ide) << 14)) | \
+ ((FLEXCAN_ID_EXT(id) & 0x1FFF8000) >> \
+ 15)) /*!< Extend Rx FIFO Mask helper macro Type B lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_HIGH(id) \
+ ((FLEXCAN_ID_EXT(id) & 0x1FE00000) << 3) /*!< Extend Rx FIFO Mask helper macro Type C upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_MID_HIGH(id) \
+ ((FLEXCAN_ID_EXT(id) & 0x1FE00000) >> \
+ 5) /*!< Extend Rx FIFO Mask helper macro Type C mid-upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_MID_LOW(id) \
+ ((FLEXCAN_ID_EXT(id) & 0x1FE00000) >> \
+ 13) /*!< Extend Rx FIFO Mask helper macro Type C mid-lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_LOW(id) \
+ ((FLEXCAN_ID_EXT(id) & 0x1FE00000) >> 21) /*!< Extend Rx FIFO Mask helper macro Type C lower part helper macro. */
+
+/*! @brief FlexCAN Rx FIFO Filter helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_A(id, rtr, ide) /*!< Standard Rx FIFO Filter helper macro Type A helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_B_HIGH(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_B_HIGH( \
+ id, rtr, ide) /*!< Standard Rx FIFO Filter helper macro Type B upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_B_LOW(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_B_LOW( \
+ id, rtr, ide) /*!< Standard Rx FIFO Filter helper macro Type B lower part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_C_HIGH(id) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_HIGH( \
+ id) /*!< Standard Rx FIFO Filter helper macro Type C upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_C_MID_HIGH(id) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_MID_HIGH( \
+ id) /*!< Standard Rx FIFO Filter helper macro Type C mid-upper part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_C_MID_LOW(id) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_MID_LOW( \
+ id) /*!< Standard Rx FIFO Filter helper macro Type C mid-lower part helper macro. */
+#define FLEXCAN_RX_FIFO_STD_FILTER_TYPE_C_LOW(id) \
+ FLEXCAN_RX_FIFO_STD_MASK_TYPE_C_LOW( \
+ id) /*!< Standard Rx FIFO Filter helper macro Type C lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_A(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_A(id, rtr, ide) /*!< Extend Rx FIFO Filter helper macro Type A helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_B_HIGH(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_B_HIGH( \
+ id, rtr, ide) /*!< Extend Rx FIFO Filter helper macro Type B upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_B_LOW(id, rtr, ide) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_B_LOW( \
+ id, rtr, ide) /*!< Extend Rx FIFO Filter helper macro Type B lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_C_HIGH(id) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_HIGH( \
+ id) /*!< Extend Rx FIFO Filter helper macro Type C upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_C_MID_HIGH(id) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_MID_HIGH( \
+ id) /*!< Extend Rx FIFO Filter helper macro Type C mid-upper part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_C_MID_LOW(id) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_MID_LOW( \
+ id) /*!< Extend Rx FIFO Filter helper macro Type C mid-lower part helper macro. */
+#define FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_C_LOW(id) \
+ FLEXCAN_RX_FIFO_EXT_MASK_TYPE_C_LOW(id) /*!< Extend Rx FIFO Filter helper macro Type C lower part helper macro. */
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*! @brief FlexCAN Enhanced Rx FIFO Filter and Mask helper macro. */
+#define ENHANCED_RX_FIFO_FSCH(x) (((uint32_t)(((uint32_t)(x)) << 30)) & 0xC0000000U)
+#define RTR_STD_HIGH(x) (((uint32_t)(((uint32_t)(x)) << 27)) & 0x08000000U)
+#define RTR_STD_LOW(x) (((uint32_t)(((uint32_t)(x)) << 11)) & 0x00000800U)
+#define RTR_EXT(x) (((uint32_t)(((uint32_t)(x)) << 29)) & 0x40000000U)
+#define ID_STD_LOW(id) (((uint32_t)id) & 0x7FFU)
+#define ID_STD_HIGH(id) (((uint32_t)(((uint32_t)(id)) << 16)) & 0x07FF0000U)
+#define ID_EXT(id) (((uint32_t)id) & 0x1FFFFFFFU)
+
+/*! Standard ID filter element with filter + mask scheme. */
+#define FLEXCAN_ENHANCED_RX_FIFO_STD_MASK_AND_FILTER(id, rtr, id_mask, rtr_mask) \
+ (ENHANCED_RX_FIFO_FSCH(0x0) | RTR_STD_HIGH(rtr) | ID_STD_HIGH(id) | RTR_STD_LOW(rtr_mask) | ID_STD_LOW(id_mask))
+/*! Standard ID filter element with filter range. */
+#define FLEXCAN_ENHANCED_RX_FIFO_STD_FILTER_WITH_RANGE(id_upper, rtr, id_lower, rtr_mask) \
+ (ENHANCED_RX_FIFO_FSCH(0x1) | RTR_STD_HIGH(rtr) | ID_STD_HIGH(id_upper) | RTR_STD_LOW(rtr_mask) | \
+ ID_STD_LOW(id_lower))
+/*! Standard ID filter element with two filters without masks. */
+#define FLEXCAN_ENHANCED_RX_FIFO_STD_TWO_FILTERS(id1, rtr1, id2, rtr2) \
+ (ENHANCED_RX_FIFO_FSCH(0x2) | RTR_STD_HIGH(rtr1) | ID_STD_HIGH(id1) | RTR_STD_LOW(rtr2) | ID_STD_LOW(id2))
+/*! Extended ID filter element with filter + mask scheme low word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_MASK_AND_FILTER_LOW(id, rtr) \
+ (ENHANCED_RX_FIFO_FSCH(0x0) | RTR_EXT(rtr) | ID_EXT(id))
+/*! Extended ID filter element with filter + mask scheme high word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_MASK_AND_FILTER_HIGH(id_mask, rtr_mask) \
+ (ENHANCED_RX_FIFO_FSCH(0x0) | RTR_EXT(rtr_mask) | ID_EXT(id_mask))
+/*! Extended ID filter element with range scheme low word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_FILTER_WITH_RANGE_LOW(id_upper, rtr) \
+ (ENHANCED_RX_FIFO_FSCH(0x1) | RTR_EXT(rtr) | ID_EXT(id_upper))
+/*! Extended ID filter element with range scheme high word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_FILTER_WITH_RANGE_HIGH(id_lower, rtr_mask) \
+ (ENHANCED_RX_FIFO_FSCH(0x1) | RTR_EXT(rtr_mask) | ID_EXT(id_lower))
+/*! Extended ID filter element with two filters without masks low word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_TWO_FILTERS_LOW(id2, rtr2) \
+ (ENHANCED_RX_FIFO_FSCH(0x2) | RTR_EXT(rtr2) | ID_EXT(id2))
+/*! Extended ID filter element with two filters without masks high word. */
+#define FLEXCAN_ENHANCED_RX_FIFO_EXT_TWO_FILTERS_HIGH(id1, rtr1) \
+ (ENHANCED_RX_FIFO_FSCH(0x2) | RTR_EXT(rtr1) | ID_EXT(id1))
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*! @brief FlexCAN Pretended Networking ID Mask helper macro. */
+#define FLEXCAN_PN_STD_MASK(id, rtr) \
+ ((uint32_t)((uint32_t)(rtr) << CAN_FLT_ID1_FLT_RTR_SHIFT) | \
+ FLEXCAN_ID_STD(id)) /*!< Standard Rx Message Buffer Mask helper macro. */
+#define FLEXCAN_PN_EXT_MASK(id, rtr) \
+ ((uint32_t)CAN_FLT_ID1_FLT_IDE_MASK | (uint32_t)((uint32_t)(rtr) << CAN_FLT_ID1_FLT_RTR_SHIFT) | \
+ FLEXCAN_ID_EXT(id)) /*!< Extend Rx Message Buffer Mask helper macro. */
+#endif
+
+/*! @brief FlexCAN interrupt/status flag helper macro. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+#define FLEXCAN_PN_INT_MASK(x) (((uint64_t)(((uint64_t)(x)) << 32)) & 0x3000000000000U)
+#define FLEXCAN_PN_INT_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 32)) & 0x00030000U)
+#define FLEXCAN_PN_STATUS_MASK(x) (((uint64_t)(((uint64_t)(x)) << 16)) & 0x300000000U)
+#define FLEXCAN_PN_STATUS_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 16)) & 0x00030000U)
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+#define FLEXCAN_EFIFO_INT_MASK(x) (((uint64_t)(((uint64_t)(x)) << 32)) & 0xF000000000000000U)
+#define FLEXCAN_EFIFO_INT_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 32)) & 0xF0000000U)
+#define FLEXCAN_EFIFO_STATUS_MASK(x) (((uint64_t)(((uint64_t)(x)) << 32)) & 0xF003000000000000U)
+#define FLEXCAN_EFIFO_STATUS_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 32)) & 0xF0030000U)
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+#define FLEXCAN_MECR_INT_MASK(x) (((uint64_t)(((uint64_t)(x)) << 16)) & 0xD00000000U)
+#define FLEXCAN_MECR_INT_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 16)) & 0x000D0000U)
+#define FLEXCAN_MECR_STATUS_MASK(x) (((uint64_t)(((uint64_t)(x)) << 34)) & 0x34003400000000U)
+#define FLEXCAN_MECR_STATUS_UNMASK(x) (((uint32_t)(((uint64_t)(x)) >> 34)) & 0x000D000DU)
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+#define FLEXCAN_ERROR_AND_STATUS_INIT_FLAG \
+ ((uint32_t)kFLEXCAN_ErrorOverrunFlag | (uint32_t)kFLEXCAN_FDErrorIntFlag | (uint32_t)kFLEXCAN_BusoffDoneIntFlag | \
+ (uint32_t)kFLEXCAN_TxWarningIntFlag | (uint32_t)kFLEXCAN_RxWarningIntFlag | (uint32_t)kFLEXCAN_BusOffIntFlag | \
+ (uint32_t)kFLEXCAN_ErrorIntFlag | FLEXCAN_MEMORY_ERROR_INIT_FLAG)
+#else
+#define FLEXCAN_ERROR_AND_STATUS_INIT_FLAG \
+ ((uint32_t)kFLEXCAN_TxWarningIntFlag | (uint32_t)kFLEXCAN_RxWarningIntFlag | (uint32_t)kFLEXCAN_BusOffIntFlag | \
+ (uint32_t)kFLEXCAN_ErrorIntFlag | FLEXCAN_MEMORY_ERROR_INIT_FLAG)
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+#define FLEXCAN_WAKE_UP_FLAG \
+ ((uint32_t)kFLEXCAN_WakeUpIntFlag | (uint64_t)kFLEXCAN_PNMatchIntFlag | (uint64_t)kFLEXCAN_PNTimeoutIntFlag)
+#else
+#define FLEXCAN_WAKE_UP_FLAG ((uint32_t)kFLEXCAN_WakeUpIntFlag)
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+#define FLEXCAN_MEMORY_ERROR_INIT_FLAG ((uint64_t)kFLEXCAN_AllMemoryErrorFlag)
+#else
+#define FLEXCAN_MEMORY_ERROR_INIT_FLAG (0U)
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+#define FLEXCAN_MEMORY_ENHANCED_RX_FIFO_INIT_FLAG \
+ ((uint64_t)kFLEXCAN_ERxFifoUnderflowIntFlag | (uint64_t)kFLEXCAN_ERxFifoOverflowIntFlag | \
+ (uint64_t)kFLEXCAN_ERxFifoWatermarkIntFlag | (uint64_t)kFLEXCAN_ERxFifoDataAvlIntFlag)
+#endif
+/*! @brief FlexCAN Enhanced Rx FIFO base address helper macro. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+#define E_RX_FIFO(base) ((uint32_t)(base) + 0x2000U)
+#else
+#define FLEXCAN_MEMORY_ENHANCED_RX_FIFO_INIT_FLAG (0U)
+#endif
+/*! @brief FlexCAN transfer status. */
+enum
+{
+ kStatus_FLEXCAN_TxBusy = MAKE_STATUS(kStatusGroup_FLEXCAN, 0), /*!< Tx Message Buffer is Busy. */
+ kStatus_FLEXCAN_TxIdle = MAKE_STATUS(kStatusGroup_FLEXCAN, 1), /*!< Tx Message Buffer is Idle. */
+ kStatus_FLEXCAN_TxSwitchToRx = MAKE_STATUS(
+ kStatusGroup_FLEXCAN, 2), /*!< Remote Message is send out and Message buffer changed to Receive one. */
+ kStatus_FLEXCAN_RxBusy = MAKE_STATUS(kStatusGroup_FLEXCAN, 3), /*!< Rx Message Buffer is Busy. */
+ kStatus_FLEXCAN_RxIdle = MAKE_STATUS(kStatusGroup_FLEXCAN, 4), /*!< Rx Message Buffer is Idle. */
+ kStatus_FLEXCAN_RxOverflow = MAKE_STATUS(kStatusGroup_FLEXCAN, 5), /*!< Rx Message Buffer is Overflowed. */
+ kStatus_FLEXCAN_RxFifoBusy = MAKE_STATUS(kStatusGroup_FLEXCAN, 6), /*!< Rx Message FIFO is Busy. */
+ kStatus_FLEXCAN_RxFifoIdle = MAKE_STATUS(kStatusGroup_FLEXCAN, 7), /*!< Rx Message FIFO is Idle. */
+ kStatus_FLEXCAN_RxFifoOverflow = MAKE_STATUS(kStatusGroup_FLEXCAN, 8), /*!< Rx Message FIFO is overflowed. */
+ kStatus_FLEXCAN_RxFifoWarning = MAKE_STATUS(kStatusGroup_FLEXCAN, 9), /*!< Rx Message FIFO is almost overflowed. */
+ kStatus_FLEXCAN_RxFifoDisabled =
+ MAKE_STATUS(kStatusGroup_FLEXCAN, 10), /*!< Rx Message FIFO is disabled during reading. */
+ kStatus_FLEXCAN_ErrorStatus = MAKE_STATUS(kStatusGroup_FLEXCAN, 11), /*!< FlexCAN Module Error and Status. */
+ kStatus_FLEXCAN_WakeUp = MAKE_STATUS(kStatusGroup_FLEXCAN, 12), /*!< FlexCAN is waken up from STOP mode. */
+ kStatus_FLEXCAN_UnHandled = MAKE_STATUS(kStatusGroup_FLEXCAN, 13), /*!< UnHadled Interrupt asserted. */
+ kStatus_FLEXCAN_RxRemote = MAKE_STATUS(kStatusGroup_FLEXCAN, 14), /*!< Rx Remote Message Received in Mail box. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ kStatus_FLEXCAN_RxFifoUnderflow =
+ MAKE_STATUS(kStatusGroup_FLEXCAN, 15), /*!< Enhanced Rx Message FIFO is underflow. */
+#endif
+};
+
+/*! @brief FlexCAN frame format. */
+typedef enum _flexcan_frame_format
+{
+ kFLEXCAN_FrameFormatStandard = 0x0U, /*!< Standard frame format attribute. */
+ kFLEXCAN_FrameFormatExtend = 0x1U, /*!< Extend frame format attribute. */
+} flexcan_frame_format_t;
+
+/*! @brief FlexCAN frame type. */
+typedef enum _flexcan_frame_type
+{
+ kFLEXCAN_FrameTypeData = 0x0U, /*!< Data frame type attribute. */
+ kFLEXCAN_FrameTypeRemote = 0x1U, /*!< Remote frame type attribute. */
+} flexcan_frame_type_t;
+
+/*! @brief FlexCAN clock source.
+ * @deprecated Do not use the kFLEXCAN_ClkSrcOs. It has been superceded kFLEXCAN_ClkSrc0
+ * @deprecated Do not use the kFLEXCAN_ClkSrcPeri. It has been superceded kFLEXCAN_ClkSrc1
+ */
+typedef enum _flexcan_clock_source
+{
+ kFLEXCAN_ClkSrcOsc = 0x0U, /*!< FlexCAN Protocol Engine clock from Oscillator. */
+ kFLEXCAN_ClkSrcPeri = 0x1U, /*!< FlexCAN Protocol Engine clock from Peripheral Clock. */
+ kFLEXCAN_ClkSrc0 = 0x0U, /*!< FlexCAN Protocol Engine clock selected by user as SRC == 0. */
+ kFLEXCAN_ClkSrc1 = 0x1U, /*!< FlexCAN Protocol Engine clock selected by user as SRC == 1. */
+} flexcan_clock_source_t;
+
+/*! @brief FlexCAN wake up source. */
+typedef enum _flexcan_wake_up_source
+{
+ kFLEXCAN_WakeupSrcUnfiltered = 0x0U, /*!< FlexCAN uses unfiltered Rx input to detect edge. */
+ kFLEXCAN_WakeupSrcFiltered = 0x1U, /*!< FlexCAN uses filtered Rx input to detect edge. */
+} flexcan_wake_up_source_t;
+
+/*! @brief FlexCAN Rx Fifo Filter type. */
+typedef enum _flexcan_rx_fifo_filter_type
+{
+ kFLEXCAN_RxFifoFilterTypeA = 0x0U, /*!< One full ID (standard and extended) per ID Filter element. */
+ kFLEXCAN_RxFifoFilterTypeB =
+ 0x1U, /*!< Two full standard IDs or two partial 14-bit ID slices per ID Filter Table element. */
+ kFLEXCAN_RxFifoFilterTypeC =
+ 0x2U, /*!< Four partial 8-bit Standard or extended ID slices per ID Filter Table element. */
+ kFLEXCAN_RxFifoFilterTypeD = 0x3U, /*!< All frames rejected. */
+} flexcan_rx_fifo_filter_type_t;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief FlexCAN Message Buffer Payload size.
+ */
+typedef enum _flexcan_mb_size
+{
+ kFLEXCAN_8BperMB = 0x0U, /*!< Selects 8 bytes per Message Buffer. */
+ kFLEXCAN_16BperMB = 0x1U, /*!< Selects 16 bytes per Message Buffer. */
+ kFLEXCAN_32BperMB = 0x2U, /*!< Selects 32 bytes per Message Buffer. */
+ kFLEXCAN_64BperMB = 0x3U, /*!< Selects 64 bytes per Message Buffer. */
+} flexcan_mb_size_t;
+
+/*!
+ * @brief FlexCAN CAN FD frame supporting data length (available DLC values).
+ *
+ * For Tx, when the Data size corresponding to DLC value stored in the MB selected for transmission is larger than the
+ * MB Payload size, FlexCAN adds the necessary number of bytes with constant 0xCC pattern to complete the expected DLC.
+ * For Rx, when the Data size corresponding to DLC value received from the CAN bus is larger than the MB Payload size,
+ * the high order bytes that do not fit the Payload size will lose.
+ */
+enum _flexcan_fd_frame_length
+{
+ kFLEXCAN_0BperFrame = 0x0U, /*!< Frame contains 0 valid data bytes. */
+ kFLEXCAN_1BperFrame, /*!< Frame contains 1 valid data bytes. */
+ kFLEXCAN_2BperFrame, /*!< Frame contains 2 valid data bytes. */
+ kFLEXCAN_3BperFrame, /*!< Frame contains 3 valid data bytes. */
+ kFLEXCAN_4BperFrame, /*!< Frame contains 4 valid data bytes. */
+ kFLEXCAN_5BperFrame, /*!< Frame contains 5 valid data bytes. */
+ kFLEXCAN_6BperFrame, /*!< Frame contains 6 valid data bytes. */
+ kFLEXCAN_7BperFrame, /*!< Frame contains 7 valid data bytes. */
+ kFLEXCAN_8BperFrame, /*!< Frame contains 8 valid data bytes. */
+ kFLEXCAN_12BperFrame, /*!< Frame contains 12 valid data bytes. */
+ kFLEXCAN_16BperFrame, /*!< Frame contains 16 valid data bytes. */
+ kFLEXCAN_20BperFrame, /*!< Frame contains 20 valid data bytes. */
+ kFLEXCAN_24Bperrame, /*!< Frame contains 24 valid data bytes. */
+ kFLEXCAN_32BperFrame, /*!< Frame contains 32 valid data bytes. */
+ kFLEXCAN_48BperFrame, /*!< Frame contains 48 valid data bytes. */
+ kFLEXCAN_64BperFrame, /*!< Frame contains 64 valid data bytes. */
+};
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*! @brief FlexCAN Enhanced Rx Fifo DMA transfer per read length enumerations. */
+typedef enum _flexcan_efifo_dma_per_read_length
+{
+ kFLEXCAN_1WordPerRead = 0x0U, /*!< Transfer 1 32-bit words (CS).*/
+ kFLEXCAN_2WordPerRead, /*!< Transfer 2 32-bit words (CS + ID).*/
+ kFLEXCAN_3WordPerRead, /*!< Transfer 3 32-bit words (CS + ID + 1~4 bytes data).*/
+ kFLEXCAN_4WordPerRead, /*!< Transfer 4 32-bit words (CS + ID + 5~8 bytes data).*/
+ kFLEXCAN_5WordPerRead, /*!< Transfer 5 32-bit words (CS + ID + 9~12 bytes data).*/
+ kFLEXCAN_6WordPerRead, /*!< Transfer 6 32-bit words (CS + ID + 13~16 bytes data).*/
+ kFLEXCAN_7WordPerRead, /*!< Transfer 7 32-bit words (CS + ID + 17~20 bytes data).*/
+ kFLEXCAN_8WordPerRead, /*!< Transfer 8 32-bit words (CS + ID + 21~24 bytes data).*/
+ kFLEXCAN_9WordPerRead, /*!< Transfer 9 32-bit words (CS + ID + 25~28 bytes data).*/
+ kFLEXCAN_10WordPerRead, /*!< Transfer 10 32-bit words (CS + ID + 29~32 bytes data).*/
+ kFLEXCAN_11WordPerRead, /*!< Transfer 11 32-bit words (CS + ID + 33~36 bytes data).*/
+ kFLEXCAN_12WordPerRead, /*!< Transfer 12 32-bit words (CS + ID + 37~40 bytes data).*/
+ kFLEXCAN_13WordPerRead, /*!< Transfer 13 32-bit words (CS + ID + 41~44 bytes data).*/
+ kFLEXCAN_14WordPerRead, /*!< Transfer 14 32-bit words (CS + ID + 45~48 bytes data).*/
+ kFLEXCAN_15WordPerRead, /*!< Transfer 15 32-bit words (CS + ID + 49~52 bytes data).*/
+ kFLEXCAN_16WordPerRead, /*!< Transfer 16 32-bit words (CS + ID + 53~56 bytes data).*/
+ kFLEXCAN_17WordPerRead, /*!< Transfer 17 32-bit words (CS + ID + 57~60 bytes data).*/
+ kFLEXCAN_18WordPerRead, /*!< Transfer 18 32-bit words (CS + ID + 61~64 bytes data).*/
+ kFLEXCAN_19WordPerRead /*!< Transfer 19 32-bit words (CS + ID + 64 bytes data + ID HIT).*/
+} flexcan_efifo_dma_per_read_length_t;
+#endif
+
+/*!
+ * @brief FlexCAN Enhanced/Legacy Rx FIFO priority.
+ *
+ * The matching process starts from the Rx MB(or Enhanced/Legacy Rx FIFO) with higher priority.
+ * If no MB(or Enhanced/Legacy Rx FIFO filter) is satisfied, the matching process goes on with
+ * the Enhanced/Legacy Rx FIFO(or Rx MB) with lower priority.
+ */
+typedef enum _flexcan_rx_fifo_priority
+{
+ kFLEXCAN_RxFifoPrioLow = 0x0U, /*!< Matching process start from Rx Message Buffer first. */
+ kFLEXCAN_RxFifoPrioHigh = 0x1U, /*!< Matching process start from Enhanced/Legacy Rx FIFO first. */
+} flexcan_rx_fifo_priority_t;
+
+/*!
+ * @brief FlexCAN interrupt enable enumerations.
+ *
+ * This provides constants for the FlexCAN interrupt enable enumerations for use in the FlexCAN functions.
+ * @note FlexCAN Message Buffers and Legacy Rx FIFO interrupts not included in.
+ */
+enum _flexcan_interrupt_enable
+{
+ kFLEXCAN_BusOffInterruptEnable = CAN_CTRL1_BOFFMSK_MASK, /*!< Bus Off interrupt, use bit 15. */
+ kFLEXCAN_ErrorInterruptEnable = CAN_CTRL1_ERRMSK_MASK, /*!< CAN Error interrupt, use bit 14. */
+ kFLEXCAN_TxWarningInterruptEnable = CAN_CTRL1_TWRNMSK_MASK, /*!< Tx Warning interrupt, use bit 11. */
+ kFLEXCAN_RxWarningInterruptEnable = CAN_CTRL1_RWRNMSK_MASK, /*!< Rx Warning interrupt, use bit 10. */
+ kFLEXCAN_WakeUpInterruptEnable = CAN_MCR_WAKMSK_MASK, /*!< Self Wake Up interrupt, use bit 26. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ kFLEXCAN_FDErrorInterruptEnable = CAN_CTRL2_ERRMSK_FAST_MASK, /*!< CAN FD Error interrupt, use bit 31. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /*! PN Match Wake Up interrupt, use high word bit 17. */
+ kFLEXCAN_PNMatchWakeUpInterruptEnable = FLEXCAN_PN_INT_MASK(CAN_CTRL1_PN_WTOF_MSK_MASK),
+ /*! PN Timeout Wake Up interrupt, use high word bit 16. */
+ kFLEXCAN_PNTimeoutWakeUpInterruptEnable = FLEXCAN_PN_INT_MASK(CAN_CTRL1_PN_WUMF_MSK_MASK),
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /*!< Enhanced Rx FIFO Underflow interrupt, use high word bit 31. */
+ kFLEXCAN_ERxFifoUnderflowInterruptEnable = FLEXCAN_EFIFO_INT_MASK(CAN_ERFIER_ERFUFWIE_MASK),
+ /*!< Enhanced Rx FIFO Overflow interrupt, use high word bit 30. */
+ kFLEXCAN_ERxFifoOverflowInterruptEnable = FLEXCAN_EFIFO_INT_MASK(CAN_ERFIER_ERFOVFIE_MASK),
+ /*!< Enhanced Rx FIFO Watermark interrupt, use high word bit 29. */
+ kFLEXCAN_ERxFifoWatermarkInterruptEnable = FLEXCAN_EFIFO_INT_MASK(CAN_ERFIER_ERFWMIIE_MASK),
+ /*!< Enhanced Rx FIFO Data Avilable interrupt, use high word bit 28. */
+ kFLEXCAN_ERxFifoDataAvlInterruptEnable = FLEXCAN_EFIFO_INT_MASK(CAN_ERFIER_ERFDAIE_MASK),
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /*! Host Access With Non-Correctable Errors interrupt, use high word bit 0. */
+ kFLEXCAN_HostAccessNCErrorInterruptEnable = FLEXCAN_MECR_INT_MASK(CAN_MECR_HANCEI_MSK_MASK),
+ /*! FlexCAN Access With Non-Correctable Errors interrupt, use high word bit 2. */
+ kFLEXCAN_FlexCanAccessNCErrorInterruptEnable = FLEXCAN_MECR_INT_MASK(CAN_MECR_FANCEI_MSK_MASK),
+ /*! Host or FlexCAN Access With Correctable Errors interrupt, use high word bit 3. */
+ kFLEXCAN_HostOrFlexCanCErrorInterruptEnable = FLEXCAN_MECR_INT_MASK(CAN_MECR_CEI_MSK_MASK),
+#endif
+};
+
+/*!
+ * @brief FlexCAN status flags.
+ *
+ * This provides constants for the FlexCAN status flags for use in the FlexCAN functions.
+ * @note The CPU read action clears the bits corresponding to the FlEXCAN_ErrorFlag macro, therefore user need to
+ * read status flags and distinguish which error is occur using @ref _flexcan_error_flags enumerations.
+ */
+enum _flexcan_flags
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ kFLEXCAN_ErrorOverrunFlag = CAN_ESR1_ERROVR_MASK, /*!< Error Overrun Status. */
+ kFLEXCAN_FDErrorIntFlag = CAN_ESR1_ERRINT_FAST_MASK, /*!< CAN FD Error Interrupt Flag. */
+ kFLEXCAN_BusoffDoneIntFlag = CAN_ESR1_BOFFDONEINT_MASK, /*!< Bus Off process completed Interrupt Flag. */
+#endif
+ kFLEXCAN_SynchFlag = CAN_ESR1_SYNCH_MASK, /*!< CAN Synchronization Status. */
+ kFLEXCAN_TxWarningIntFlag = CAN_ESR1_TWRNINT_MASK, /*!< Tx Warning Interrupt Flag. */
+ kFLEXCAN_RxWarningIntFlag = CAN_ESR1_RWRNINT_MASK, /*!< Rx Warning Interrupt Flag. */
+ kFLEXCAN_IdleFlag = CAN_ESR1_IDLE_MASK, /*!< FlexCAN In IDLE Status. */
+ kFLEXCAN_FaultConfinementFlag = CAN_ESR1_FLTCONF_MASK, /*!< FlexCAN Fault Confinement State. */
+ kFLEXCAN_TransmittingFlag = CAN_ESR1_TX_MASK, /*!< FlexCAN In Transmission Status. */
+ kFLEXCAN_ReceivingFlag = CAN_ESR1_RX_MASK, /*!< FlexCAN In Reception Status. */
+ kFLEXCAN_BusOffIntFlag = CAN_ESR1_BOFFINT_MASK, /*!< Bus Off Interrupt Flag. */
+ kFLEXCAN_ErrorIntFlag = CAN_ESR1_ERRINT_MASK, /*!< CAN Error Interrupt Flag. */
+ kFLEXCAN_WakeUpIntFlag = CAN_ESR1_WAKINT_MASK, /*!< Self Wake-Up Interrupt Flag. */
+ kFLEXCAN_ErrorFlag =
+ (uint32_t)(/*!< All FlexCAN Read Clear Error Status. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ CAN_ESR1_STFERR_FAST_MASK | CAN_ESR1_FRMERR_FAST_MASK | CAN_ESR1_CRCERR_FAST_MASK |
+ CAN_ESR1_BIT0ERR_FAST_MASK | CAN_ESR1_BIT1ERR_FAST_MASK | CAN_ESR1_ERROVR_MASK |
+#endif
+ CAN_ESR1_TXWRN_MASK | CAN_ESR1_RXWRN_MASK | CAN_ESR1_BIT1ERR_MASK | CAN_ESR1_BIT0ERR_MASK |
+ CAN_ESR1_ACKERR_MASK | CAN_ESR1_CRCERR_MASK | CAN_ESR1_FRMERR_MASK | CAN_ESR1_STFERR_MASK),
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ kFLEXCAN_PNMatchIntFlag = FLEXCAN_PN_STATUS_MASK(CAN_WU_MTC_WUMF_MASK), /*!< PN Matching Event Interrupt Flag. */
+ kFLEXCAN_PNTimeoutIntFlag = FLEXCAN_PN_STATUS_MASK(CAN_WU_MTC_WTOF_MASK), /*!< PN Timeout Event Interrupt Flag. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ kFLEXCAN_ERxFifoUnderflowIntFlag =
+ FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFUFW_MASK), /*!< Enhanced Rx FIFO underflow Interrupt Flag. */
+ kFLEXCAN_ERxFifoOverflowIntFlag =
+ FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFOVF_MASK), /*!< Enhanced Rx FIFO overflow Interrupt Flag. */
+ kFLEXCAN_ERxFifoWatermarkIntFlag =
+ FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFWMI_MASK), /*!< Enhanced Rx FIFO watermark Interrupt Flag. */
+ kFLEXCAN_ERxFifoDataAvlIntFlag =
+ FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFDA_MASK), /*!< Enhanced Rx FIFO data available Interrupt Flag. */
+ kFLEXCAN_ERxFifoEmptyFlag = FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFE_MASK), /*!< Enhanced Rx FIFO empty status. */
+ kFLEXCAN_ERxFifoFullFlag = FLEXCAN_EFIFO_STATUS_MASK(CAN_ERFSR_ERFF_MASK), /*!< Enhanced Rx FIFO full status. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /*! Host Access With Non-Correctable Error Interrupt Flag. */
+ kFLEXCAN_HostAccessNonCorrectableErrorIntFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_HANCEIF_MASK),
+ /*! FlexCAN Access With Non-Correctable Error Interrupt Flag. */
+ kFLEXCAN_FlexCanAccessNonCorrectableErrorIntFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_FANCEIF_MASK),
+ /*! Correctable Error Interrupt Flag. */
+ kFLEXCAN_CorrectableErrorIntFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_CEIF_MASK),
+ /*! Host Access With Non-Correctable Error Interrupt Overrun Flag. */
+ kFLEXCAN_HostAccessNonCorrectableErrorOverrunFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_HANCEIOF_MASK),
+ /*! FlexCAN Access With Non-Correctable Error Interrupt Overrun Flag. */
+ kFLEXCAN_FlexCanAccessNonCorrectableErrorOverrunFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_FANCEIOF_MASK),
+ /*! Correctable Error Interrupt Overrun Flag. */
+ kFLEXCAN_CorrectableErrorOverrunFlag = FLEXCAN_MECR_INT_MASK(CAN_ERRSR_CEIOF_MASK),
+ /*! All Memory Error Flags. */
+ kFLEXCAN_AllMemoryErrorFlag =
+ (kFLEXCAN_HostAccessNonCorrectableErrorIntFlag | kFLEXCAN_FlexCanAccessNonCorrectableErrorIntFlag |
+ kFLEXCAN_CorrectableErrorIntFlag | kFLEXCAN_HostAccessNonCorrectableErrorOverrunFlag |
+ kFLEXCAN_FlexCanAccessNonCorrectableErrorOverrunFlag | kFLEXCAN_CorrectableErrorOverrunFlag)
+#endif
+};
+
+/*!
+ * @brief FlexCAN error status flags.
+ *
+ * The FlexCAN Error Status enumerations is used to report current error of the FlexCAN bus.
+ * This enumerations should be used with KFLEXCAN_ErrorFlag in @ref _flexcan_flags enumerations
+ * to ditermine which error is generated.
+ */
+enum _flexcan_error_flags
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ kFLEXCAN_FDStuffingError = CAN_ESR1_STFERR_FAST_MASK, /*!< Stuffing Error. */
+ kFLEXCAN_FDFormError = CAN_ESR1_FRMERR_FAST_MASK, /*!< Form Error. */
+ kFLEXCAN_FDCrcError = CAN_ESR1_CRCERR_FAST_MASK, /*!< Cyclic Redundancy Check Error. */
+ kFLEXCAN_FDBit0Error = CAN_ESR1_BIT0ERR_FAST_MASK, /*!< Unable to send dominant bit. */
+ kFLEXCAN_FDBit1Error = (int)CAN_ESR1_BIT1ERR_FAST_MASK, /*!< Unable to send recessive bit. */
+#endif
+ kFLEXCAN_TxErrorWarningFlag = CAN_ESR1_TXWRN_MASK, /*!< Tx Error Warning Status. */
+ kFLEXCAN_RxErrorWarningFlag = CAN_ESR1_RXWRN_MASK, /*!< Rx Error Warning Status. */
+ kFLEXCAN_StuffingError = CAN_ESR1_STFERR_MASK, /*!< Stuffing Error. */
+ kFLEXCAN_FormError = CAN_ESR1_FRMERR_MASK, /*!< Form Error. */
+ kFLEXCAN_CrcError = CAN_ESR1_CRCERR_MASK, /*!< Cyclic Redundancy Check Error. */
+ kFLEXCAN_AckError = CAN_ESR1_ACKERR_MASK, /*!< Received no ACK on transmission. */
+ kFLEXCAN_Bit0Error = CAN_ESR1_BIT0ERR_MASK, /*!< Unable to send dominant bit. */
+ kFLEXCAN_Bit1Error = CAN_ESR1_BIT1ERR_MASK, /*!< Unable to send recessive bit. */
+};
+
+/*!
+ * @brief FlexCAN Legacy Rx FIFO status flags.
+ *
+ * The FlexCAN Legacy Rx FIFO Status enumerations are used to determine the status of the
+ * Rx FIFO. Because Rx FIFO occupy the MB0 ~ MB7 (Rx Fifo filter also occupies
+ * more Message Buffer space), Rx FIFO status flags are mapped to the corresponding
+ * Message Buffer status flags.
+ */
+enum
+{
+ kFLEXCAN_RxFifoOverflowFlag = CAN_IFLAG1_BUF7I_MASK, /*!< Rx FIFO overflow flag. */
+ kFLEXCAN_RxFifoWarningFlag = CAN_IFLAG1_BUF6I_MASK, /*!< Rx FIFO almost full flag. */
+ kFLEXCAN_RxFifoFrameAvlFlag = CAN_IFLAG1_BUF5I_MASK, /*!< Frames available in Rx FIFO flag. */
+};
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+/*!
+ * @brief FlexCAN Memory Error Type.
+ */
+typedef enum _flexcan_memory_error_type
+{
+ kFLEXCAN_CorrectableError = 0U, /*!< The memory error is correctable which means on bit error. */
+ kFLEXCAN_NonCorrectableError /*!< The memory error is non-correctable which means two bit errors. */
+} flexcan_memory_error_type_t;
+
+/*!
+ * @brief FlexCAN Memory Access Type.
+ */
+typedef enum _flexcan_memory_access_type
+{
+ kFLEXCAN_MoveOutFlexCanAccess = 0U, /*!< The memory error was detected during move-out FlexCAN access. */
+ kFLEXCAN_MoveInAccess, /*!< The memory error was detected during move-in FlexCAN access. */
+ kFLEXCAN_TxArbitrationAccess, /*!< The memory error was detected during Tx Arbitration FlexCAN access. */
+ kFLEXCAN_RxMatchingAccess, /*!< The memory error was detected during Rx Matching FlexCAN access. */
+ kFLEXCAN_MoveOutHostAccess /*!< The memory error was detected during Rx Matching Host (CPU) access. */
+} flexcan_memory_access_type_t;
+
+/*!
+ * @brief FlexCAN Memory Error Byte Syndrome.
+ */
+typedef enum _flexcan_byte_error_syndrome
+{
+ kFLEXCAN_NoError = 0U, /*!< No bit error in this byte. */
+ kFLEXCAN_ParityBits0Error = 1U, /*!< Parity bit 0 error in this byte. */
+ kFLEXCAN_ParityBits1Error = 2U, /*!< Parity bit 1 error in this byte. */
+ kFLEXCAN_ParityBits2Error = 4U, /*!< Parity bit 2 error in this byte. */
+ kFLEXCAN_ParityBits3Error = 8U, /*!< Parity bit 3 error in this byte. */
+ kFLEXCAN_ParityBits4Error = 16U, /*!< Parity bit 4 error in this byte. */
+ kFLEXCAN_DataBits0Error = 28U, /*!< Data bit 0 error in this byte. */
+ kFLEXCAN_DataBits1Error = 22U, /*!< Data bit 1 error in this byte. */
+ kFLEXCAN_DataBits2Error = 19U, /*!< Data bit 2 error in this byte. */
+ kFLEXCAN_DataBits3Error = 25U, /*!< Data bit 3 error in this byte. */
+ kFLEXCAN_DataBits4Error = 26U, /*!< Data bit 4 error in this byte. */
+ kFLEXCAN_DataBits5Error = 7U, /*!< Data bit 5 error in this byte. */
+ kFLEXCAN_DataBits6Error = 21U, /*!< Data bit 6 error in this byte. */
+ kFLEXCAN_DataBits7Error = 14U, /*!< Data bit 7 error in this byte. */
+ kFLEXCAN_AllZeroError = 6U, /*!< All-zeros non-correctable error in this byte. */
+ kFLEXCAN_AllOneError = 31U, /*!< All-ones non-correctable error in this byte. */
+ kFLEXCAN_NonCorrectableErrors /*!< Non-correctable error in this byte. */
+} flexcan_byte_error_syndrome_t;
+
+/*!
+ * @brief FlexCAN memory error register status structure
+ *
+ * This structure contains the memory access properties that caused a memory error access.
+ * It is used as the parameter of FLEXCAN_GetMemoryErrorReportStatus() function. And user can
+ * use FLEXCAN_GetMemoryErrorReportStatus to get the status of the last memory error access.
+ */
+typedef struct _flexcan_memory_error_report_status
+{
+ flexcan_memory_error_type_t errorType; /*!< The type of memory error that giving rise to the report. */
+ flexcan_memory_access_type_t accessType; /*!< The type of memory access that giving rise to the memory error. */
+ uint16_t accessAddress; /*!< The address where memory error detected. */
+ uint32_t errorData; /*!< The raw data word read from memory with error. */
+ struct
+ {
+ bool byteIsRead; /*!< The byte n (0~3) was read or not. */
+ /*!< The type of error and which bit in byte (n) is affected by the error. */
+ flexcan_byte_error_syndrome_t bitAffected;
+ } byteStatus[4];
+} flexcan_memory_error_report_status_t;
+#endif
+
+#if defined(__CC_ARM)
+#pragma anon_unions
+#endif
+/*! @brief FlexCAN message frame structure. */
+typedef struct _flexcan_frame
+{
+ struct
+ {
+ uint32_t timestamp : 16; /*!< FlexCAN internal Free-Running Counter Time Stamp. */
+ uint32_t length : 4; /*!< CAN frame data length in bytes (Range: 0~8). */
+ uint32_t type : 1; /*!< CAN Frame Type(DATA or REMOTE). */
+ uint32_t format : 1; /*!< CAN Frame Identifier(STD or EXT format). */
+ uint32_t : 1; /*!< Reserved. */
+ uint32_t idhit : 9; /*!< CAN Rx FIFO filter hit id(This value is only used in Rx FIFO receive mode). */
+ };
+ struct
+ {
+ uint32_t id : 29; /*!< CAN Frame Identifier, should be set using FLEXCAN_ID_EXT() or FLEXCAN_ID_STD() macro. */
+ uint32_t : 3; /*!< Reserved. */
+ };
+ union
+ {
+ struct
+ {
+ uint32_t dataWord0; /*!< CAN Frame payload word0. */
+ uint32_t dataWord1; /*!< CAN Frame payload word1. */
+ };
+ struct
+ {
+ uint8_t dataByte3; /*!< CAN Frame payload byte3. */
+ uint8_t dataByte2; /*!< CAN Frame payload byte2. */
+ uint8_t dataByte1; /*!< CAN Frame payload byte1. */
+ uint8_t dataByte0; /*!< CAN Frame payload byte0. */
+ uint8_t dataByte7; /*!< CAN Frame payload byte7. */
+ uint8_t dataByte6; /*!< CAN Frame payload byte6. */
+ uint8_t dataByte5; /*!< CAN Frame payload byte5. */
+ uint8_t dataByte4; /*!< CAN Frame payload byte4. */
+ };
+ };
+} flexcan_frame_t;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*! @brief CAN FD message frame structure.
+ *
+ * The CAN FD message supporting up to sixty four bytes can be used for a data frame, depending on the length
+ * selected for the message buffers. The length should be a enumeration member, see @ref _flexcan_fd_frame_length.
+ */
+typedef struct _flexcan_fd_frame
+{
+ struct
+ {
+ uint32_t timestamp : 16; /*!< FlexCAN internal Free-Running Counter Time Stamp. */
+ uint32_t length : 4; /*!< CAN FD frame data length code (DLC), range see @ref _flexcan_fd_frame_length, When the
+ length <= 8, it equal to the data length, otherwise the number of valid frame data is
+ not equal to the length value. user can
+ use DLC_LENGTH_DECODE(length) macro to get the number of valid data bytes. */
+ uint32_t type : 1; /*!< CAN Frame Type(DATA or REMOTE). */
+ uint32_t format : 1; /*!< CAN Frame Identifier(STD or EXT format). */
+ uint32_t srr : 1; /*!< Substitute Remote request. */
+ uint32_t : 6;
+ uint32_t esi : 1; /*!< Error State Indicator. */
+ uint32_t brs : 1; /*!< Bit Rate Switch. */
+ uint32_t edl : 1; /*!< Extended Data Length. */
+ };
+ struct
+ {
+ uint32_t id : 29; /*!< CAN Frame Identifier, should be set using FLEXCAN_ID_EXT() or FLEXCAN_ID_STD() macro. */
+ uint32_t : 3; /*!< Reserved. */
+ };
+ union
+ {
+ struct
+ {
+ uint32_t dataWord[16]; /*!< CAN FD Frame payload, 16 double word maximum. */
+ };
+ /* Note: the maximum databyte* below is actually 64, user can add them if needed,
+ or just use dataWord[*] instead. */
+ struct
+ {
+ uint8_t dataByte3; /*!< CAN Frame payload byte3. */
+ uint8_t dataByte2; /*!< CAN Frame payload byte2. */
+ uint8_t dataByte1; /*!< CAN Frame payload byte1. */
+ uint8_t dataByte0; /*!< CAN Frame payload byte0. */
+ uint8_t dataByte7; /*!< CAN Frame payload byte7. */
+ uint8_t dataByte6; /*!< CAN Frame payload byte6. */
+ uint8_t dataByte5; /*!< CAN Frame payload byte5. */
+ uint8_t dataByte4; /*!< CAN Frame payload byte4. */
+ };
+ };
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /*! @note ID HIT offset is changed dynamically according to data length code (DLC), when DLC is 15, they will be
+ * located below. Using FLEXCAN_FixEnhancedRxFifoFrameIdHit API is recommended to ensure this idhit value is
+ * correct.*/
+ uint32_t idhit; /*!< CAN Enhanced Rx FIFO filter hit id (This value is only used in Enhanced Rx FIFO receive
+ mode). */
+#endif
+} flexcan_fd_frame_t;
+#endif
+
+/*! @brief FlexCAN protocol timing characteristic configuration structure. */
+typedef struct _flexcan_timing_config
+{
+ uint16_t preDivider; /*!< Classic CAN or CAN FD nominal phase bit rate prescaler. */
+ uint8_t rJumpwidth; /*!< Classic CAN or CAN FD nominal phase Re-sync Jump Width. */
+ uint8_t phaseSeg1; /*!< Classic CAN or CAN FD nominal phase Segment 1. */
+ uint8_t phaseSeg2; /*!< Classic CAN or CAN FD nominal phase Segment 2. */
+ uint8_t propSeg; /*!< Classic CAN or CAN FD nominal phase Propagation Segment. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ uint16_t fpreDivider; /*!< CAN FD data phase bit rate prescaler. */
+ uint8_t frJumpwidth; /*!< CAN FD data phase Re-sync Jump Width. */
+ uint8_t fphaseSeg1; /*!< CAN FD data phase Phase Segment 1. */
+ uint8_t fphaseSeg2; /*!< CAN FD data phase Phase Segment 2. */
+ uint8_t fpropSeg; /*!< CAN FD data phase Propagation Segment. */
+#endif
+} flexcan_timing_config_t;
+
+/*! @brief FlexCAN module configuration structure.
+ * @deprecated Do not use the baudRate. It has been superceded bitRate
+ * @deprecated Do not use the baudRateFD. It has been superceded bitRateFD
+ */
+typedef struct _flexcan_config
+{
+ union
+ {
+ struct
+ {
+ uint32_t baudRate; /*!< FlexCAN bit rate in bps, for classical CAN or CANFD nominal phase. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ uint32_t baudRateFD; /*!< FlexCAN FD bit rate in bps, for CANFD data phase. */
+#endif
+ };
+ struct
+ {
+ uint32_t bitRate; /*!< FlexCAN bit rate in bps, for classical CAN or CANFD nominal phase. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ uint32_t bitRateFD; /*!< FlexCAN FD bit rate in bps, for CANFD data phase. */
+#endif
+ };
+ };
+ flexcan_clock_source_t clkSrc; /*!< Clock source for FlexCAN Protocol Engine. */
+ flexcan_wake_up_source_t wakeupSrc; /*!< Wake up source selection. */
+ uint8_t maxMbNum; /*!< The maximum number of Message Buffers used by user. */
+ bool enableLoopBack; /*!< Enable or Disable Loop Back Self Test Mode. */
+ bool enableTimerSync; /*!< Enable or Disable Timer Synchronization. */
+ bool enableSelfWakeup; /*!< Enable or Disable Self Wakeup Mode. */
+ bool enableIndividMask; /*!< Enable or Disable Rx Individual Mask and Queue feature. */
+ bool disableSelfReception; /*!< Enable or Disable Self Reflection. */
+ bool enableListenOnlyMode; /*!< Enable or Disable Listen Only Mode. */
+#if !(defined(FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_NO_SUPV_SUPPORT)
+ bool enableSupervisorMode; /*!< Enable or Disable Supervisor Mode, enable this mode will make registers allow only
+ Supervisor access. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ bool enableDoze; /*!< Enable or Disable Doze Mode. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ bool enablePretendedeNetworking; /*!< Enable or Disable the Pretended Networking mode. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ bool enableMemoryErrorControl; /*!< Enable or Disable the memory errors detection and correction mechanism. */
+ bool enableNonCorrectableErrorEnterFreeze; /*!< Enable or Disable Non-Correctable Errors In FlexCAN Access Put
+ Device In Freeze Mode. */
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_BIT_TIMING_REG)
+ bool enableTransceiverDelayMeasure; /*!< Enable or Disable the transceiver delay measurement, when it is enabled,
+ then the secondary sample point position is determined by the sum of the
+ transceiver delay measurement plus the enhanced TDC offset. */
+#endif
+ flexcan_timing_config_t timingConfig; /* Protocol timing . */
+} flexcan_config_t;
+
+/*!
+ * @brief FlexCAN Receive Message Buffer configuration structure
+ *
+ * This structure is used as the parameter of FLEXCAN_SetRxMbConfig() function.
+ * The FLEXCAN_SetRxMbConfig() function is used to configure FlexCAN Receive
+ * Message Buffer. The function abort previous receiving process, clean the
+ * Message Buffer and activate the Rx Message Buffer using given Message Buffer
+ * setting.
+ */
+typedef struct _flexcan_rx_mb_config
+{
+ uint32_t id; /*!< CAN Message Buffer Frame Identifier, should be set using
+ FLEXCAN_ID_EXT() or FLEXCAN_ID_STD() macro. */
+ flexcan_frame_format_t format; /*!< CAN Frame Identifier format(Standard of Extend). */
+ flexcan_frame_type_t type; /*!< CAN Frame Type(Data or Remote). */
+} flexcan_rx_mb_config_t;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*! @brief FlexCAN Pretended Networking match source selection. */
+typedef enum _flexcan_pn_match_source
+{
+ kFLEXCAN_PNMatSrcID = 0U, /*!< Message match with ID filtering. */
+ kFLEXCAN_PNMatSrcIDAndData, /*!< Message match with ID filtering and payload filtering. */
+} flexcan_pn_match_source_t;
+
+/*! @brief FlexCAN Pretended Networking mode match type. */
+typedef enum _flexcan_pn_match_mode
+{
+ kFLEXCAN_PNMatModeEqual = 0x0U, /*!< Match upon ID/Payload contents against an exact target value. */
+ kFLEXCAN_PNMatModeGreater, /*!< Match upon an ID/Payload value greater than or equal to a specified target value.
+ */
+ kFLEXCAN_PNMatModeSmaller, /*!< Match upon an ID/Payload value smaller than or equal to a specified target value.
+ */
+ kFLEXCAN_PNMatModeRange, /*!< Match upon an ID/Payload value inside a range, greater than or equal to a specified
+ lower limit, and smaller than or equal to a specified upper limit */
+} flexcan_pn_match_mode_t;
+
+/*!
+ * @brief FlexCAN Pretended Networking configuration structure
+ *
+ * This structure is used as the parameter of FLEXCAN_SetPNConfig() function.
+ * The FLEXCAN_SetPNConfig() function is used to configure FlexCAN Networking work mode.
+ */
+typedef struct _flexcan_pn_config
+{
+ bool enableTimeout; /*!< Enable or Disable timeout event trigger wakeup.*/
+ uint16_t timeoutValue; /*!< The timeout value that generates a wakeup event, the counter timer is incremented based
+ on 64 times the CAN Bit Time unit. */
+ bool enableMatch; /*!< Enable or Disable match event trigger wakeup.*/
+ flexcan_pn_match_source_t matchSrc; /*!< Selects the match source (ID and/or data match) to trigger wakeup. */
+ uint8_t matchNum; /*!< The number of times a given message must match the predefined ID and/or data before
+ generating a wakeup event, range in 0x1 ~ 0xFF. */
+ flexcan_pn_match_mode_t idMatchMode; /*!< The ID match type. */
+ flexcan_pn_match_mode_t dataMatchMode; /*!< The data match type. */
+ uint32_t idLower; /*!< The ID target values 1 which used either for ID match "equal to", "smaller than",
+ "greater than" comparisons, or as the lower limit value in ID match "range detection". */
+ uint32_t idUpper; /*!< The ID target values 2 which used only as the upper limit value in ID match "range
+ detection" or used to store the ID mask in "equal to". */
+ uint8_t lengthLower; /*!< The lower limit for length of data bytes which used only in data match "range
+ detection". Range in 0x0 ~ 0x8.*/
+ uint8_t lengthUpper; /*!< The upper limit for length of data bytes which used only in data match "range
+ detection". Range in 0x0 ~ 0x8.*/
+ union
+ {
+ /*!< The data target values 1 which used either for data match "equal to", "smaller than",
+ "greater than" comparisons, or as the lower limit value in data match "range
+ detection". */
+ struct
+ {
+ uint32_t lowerWord0; /*!< CAN Frame payload word0. */
+ uint32_t lowerWord1; /*!< CAN Frame payload word1. */
+ };
+ struct
+ {
+ uint8_t lowerByte3; /*!< CAN Frame payload byte3. */
+ uint8_t lowerByte2; /*!< CAN Frame payload byte2. */
+ uint8_t lowerByte1; /*!< CAN Frame payload byte1. */
+ uint8_t lowerByte0; /*!< CAN Frame payload byte0. */
+ uint8_t lowerByte7; /*!< CAN Frame payload byte7. */
+ uint8_t lowerByte6; /*!< CAN Frame payload byte6. */
+ uint8_t lowerByte5; /*!< CAN Frame payload byte5. */
+ uint8_t lowerByte4; /*!< CAN Frame payload byte4. */
+ };
+ };
+ union
+ {
+ /*!< The data target values 2 which used only as the upper limit value in data match "range
+ detection" or used to store the data mask in "equal to". */
+ struct
+ {
+ uint32_t upperWord0; /*!< CAN Frame payload word0. */
+ uint32_t upperWord1; /*!< CAN Frame payload word1. */
+ };
+ struct
+ {
+ uint8_t upperByte3; /*!< CAN Frame payload byte3. */
+ uint8_t upperByte2; /*!< CAN Frame payload byte2. */
+ uint8_t upperByte1; /*!< CAN Frame payload byte1. */
+ uint8_t upperByte0; /*!< CAN Frame payload byte0. */
+ uint8_t upperByte7; /*!< CAN Frame payload byte7. */
+ uint8_t upperByte6; /*!< CAN Frame payload byte6. */
+ uint8_t upperByte5; /*!< CAN Frame payload byte5. */
+ uint8_t upperByte4; /*!< CAN Frame payload byte4. */
+ };
+ };
+} flexcan_pn_config_t;
+#endif
+
+/*! @brief FlexCAN Legacy Rx FIFO configuration structure. */
+typedef struct _flexcan_rx_fifo_config
+{
+ uint32_t *idFilterTable; /*!< Pointer to the FlexCAN Legacy Rx FIFO identifier filter table. */
+ uint8_t idFilterNum; /*!< The FlexCAN Legacy Rx FIFO Filter elements quantity. */
+ flexcan_rx_fifo_filter_type_t idFilterType; /*!< The FlexCAN Legacy Rx FIFO Filter type. */
+ flexcan_rx_fifo_priority_t priority; /*!< The FlexCAN Legacy Rx FIFO receive priority. */
+} flexcan_rx_fifo_config_t;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*! @brief FlexCAN Enhanced Rx FIFO Standard ID filter element structure. */
+typedef struct _flexcan_enhanced_rx_fifo_std_id_filter
+{
+ uint32_t filterType : 2; /*!< FlexCAN internal Free-Running Counter Time Stamp. */
+ uint32_t : 2;
+ uint32_t rtr1 : 1; /*!< CAN FD frame data length code (DLC), range see @ref _flexcan_fd_frame_length, When the
+ length <= 8, it equal to the data length, otherwise the number of valid frame data is
+ not equal to the length value. user can
+ use DLC_LENGTH_DECODE(length) macro to get the number of valid data bytes. */
+ uint32_t std1 : 11; /*!< CAN Frame Type(DATA or REMOTE). */
+ uint32_t : 4;
+ uint32_t rtr2 : 1; /*!< CAN Frame Identifier(STD or EXT format). */
+ uint32_t std2 : 11; /*!< Substitute Remote request. */
+} flexcan_enhanced_rx_fifo_std_id_filter_t;
+
+/*! @brief FlexCAN Enhanced Rx FIFO Extended ID filter element structure. */
+typedef struct _flexcan_enhanced_rx_fifo_ext_id_filter
+{
+ uint32_t filterType : 2; /*!< FlexCAN internal Free-Running Counter Time Stamp. */
+ uint32_t rtr1 : 1; /*!< CAN FD frame data length code (DLC), range see @ref _flexcan_fd_frame_length, When the
+ length <= 8, it equal to the data length, otherwise the number of valid frame data is
+ not equal to the length value. user can
+ use DLC_LENGTH_DECODE(length) macro to get the number of valid data bytes. */
+ uint32_t std1 : 29; /*!< CAN Frame Type(DATA or REMOTE). */
+ uint32_t : 2;
+ uint32_t rtr2 : 1; /*!< CAN Frame Identifier(STD or EXT format). */
+ uint32_t std2 : 29; /*!< Substitute Remote request. */
+} flexcan_enhanced_rx_fifo_ext_id_filter_t;
+/*! @brief FlexCAN Enhanced Rx FIFO configuration structure. */
+typedef struct _flexcan_enhanced_rx_fifo_config
+{
+ uint32_t *idFilterTable; /*!< Pointer to the FlexCAN Enhanced Rx FIFO identifier filter table, each table member
+ occupies 32 bit word, table size should be equal to idFilterNum. There are two types of
+ Enhanced Rx FIFO filter elements that can be stored in table : extended-ID filter element
+ (1 word, occupie 1 table members) and standard-ID filter element (2 words, occupies 2 table
+ members), the extended-ID filter element needs to be placed in front of the table. */
+ uint8_t idFilterPairNum; /*!< idFilterPairNum is the Enhanced Rx FIFO identifier filter element pair numbers,
+ each pair of filter elements occupies 2 words and can consist of one extended ID filter
+ element or two standard ID filter elements. */
+ uint8_t extendIdFilterNum; /*!< The number of extended ID filter element items in the FlexCAN enhanced Rx FIFO
+ identifier filter table, each extended-ID filter element occupies 2 words,
+ extendIdFilterNum need less than or equal to idFilterPairNum. */
+ uint8_t fifoWatermark; /*!< (fifoWatermark + 1) is the minimum number of CAN messages stored in the Enhanced RX FIFO
+ which can trigger FIFO watermark interrupt or a DMA request. */
+ flexcan_efifo_dma_per_read_length_t dmaPerReadLength; /*!< Define the length of each read of the Enhanced RX FIFO
+ element by the DAM, see @ref _flexcan_fd_frame_length. */
+ flexcan_rx_fifo_priority_t priority; /*!< The FlexCAN Enhanced Rx FIFO receive priority. */
+} flexcan_enhanced_rx_fifo_config_t;
+#endif
+
+/*! @brief FlexCAN Message Buffer transfer. */
+typedef struct _flexcan_mb_transfer
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ flexcan_fd_frame_t *framefd;
+#endif
+ flexcan_frame_t *frame; /*!< The buffer of CAN Message to be transfer. */
+ uint8_t mbIdx; /*!< The index of Message buffer used to transfer Message. */
+} flexcan_mb_transfer_t;
+
+/*! @brief FlexCAN Rx FIFO transfer. */
+typedef struct _flexcan_fifo_transfer
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ flexcan_fd_frame_t *framefd; /*!< The buffer of CAN Message to be received from Enhanced Rx FIFO. */
+#endif
+ flexcan_frame_t *frame; /*!< The buffer of CAN Message to be received from Legacy Rx FIFO. */
+ size_t frameNum; /*!< Number of CAN Message need to be received from Legacy or Ehanced Rx FIFO. */
+} flexcan_fifo_transfer_t;
+
+/*! @brief FlexCAN handle structure definition. */
+typedef struct _flexcan_handle flexcan_handle_t;
+
+/*! @brief FlexCAN transfer callback function.
+ *
+ * The FlexCAN transfer callback returns a value from the underlying layer.
+ * If the status equals to kStatus_FLEXCAN_ErrorStatus, the result parameter is the Content of
+ * FlexCAN status register which can be used to get the working status(or error status) of FlexCAN module.
+ * If the status equals to other FlexCAN Message Buffer transfer status, the result is the index of
+ * Message Buffer that generate transfer event.
+ * If the status equals to other FlexCAN Message Buffer transfer status, the result is meaningless and should be
+ * Ignored.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+#define FLEXCAN_CALLBACK(x) \
+ void(x)(CAN_Type * base, flexcan_handle_t * handle, status_t status, uint64_t result, void *userData)
+typedef void (*flexcan_transfer_callback_t)(
+ CAN_Type *base, flexcan_handle_t *handle, status_t status, uint64_t result, void *userData);
+#else
+#define FLEXCAN_CALLBACK(x) \
+ void(x)(CAN_Type * base, flexcan_handle_t * handle, status_t status, uint32_t result, void *userData)
+typedef void (*flexcan_transfer_callback_t)(
+ CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData);
+#endif
+
+/*! @brief FlexCAN handle structure. */
+struct _flexcan_handle
+{
+ flexcan_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< FlexCAN callback function parameter.*/
+ flexcan_frame_t
+ *volatile mbFrameBuf[CAN_WORD1_COUNT]; /*!< The buffer for received CAN data from Message Buffers. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ flexcan_fd_frame_t
+ *volatile mbFDFrameBuf[CAN_WORD1_COUNT]; /*!< The buffer for received CAN FD data from Message Buffers. */
+#endif
+ flexcan_frame_t *volatile rxFifoFrameBuf; /*!< The buffer for received CAN data from Legacy Rx FIFO. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ flexcan_fd_frame_t *volatile rxFifoFDFrameBuf; /*!< The buffer for received CAN FD data from Ehanced Rx FIFO. */
+#endif
+ size_t rxFifoFrameNum; /*!< The number of CAN messages remaining to be received from Legacy or Ehanced Rx FIFO. */
+ size_t rxFifoTransferTotalNum; /*!< Total CAN Message number need to be received from Legacy or Ehanced Rx FIFO. */
+ volatile uint8_t mbState[CAN_WORD1_COUNT]; /*!< Message Buffer transfer state. */
+ volatile uint8_t rxFifoState; /*!< Rx FIFO transfer state. */
+ volatile uint32_t timestamp[CAN_WORD1_COUNT]; /*!< Mailbox transfer timestamp. */
+};
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Enter FlexCAN Freeze Mode.
+ *
+ * This function makes the FlexCAN work under Freeze Mode.
+ *
+ * @param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_EnterFreezeMode(CAN_Type *base);
+
+/*!
+ * @brief Exit FlexCAN Freeze Mode.
+ *
+ * This function makes the FlexCAN leave Freeze Mode.
+ *
+ * @param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_ExitFreezeMode(CAN_Type *base);
+
+/*!
+ * @brief Get the FlexCAN instance from peripheral base address.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return FlexCAN instance.
+ */
+uint32_t FLEXCAN_GetInstance(CAN_Type *base);
+
+/*!
+ * @brief Calculates the improved timing values by specific bit Rates for classical CAN.
+ *
+ * This function use to calculates the Classical CAN timing values according to the given bit rate. The Calculated
+ * timing values will be set in CTRL1/CBT/ENCBT register. The calculation is based on the recommendation of the CiA 301
+ * v4.2.0 and previous version document.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param bitRate The classical CAN speed in bps defined by user, should be less than or equal to 1Mbps.
+ * @param sourceClock_Hz The Source clock frequency in Hz.
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration.
+ */
+bool FLEXCAN_CalculateImprovedTimingValues(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig);
+
+/*!
+ * @brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_Init function by passing in these parameters.
+ * @code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.bitRate = 1000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_Init(CAN0, &flexcanConfig, 40000000UL);
+ * @endcode
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the user-defined configuration structure.
+ * @param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ */
+void FLEXCAN_Init(CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Calculates the improved timing values by specific bit rates for CANFD.
+ *
+ * This function use to calculates the CANFD timing values according to the given nominal phase bit rate and data phase
+ * bit rate. The Calculated timing values will be set in CBT/ENCBT and FDCBT/EDCBT registers. The calculation is based
+ * on the recommendation of the CiA 1301 v1.0.0 document.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param bitRate The CANFD bus control speed in bps defined by user.
+ * @param bitRateFD The CAN FD data phase speed in bps defined by user. Equal to bitRate means disable bit rate
+ * switching.
+ * @param sourceClock_Hz The Source clock frequency in Hz.
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+bool FLEXCAN_FDCalculateImprovedTimingValues(CAN_Type *base,
+ uint32_t bitRate,
+ uint32_t bitRateFD,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig);
+/*!
+ * @brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_FDInit function by passing in these parameters.
+ * @code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.bitRate = 1000000U;
+ * flexcanConfig.bitRateFD = 2000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_FDInit(CAN0, &flexcanConfig, 80000000UL, kFLEXCAN_16BperMB, true);
+ * @endcode
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the user-defined configuration structure.
+ * @param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ * @param dataSize FlexCAN Message Buffer payload size. The actual transmitted or received CAN FD frame data size needs
+ * to be less than or equal to this value.
+ * @param brs True if bit rate switch is enabled in FD mode.
+ */
+void FLEXCAN_FDInit(
+ CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz, flexcan_mb_size_t dataSize, bool brs);
+#endif
+
+/*!
+ * @brief De-initializes a FlexCAN instance.
+ *
+ * This function disables the FlexCAN module clock and sets all register values
+ * to the reset value.
+ *
+ * @param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_Deinit(CAN_Type *base);
+
+/*!
+ * @brief Gets the default configuration structure.
+ *
+ * This function initializes the FlexCAN configuration structure to default values. The default
+ * values are as follows.
+ * flexcanConfig->clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig->bitRate = 1000000U;
+ * flexcanConfig->bitRateFD = 2000000U;
+ * flexcanConfig->maxMbNum = 16;
+ * flexcanConfig->enableLoopBack = false;
+ * flexcanConfig->enableSelfWakeup = false;
+ * flexcanConfig->enableIndividMask = false;
+ * flexcanConfig->disableSelfReception = false;
+ * flexcanConfig->enableListenOnlyMode = false;
+ * flexcanConfig->enableDoze = false;
+ * flexcanConfig->enableMemoryErrorControl = true;
+ * flexcanConfig->enableNonCorrectableErrorEnterFreeze = true;
+ * flexcanConfig.timingConfig = timingConfig;
+ *
+ * @param pConfig Pointer to the FlexCAN configuration structure.
+ */
+void FLEXCAN_GetDefaultConfig(flexcan_config_t *pConfig);
+
+/* @} */
+
+/*!
+ * @name Configuration.
+ * @{
+ */
+
+/*!
+ * @brief Sets the FlexCAN classical CAN protocol timing characteristic.
+ *
+ * This function gives user settings to classical CAN or CAN FD nominal phase timing characteristic.
+ * The function is for an experienced user. For less experienced users, call the FLEXCAN_SetBitRate() instead.
+ *
+ * @note Calling FLEXCAN_SetTimingConfig() overrides the bit rate set in FLEXCAN_Init() or FLEXCAN_SetBitRate().
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig);
+
+/*!
+ * @brief Set bit rate of FlexCAN classical CAN frame or CAN FD frame nominal phase.
+ *
+ * This function set the bit rate of classical CAN frame or CAN FD frame nominal phase base on
+ * FLEXCAN_CalculateImprovedTimingValues() API calculated timing values.
+ *
+ * @note Calling FLEXCAN_SetBitRate() overrides the bit rate set in FLEXCAN_Init().
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param bitRate_Bps Bit rate in Bps.
+ * @return kStatus_Success - Set CAN baud rate (only Nominal phase) successfully.
+ */
+status_t FLEXCAN_SetBitRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t bitRate_Bps);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Sets the FlexCAN CANFD data phase timing characteristic.
+ *
+ * This function gives user settings to CANFD data phase timing characteristic.
+ * The function is for an experienced user. For less experienced users, call the FLEXCAN_SetFDBitRate()
+ * to set both Nominal/Data bit Rate instead.
+ *
+ * @note Calling FLEXCAN_SetFDTimingConfig() overrides the data phase bit rate set in
+ * FLEXCAN_FDInit()/FLEXCAN_SetFDBitRate().
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetFDTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig);
+
+/*!
+ * @brief Set bit rate of FlexCAN FD frame.
+ *
+ * This function set the baud rate of FLEXCAN FD base on FLEXCAN_FDCalculateImprovedTimingValues() API calculated timing
+ * values.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param bitRateN_Bps Nominal bit Rate in Bps.
+ * @param bitRateD_Bps Data bit Rate in Bps.
+ * @return kStatus_Success - Set CAN FD bit rate (include Nominal and Data phase) successfully.
+ */
+status_t FLEXCAN_SetFDBitRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t bitRateN_Bps, uint32_t bitRateD_Bps);
+#endif
+
+/*!
+ * @brief Sets the FlexCAN receive message buffer global mask.
+ *
+ * This function sets the global mask for the FlexCAN message buffer in a matching process.
+ * The configuration is only effective when the Rx individual mask is disabled in the FLEXCAN_Init().
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask Rx Message Buffer Global Mask value.
+ */
+void FLEXCAN_SetRxMbGlobalMask(CAN_Type *base, uint32_t mask);
+
+/*!
+ * @brief Sets the FlexCAN receive FIFO global mask.
+ *
+ * This function sets the global mask for FlexCAN FIFO in a matching process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask Rx Fifo Global Mask value.
+ */
+void FLEXCAN_SetRxFifoGlobalMask(CAN_Type *base, uint32_t mask);
+
+/*!
+ * @brief Sets the FlexCAN receive individual mask.
+ *
+ * This function sets the individual mask for the FlexCAN matching process.
+ * The configuration is only effective when the Rx individual mask is enabled in the FLEXCAN_Init().
+ * If the Rx FIFO is disabled, the individual mask is applied to the corresponding Message Buffer.
+ * If the Rx FIFO is enabled, the individual mask for Rx FIFO occupied Message Buffer is applied to
+ * the Rx Filter with the same index. Note that only the first 32
+ * individual masks can be used as the Rx FIFO filter mask.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param maskIdx The Index of individual Mask.
+ * @param mask Rx Individual Mask value.
+ */
+void FLEXCAN_SetRxIndividualMask(CAN_Type *base, uint8_t maskIdx, uint32_t mask);
+
+/*!
+ * @brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The Message Buffer index.
+ * @param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The Message Buffer index.
+ * @param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetFDTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable);
+#endif
+
+/*!
+ * @brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The Message Buffer index.
+ * @param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * @param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The Message Buffer index.
+ * @param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * @param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetFDRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable);
+#endif
+
+/*!
+ * @brief Configures the FlexCAN Legacy Rx FIFO.
+ *
+ * This function configures the FlexCAN Rx FIFO with given configuration.
+ * @note Legacy Rx FIFO only can receive classic CAN message.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pRxFifoConfig Pointer to the FlexCAN Legacy Rx FIFO configuration structure. Can be NULL when enable parameter
+ * is false.
+ * @param enable Enable/disable Legacy Rx FIFO.
+ * - true: Enable Legacy Rx FIFO.
+ * - false: Disable Legacy Rx FIFO.
+ */
+void FLEXCAN_SetRxFifoConfig(CAN_Type *base, const flexcan_rx_fifo_config_t *pRxFifoConfig, bool enable);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Configures the FlexCAN Enhanced Rx FIFO.
+ *
+ * This function configures the Enhanced Rx FIFO with given configuration.
+ * @note Enhanced Rx FIFO support receive classic CAN or CAN FD messages, Legacy Rx FIFO and Enhanced Rx FIFO
+ * cannot be enabled at the same time.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the FlexCAN Enhanced Rx FIFO configuration structure. Can be NULL when enable parameter
+ * is false.
+ * @param enable Enable/disable Enhanced Rx FIFO.
+ * - true: Enable Enhanced Rx FIFO.
+ * - false: Disable Enhanced Rx FIFO.
+ */
+void FLEXCAN_SetEnhancedRxFifoConfig(CAN_Type *base, const flexcan_enhanced_rx_fifo_config_t *pConfig, bool enable);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*!
+ * @brief Configures the FlexCAN Pretended Networking mode.
+ *
+ * This function configures the FlexCAN Pretended Networking mode with given configuration.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pConfig Pointer to the FlexCAN Rx FIFO configuration structure.
+ */
+void FLEXCAN_SetPNConfig(CAN_Type *base, const flexcan_pn_config_t *pConfig);
+#endif
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexCAN module interrupt flags.
+ *
+ * This function gets all FlexCAN status flags. The flags are returned as the logical
+ * OR value of the enumerators @ref _flexcan_flags. To check the specific status,
+ * compare the return value with enumerators in @ref _flexcan_flags.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return FlexCAN status flags which are ORed by the enumerators in the _flexcan_flags.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+static inline uint64_t FLEXCAN_GetStatusFlags(CAN_Type *base)
+{
+ uint64_t tempflag = (uint64_t)base->ESR1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /* Get PN Wake Up status. */
+ tempflag |= FLEXCAN_PN_STATUS_MASK(base->WU_MTC);
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /* Get Enhanced Rx FIFO status. */
+ tempflag |= FLEXCAN_EFIFO_STATUS_MASK(base->ERFSR);
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Get Memory Error status. */
+ tempflag |= FLEXCAN_MECR_STATUS_MASK(base->ERRSR);
+#endif
+ return tempflag;
+}
+#else
+static inline uint32_t FLEXCAN_GetStatusFlags(CAN_Type *base)
+{
+ return base->ESR1;
+}
+#endif
+/*!
+ * @brief Clears status flags with the provided mask.
+ *
+ * This function clears the FlexCAN status flags with a provided mask. An automatically cleared flag
+ * can't be cleared by this function.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The status flags to be cleared, it is logical OR value of @ref _flexcan_flags.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+static inline void FLEXCAN_ClearStatusFlags(CAN_Type *base, uint64_t mask)
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /* Clear PN Wake Up status. */
+ base->WU_MTC = FLEXCAN_PN_STATUS_UNMASK(mask);
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /* Clear Enhanced Rx FIFO status. */
+ base->ERFSR = FLEXCAN_EFIFO_STATUS_UNMASK(mask);
+#endif
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Clear Memory Error status. */
+ base->ERRSR = FLEXCAN_MECR_STATUS_UNMASK(mask);
+#endif
+ base->ESR1 = (uint32_t)(mask & 0xFFFFFFFFU);
+}
+#else
+static inline void FLEXCAN_ClearStatusFlags(CAN_Type *base, uint32_t mask)
+{
+ /* Write 1 to clear status flag. */
+ base->ESR1 = mask;
+}
+#endif
+/*!
+ * @brief Gets the FlexCAN Bus Error Counter value.
+ *
+ * This function gets the FlexCAN Bus Error Counter value for both Tx and
+ * Rx direction. These values may be needed in the upper layer error handling.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param txErrBuf Buffer to store Tx Error Counter value.
+ * @param rxErrBuf Buffer to store Rx Error Counter value.
+ */
+static inline void FLEXCAN_GetBusErrCount(CAN_Type *base, uint8_t *txErrBuf, uint8_t *rxErrBuf)
+{
+ if (NULL != txErrBuf)
+ {
+ *txErrBuf = (uint8_t)((base->ECR & CAN_ECR_TXERRCNT_MASK) >> CAN_ECR_TXERRCNT_SHIFT);
+ }
+
+ if (NULL != rxErrBuf)
+ {
+ *rxErrBuf = (uint8_t)((base->ECR & CAN_ECR_RXERRCNT_MASK) >> CAN_ECR_RXERRCNT_SHIFT);
+ }
+}
+
+/*!
+ * @brief Gets the FlexCAN Message Buffer interrupt flags.
+ *
+ * This function gets the interrupt flags of a given Message Buffers.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The ORed FlexCAN Message Buffer mask.
+ * @return The status of given Message Buffers.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+static inline uint64_t FLEXCAN_GetMbStatusFlags(CAN_Type *base, uint64_t mask)
+#else
+static inline uint32_t FLEXCAN_GetMbStatusFlags(CAN_Type *base, uint32_t mask)
+#endif
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t tempflag = (uint64_t)base->IFLAG1;
+ return (tempflag | (((uint64_t)base->IFLAG2) << 32)) & mask;
+#else
+ return (base->IFLAG1 & mask);
+#endif
+}
+
+/*!
+ * @brief Clears the FlexCAN Message Buffer interrupt flags.
+ *
+ * This function clears the interrupt flags of a given Message Buffers.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The ORed FlexCAN Message Buffer mask.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+static inline void FLEXCAN_ClearMbStatusFlags(CAN_Type *base, uint64_t mask)
+#else
+static inline void FLEXCAN_ClearMbStatusFlags(CAN_Type *base, uint32_t mask)
+#endif
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IFLAG1 = (uint32_t)(mask & 0xFFFFFFFFU);
+ base->IFLAG2 = (uint32_t)(mask >> 32);
+#else
+ base->IFLAG1 = mask;
+#endif
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+/*!
+ * @brief Gets the FlexCAN Memory Error Report registers status.
+ *
+ * This function gets the FlexCAN Memory Error Report registers status.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param errorStatus Pointer to FlexCAN Memory Error Report registers status structure.
+ */
+void FLEXCAN_GetMemoryErrorReportStatus(CAN_Type *base, flexcan_memory_error_report_status_t *errorStatus);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*!
+ * @brief Gets the FlexCAN Number of Matches when in Pretended Networking.
+ *
+ * This function gets the number of times a given message has matched the predefined filtering criteria for ID and/or PL
+ * before a wakeup event.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return The number of received wake up msessages.
+ */
+static inline uint8_t FLEXCAN_GetPNMatchCount(CAN_Type *base)
+{
+ return (uint8_t)((base->WU_MTC & CAN_WU_MTC_MCOUNTER_MASK) >> CAN_WU_MTC_MCOUNTER_SHIFT);
+}
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Gets the number of FlexCAN Enhanced Rx FIFO available frames.
+ *
+ * This function gets the number of CAN messages stored in the Enhanced Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return The number of available CAN messages stored in the Enhanced Rx FIFO.
+ */
+static inline uint32_t FLEXCAN_GetEnhancedFifoDataCount(CAN_Type *base)
+{
+ return (base->ERFSR & CAN_ERFSR_ERFEL_MASK);
+}
+#endif
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables FlexCAN interrupts according to the provided mask.
+ *
+ * This function enables the FlexCAN interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members, see @ref _flexcan_interrupt_enable.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The interrupts to enable. Logical OR of @ref _flexcan_interrupt_enable.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+static inline void FLEXCAN_EnableInterrupts(CAN_Type *base, uint64_t mask)
+#else
+static inline void FLEXCAN_EnableInterrupts(CAN_Type *base, uint32_t mask)
+#endif
+{
+ /* Solve Self Wake Up interrupt. */
+ base->MCR |= (uint32_t)(mask & (uint32_t)kFLEXCAN_WakeUpInterruptEnable);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+ /* Solve CAN FD frames data phase error interrupt. */
+ base->CTRL2 |= (uint32_t)(mask & (uint32_t)kFLEXCAN_FDErrorInterruptEnable);
+ }
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /* Solve PN Wake Up interrupt. */
+ base->CTRL1_PN |= FLEXCAN_PN_INT_UNMASK(mask);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /* Solve Enhanced Rx FIFO interrupt. */
+ base->ERFIER |= FLEXCAN_EFIFO_INT_UNMASK(mask);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Solve Memory Error interrupt. */
+ base->MECR |= FLEXCAN_MECR_INT_UNMASK(mask);
+#endif
+
+ /* Solve interrupt enable bits in CTRL1 register. */
+ base->CTRL1 |=
+ (uint32_t)(mask & ((uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable));
+}
+
+/*!
+ * @brief Disables FlexCAN interrupts according to the provided mask.
+ *
+ * This function disables the FlexCAN interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members, see @ref _flexcan_interrupt_enable.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The interrupts to disable. Logical OR of @ref _flexcan_interrupt_enable.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+static inline void FLEXCAN_DisableInterrupts(CAN_Type *base, uint64_t mask)
+#else
+static inline void FLEXCAN_DisableInterrupts(CAN_Type *base, uint32_t mask)
+#endif
+{
+ /* Solve Wake Up Interrupt. */
+ base->MCR &= ~(uint32_t)(mask & (uint32_t)kFLEXCAN_WakeUpInterruptEnable);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+ /* Solve CAN FD frames data phase error interrupt. */
+ base->CTRL2 &= ~(uint32_t)(mask & (uint32_t)kFLEXCAN_FDErrorInterruptEnable);
+ }
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+ /* Solve PN Wake Up Interrupt. */
+ base->CTRL1_PN &= ~FLEXCAN_PN_STATUS_UNMASK(mask);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ /* Solve Enhanced Rx FIFO interrupt. */
+ base->ERFIER &= ~FLEXCAN_EFIFO_INT_UNMASK(mask);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Solve Memory Error Interrupt. */
+ base->MECR &= ~FLEXCAN_MECR_STATUS_UNMASK(mask);
+#endif
+
+ /* Solve interrupt enable bits in CTRL1 register. */
+ base->CTRL1 &=
+ ~(uint32_t)(mask & ((uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable));
+}
+
+/*!
+ * @brief Enables FlexCAN Message Buffer interrupts.
+ *
+ * This function enables the interrupts of given Message Buffers.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The ORed FlexCAN Message Buffer mask.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+static inline void FLEXCAN_EnableMbInterrupts(CAN_Type *base, uint64_t mask)
+#else
+static inline void FLEXCAN_EnableMbInterrupts(CAN_Type *base, uint32_t mask)
+#endif
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK1 |= (uint32_t)(mask & 0xFFFFFFFFU);
+ base->IMASK2 |= (uint32_t)(mask >> 32);
+#else
+ base->IMASK1 |= mask;
+#endif
+}
+
+/*!
+ * @brief Disables FlexCAN Message Buffer interrupts.
+ *
+ * This function disables the interrupts of given Message Buffers.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mask The ORed FlexCAN Message Buffer mask.
+ */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+static inline void FLEXCAN_DisableMbInterrupts(CAN_Type *base, uint64_t mask)
+#else
+static inline void FLEXCAN_DisableMbInterrupts(CAN_Type *base, uint32_t mask)
+#endif
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK1 &= ~((uint32_t)(mask & 0xFFFFFFFFU));
+ base->IMASK2 &= ~((uint32_t)(mask >> 32));
+#else
+ base->IMASK1 &= ~mask;
+#endif
+}
+
+/* @} */
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA) && FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA)
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables or disables the FlexCAN Rx FIFO DMA request.
+ *
+ * This function enables or disables the DMA feature of FlexCAN build-in Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param enable true to enable, false to disable.
+ */
+void FLEXCAN_EnableRxFifoDMA(CAN_Type *base, bool enable);
+
+/*!
+ * @brief Gets the Rx FIFO Head address.
+ *
+ * This function returns the FlexCAN Rx FIFO Head address, which is mainly used for the DMA/eDMA use case.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return FlexCAN Rx FIFO Head address.
+ */
+static inline uintptr_t FLEXCAN_GetRxFifoHeadAddr(CAN_Type *base)
+{
+ return (uintptr_t) & (base->MB[0].CS);
+}
+
+/* @} */
+#endif /* FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Enables or disables the FlexCAN module operation.
+ *
+ * This function enables or disables the FlexCAN module.
+ *
+ * @param base FlexCAN base pointer.
+ * @param enable true to enable, false to disable.
+ */
+static inline void FLEXCAN_Enable(CAN_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MCR &= ~CAN_MCR_MDIS_MASK;
+
+ /* Wait FlexCAN exit from low-power mode. */
+ while (0U != (base->MCR & CAN_MCR_LPMACK_MASK))
+ {
+ }
+ }
+ else
+ {
+ base->MCR |= CAN_MCR_MDIS_MASK;
+
+ /* Wait FlexCAN enter low-power mode. */
+ while (0U == (base->MCR & CAN_MCR_LPMACK_MASK))
+ {
+ }
+ }
+}
+
+/*!
+ * @brief Writes a FlexCAN Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN Message transmit. After
+ * that the function returns immediately.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @param pTxFrame Pointer to CAN message frame to be sent.
+ * @retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * @retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_frame_t *pTxFrame);
+
+/*!
+ * @brief Reads a FlexCAN Message from Receive Message Buffer.
+ *
+ * This function reads a CAN message from a specified Receive Message Buffer.
+ * The function fills a receive CAN message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @param pRxFrame Pointer to CAN message frame structure for reception.
+ * @retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * @retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * @retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Writes a FlexCAN FD Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN FD Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN FD Message transmit. After
+ * that the function returns immediately.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ * @param pTxFrame Pointer to CAN FD message frame to be sent.
+ * @retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * @retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteFDTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_fd_frame_t *pTxFrame);
+
+/*!
+ * @brief Reads a FlexCAN FD Message from Receive Message Buffer.
+ *
+ * This function reads a CAN FD message from a specified Receive Message Buffer.
+ * The function fills a receive CAN FD message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ * @param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * @retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * @retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * @retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadFDRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame);
+#endif
+
+/*!
+ * @brief Reads a FlexCAN Message from Legacy Rx FIFO.
+ *
+ * This function reads a CAN message from the FlexCAN Legacy Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pRxFrame Pointer to CAN message frame structure for reception.
+ * @retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * @retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_ReadRxFifo(CAN_Type *base, flexcan_frame_t *pRxFrame);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Reads a FlexCAN Message from Enhanced Rx FIFO.
+ *
+ * This function reads a CAN or CAN FD message from the FlexCAN Enhanced Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * @retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * @retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_ReadEnhancedRxFifo(CAN_Type *base, flexcan_fd_frame_t *pRxFrame);
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_PN_MODE) && FSL_FEATURE_FLEXCAN_HAS_PN_MODE)
+/*!
+ * @brief Reads a FlexCAN Message from Wake Up MB.
+ *
+ * This function reads a CAN message from the FlexCAN Wake up Message Buffers. There are four Wake up Message Buffers
+ * (WMBs) used to store incoming messages in Pretended Networking mode. The WMB index indicates the arrival order. The
+ * last message is stored in WMB3.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pRxFrame Pointer to CAN message frame structure for reception.
+ * @param mbIdx The FlexCAN Wake up Message Buffer index. Range in 0x0 ~ 0x3.
+ * @retval kStatus_Success - Read Message from Wake up Message Buffer successfully.
+ * @retval kStatus_Fail - Wake up Message Buffer has no valid content.
+ */
+status_t FLEXCAN_ReadPNWakeUpMB(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame);
+#endif
+/* @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Performs a polling send transaction on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ * @param pTxFrame Pointer to CAN FD message frame to be sent.
+ * @retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * @retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferFDSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pTxFrame);
+
+/*!
+ * @brief Performs a polling receive transaction on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ * @param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * @retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * @retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * @retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferFDReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame);
+
+/*!
+ * @brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * @retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * @retval kStatus_Fail Write Tx Message Buffer failed.
+ * @retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer);
+
+/*!
+ * @brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * @retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * @retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer);
+
+/*!
+ * @brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx);
+
+/*!
+ * @brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx);
+#endif
+
+/*!
+ * @brief Performs a polling send transaction on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @param pTxFrame Pointer to CAN message frame to be sent.
+ * @retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * @retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pTxFrame);
+
+/*!
+ * @brief Performs a polling receive transaction on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @param pRxFrame Pointer to CAN message frame structure for reception.
+ * @retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * @retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * @retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame);
+
+/*!
+ * @brief Performs a polling receive transaction from Legacy Rx FIFO on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param pRxFrame Pointer to CAN message frame structure for reception.
+ * @retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * @retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_TransferReceiveFifoBlocking(CAN_Type *base, flexcan_frame_t *pRxFrame);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Performs a polling receive transaction from Enhanced Rx FIFO on the CAN bus.
+ *
+ * @note A transfer handle does not need to be created before calling this API.
+ *
+ * @param base FlexCAN peripheral base pointer.
+ * @param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * @retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * @retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_TransferReceiveEnhancedFifoBlocking(CAN_Type *base, flexcan_fd_frame_t *pRxFrame);
+#endif
+
+/*!
+ * @brief Initializes the FlexCAN handle.
+ *
+ * This function initializes the FlexCAN handle, which can be used for other FlexCAN
+ * transactional APIs. Usually, for a specified FlexCAN instance,
+ * call this API once to get the initialized handle.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ */
+void FLEXCAN_TransferCreateHandle(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * @retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * @retval kStatus_Fail Write Tx Message Buffer failed.
+ * @retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer);
+
+/*!
+ * @brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * @retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * @retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer);
+
+/*!
+ * @brief Receives a message from Rx FIFO using IRQ.
+ *
+ * This function receives a message using IRQ. This is a non-blocking function, which returns
+ * right away. When all messages have been received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pFifoXfer FlexCAN Rx FIFO transfer structure. See the @ref flexcan_fifo_transfer_t.
+ * @retval kStatus_Success - Start Rx FIFO receiving process successfully.
+ * @retval kStatus_FLEXCAN_RxFifoBusy - Rx FIFO is currently in use.
+ */
+status_t FLEXCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer);
+
+/*!
+ * @brief Gets the Legacy Rx Fifo transfer status during a interrupt non-blocking receive.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param count Number of CAN messages receive so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+
+status_t FLEXCAN_TransferGetReceiveFifoCount(CAN_Type *base, flexcan_handle_t *handle, size_t *count);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Receives a message from Enhanced Rx FIFO using IRQ.
+ *
+ * This function receives a message using IRQ. This is a non-blocking function, which returns
+ * right away. When all messages have been received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pFifoXfer FlexCAN Rx FIFO transfer structure. See the ref flexcan_fifo_transfer_t.@
+ * @retval kStatus_Success - Start Rx FIFO receiving process successfully.
+ * @retval kStatus_FLEXCAN_RxFifoBusy - Rx FIFO is currently in use.
+ */
+status_t FLEXCAN_TransferReceiveEnhancedFifoNonBlocking(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer);
+
+/*!
+ * @brief Gets the Enhanced Rx Fifo transfer status during a interrupt non-blocking receive.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param count Number of CAN messages receive so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+
+static inline status_t FLEXCAN_TransferGetReceiveEnhancedFifoCount(CAN_Type *base,
+ flexcan_handle_t *handle,
+ size_t *count)
+{
+ return FLEXCAN_TransferGetReceiveFifoCount(base, handle, count);
+}
+#endif
+
+/*!
+ * @brief Gets the detail index of Mailbox's Timestamp by handle.
+ *
+ * Then function can only be used when calling non-blocking Data transfer (TX/RX) API,
+ * After TX/RX data transfer done (User can get the status by handler's callback function),
+ * we can get the detail index of Mailbox's timestamp by handle,
+ * Detail non-blocking data transfer API (TX/RX) contain.
+ * -FLEXCAN_TransferSendNonBlocking
+ * -FLEXCAN_TransferFDSendNonBlocking
+ * -FLEXCAN_TransferReceiveNonBlocking
+ * -FLEXCAN_TransferFDReceiveNonBlocking
+ * -FLEXCAN_TransferReceiveFifoNonBlocking
+ *
+ * @param handle FlexCAN handle pointer.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @retval the index of mailbox 's timestamp stored in the handle.
+ *
+ */
+uint32_t FLEXCAN_GetTimeStamp(flexcan_handle_t *handle, uint8_t mbIdx);
+
+/*!
+ * @brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx);
+
+/*!
+ * @brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx);
+
+/*!
+ * @brief Aborts the interrupt driven message receive from Rx FIFO process.
+ *
+ * This function aborts the interrupt driven message receive from Rx FIFO process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferAbortReceiveFifo(CAN_Type *base, flexcan_handle_t *handle);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Aborts the interrupt driven message receive from Enhanced Rx FIFO process.
+ *
+ * This function aborts the interrupt driven message receive from Enhanced Rx FIFO process.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferAbortReceiveEnhancedFifo(CAN_Type *base, flexcan_handle_t *handle);
+#endif
+
+/*!
+ * @brief FlexCAN IRQ handle function.
+ *
+ * This function handles the FlexCAN Error, the Message Buffer, and the Rx FIFO IRQ request.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferHandleIRQ(CAN_Type *base, flexcan_handle_t *handle);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_FLEXCAN_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan_edma.h
new file mode 100644
index 0000000000..5af4aa4028
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexcan/fsl_flexcan_edma.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXCAN_EDMA_H_
+#define _FSL_FLEXCAN_EDMA_H_
+
+#include "fsl_flexcan.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexcan_edma_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexCAN EDMA driver version. */
+#define FSL_FLEXCAN_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 9, 2))
+/*@}*/
+
+/* Forward declaration of the handle typedef. */
+typedef struct _flexcan_edma_handle flexcan_edma_handle_t;
+
+/*! @brief FlexCAN transfer callback function. */
+typedef void (*flexcan_edma_transfer_callback_t)(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief FlexCAN eDMA handle
+ */
+struct _flexcan_edma_handle
+{
+ flexcan_edma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< FlexCAN callback function parameter.*/
+ edma_handle_t *rxFifoEdmaHandle; /*!< The EDMA handler for Rx FIFO. */
+ volatile uint8_t rxFifoState; /*!< Rx FIFO transfer state. */
+ size_t frameNum; /*!< The number of messages that need to be received. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+ flexcan_fd_frame_t *framefd; /*!< Point to the buffer of CAN Message to be received from Enhanced Rx FIFO. */
+#endif
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexCAN handle, which is used in transactional functions.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle Pointer to flexcan_edma_handle_t structure.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @param rxFifoEdmaHandle User-requested DMA handle for Rx FIFO DMA transfer.
+ */
+void FLEXCAN_TransferCreateHandleEDMA(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ flexcan_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *rxFifoEdmaHandle);
+
+/*!
+ * @brief Prepares the eDMA transfer configuration for FLEXCAN Legacy RX FIFO.
+ *
+ * This function prepares the eDMA transfer configuration structure according to FLEXCAN Legacy RX FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param pFifoXfer FlexCAN Rx FIFO EDMA transfer structure, see #flexcan_fifo_transfer_t.
+ * @param pEdmaConfig The user configuration structure of type edma_transfer_t.
+ *
+ */
+void FLEXCAN_PrepareTransfConfiguration(CAN_Type *base,
+ flexcan_fifo_transfer_t *pFifoXfer,
+ edma_transfer_config_t *pEdmaConfig);
+
+/*!
+ * @brief Start Transfer Data from the FLEXCAN Legacy Rx FIFO using eDMA.
+ *
+ * This function to Update edma transfer confiugration and Start eDMA transfer
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle Pointer to flexcan_edma_handle_t structure.
+ * @param pEdmaConfig The user configuration structure of type edma_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXCAN_RxFifoBusy Previous transfer ongoing.
+ */
+status_t FLEXCAN_StartTransferDatafromRxFIFO(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ edma_transfer_config_t *pEdmaConfig);
+
+/*!
+ * @brief Receives the CAN Message from the Legacy Rx FIFO using eDMA.
+ *
+ * This function receives the CAN Message using eDMA. This is a non-blocking function, which returns
+ * right away. After the CAN Message is received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle Pointer to flexcan_edma_handle_t structure.
+ * @param pFifoXfer FlexCAN Rx FIFO EDMA transfer structure, see #flexcan_fifo_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXCAN_RxFifoBusy Previous transfer ongoing.
+ */
+status_t FLEXCAN_TransferReceiveFifoEDMA(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer);
+/*!
+ * @brief Gets the Legacy Rx Fifo transfer status during a interrupt non-blocking receive.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param count Number of CAN messages receive so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+
+status_t FLEXCAN_TransferGetReceiveFifoCountEMDA(CAN_Type *base, flexcan_edma_handle_t *handle, size_t *count);
+/*!
+ * @brief Aborts the receive Legacy/Enhanced Rx FIFO process which used eDMA.
+ *
+ * This function aborts the receive Legacy/Enhanced Rx FIFO process which used eDMA.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle Pointer to flexcan_edma_handle_t structure.
+ */
+void FLEXCAN_TransferAbortReceiveFifoEDMA(CAN_Type *base, flexcan_edma_handle_t *handle);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO) && FSL_FEATURE_FLEXCAN_HAS_ENHANCED_RX_FIFO)
+/*!
+ * @brief Receives the CAN FD Message from the Enhanced Rx FIFO using eDMA.
+ *
+ * This function receives the CAN FD Message using eDMA. This is a non-blocking function, which returns
+ * right away. After the CAN Message is received, the receive callback function is called.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle Pointer to flexcan_edma_handle_t structure.
+ * @param pFifoXfer FlexCAN Rx FIFO EDMA transfer structure, see #flexcan_fifo_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXCAN_RxFifoBusy Previous transfer ongoing.
+ */
+status_t FLEXCAN_TransferReceiveEnhancedFifoEDMA(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer);
+/*!
+ * @brief Gets the Enhanced Rx Fifo transfer status during a interrupt non-blocking receive.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param count Number of CAN messages receive so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+
+static inline status_t FLEXCAN_TransferGetReceiveEnhancedFifoCountEMDA(CAN_Type *base,
+ flexcan_edma_handle_t *handle,
+ size_t *count)
+{
+ return FLEXCAN_TransferGetReceiveFifoCountEMDA(base, handle, count);
+}
+#endif
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_FLEXCAN_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.c
new file mode 100644
index 0000000000..18531f7743
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio"
+#endif
+
+/*< @brief user configurable flexio handle count. */
+#define FLEXIO_HANDLE_COUNT 2
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to flexio bases for each instance. */
+FLEXIO_Type *const s_flexioBases[] = FLEXIO_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to flexio clocks for each instance. */
+const clock_ip_name_t s_flexioClocks[] = FLEXIO_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*< @brief pointer to array of FLEXIO handle. */
+static void *s_flexioHandle[FLEXIO_HANDLE_COUNT];
+
+/*< @brief pointer to array of FLEXIO IP types. */
+static void *s_flexioType[FLEXIO_HANDLE_COUNT];
+
+/*< @brief pointer to array of FLEXIO Isr. */
+static flexio_isr_t s_flexioIsr[FLEXIO_HANDLE_COUNT];
+
+/* FlexIO common IRQ Handler. */
+static void FLEXIO_CommonIRQHandler(void);
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+/*!
+ * brief Get instance number for FLEXIO module.
+ *
+ * param base FLEXIO peripheral base address.
+ */
+uint32_t FLEXIO_GetInstance(FLEXIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexioBases); instance++)
+ {
+ if (s_flexioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexioBases));
+
+ return instance;
+}
+
+/*!
+ * brief Configures the FlexIO with a FlexIO configuration. The configuration structure
+ * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig().
+ *
+ * Example
+ code
+ flexio_config_t config = {
+ .enableFlexio = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false
+ };
+ FLEXIO_Configure(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig)
+{
+ uint32_t ctrlReg = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ FLEXIO_Reset(base);
+
+ ctrlReg = base->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(userConfig->enableFlexio));
+ if (!userConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->CTRL = ctrlReg;
+}
+
+/*!
+ * brief Gates the FlexIO clock. Call this API to stop the FlexIO clock.
+ *
+ * note After calling this API, call the FLEXO_Init to use the FlexIO module.
+ *
+ * param base FlexIO peripheral base address
+ */
+void FLEXIO_Deinit(FLEXIO_Type *base)
+{
+ FLEXIO_Enable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can used directly to call the FLEXIO_Configure().
+ *
+ * Example:
+ code
+ flexio_config_t config;
+ FLEXIO_GetDefaultConfig(&config);
+ endcode
+ *
+ * param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig)
+{
+ assert(userConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(userConfig, 0, sizeof(*userConfig));
+
+ userConfig->enableFlexio = true;
+ userConfig->enableInDoze = false;
+ userConfig->enableInDebug = true;
+ userConfig->enableFastAccess = false;
+}
+
+/*!
+ * brief Resets the FlexIO module.
+ *
+ * param base FlexIO peripheral base address
+ */
+void FLEXIO_Reset(FLEXIO_Type *base)
+{
+ /*do software reset, software reset operation affect all other FLEXIO registers except CTRL*/
+ base->CTRL |= FLEXIO_CTRL_SWRST_MASK;
+ base->CTRL = 0;
+}
+
+/*!
+ * brief Gets the shifter buffer address for the DMA transfer usage.
+ *
+ * param base FlexIO peripheral base address
+ * param type Shifter type of flexio_shifter_buffer_type_t
+ * param index Shifter index
+ * return Corresponding shifter buffer index
+ */
+uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index)
+{
+ assert(index < FLEXIO_SHIFTBUF_COUNT);
+
+ uint32_t address = 0;
+
+ switch (type)
+ {
+ case kFLEXIO_ShifterBuffer:
+ address = (uint32_t) & (base->SHIFTBUF[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferBitSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBIS[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBYS[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferBitByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBBS[index]);
+ break;
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP
+ case kFLEXIO_ShifterBufferNibbleByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFNBS[index]);
+ break;
+
+#endif
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP
+ case kFLEXIO_ShifterBufferHalfWordSwapped:
+ address = (uint32_t) & (base->SHIFTBUFHWS[index]);
+ break;
+
+#endif
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP
+ case kFLEXIO_ShifterBufferNibbleSwapped:
+ address = (uint32_t) & (base->SHIFTBUFNIS[index]);
+ break;
+
+#endif
+ default:
+ address = (uint32_t) & (base->SHIFTBUF[index]);
+ break;
+ }
+ return address;
+}
+
+/*!
+ * brief Configures the shifter with the shifter configuration. The configuration structure
+ * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper
+ * mode, select which timer controls the shifter to shift, whether to generate start bit/stop
+ * bit, and the polarity of start bit and stop bit.
+ *
+ * Example
+ code
+ flexio_shifter_config_t config = {
+ .timerSelect = 0,
+ .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinPolarity = kFLEXIO_PinActiveLow,
+ .shifterMode = kFLEXIO_ShifterModeTransmit,
+ .inputSource = kFLEXIO_ShifterInputFromPin,
+ .shifterStop = kFLEXIO_ShifterStopBitHigh,
+ .shifterStart = kFLEXIO_ShifterStartBitLow
+ };
+ FLEXIO_SetShifterConfig(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param index Shifter index
+ * param shifterConfig Pointer to flexio_shifter_config_t structure
+*/
+void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig)
+{
+ base->SHIFTCFG[index] = FLEXIO_SHIFTCFG_INSRC(shifterConfig->inputSource)
+#if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH
+ | FLEXIO_SHIFTCFG_PWIDTH(shifterConfig->parallelWidth)
+#endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */
+ | FLEXIO_SHIFTCFG_SSTOP(shifterConfig->shifterStop) |
+ FLEXIO_SHIFTCFG_SSTART(shifterConfig->shifterStart);
+
+ base->SHIFTCTL[index] =
+ FLEXIO_SHIFTCTL_TIMSEL(shifterConfig->timerSelect) | FLEXIO_SHIFTCTL_TIMPOL(shifterConfig->timerPolarity) |
+ FLEXIO_SHIFTCTL_PINCFG(shifterConfig->pinConfig) | FLEXIO_SHIFTCTL_PINSEL(shifterConfig->pinSelect) |
+ FLEXIO_SHIFTCTL_PINPOL(shifterConfig->pinPolarity) | FLEXIO_SHIFTCTL_SMOD(shifterConfig->shifterMode);
+}
+
+/*!
+ * brief Configures the timer with the timer configuration. The configuration structure
+ * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper
+ * mode, select trigger source for timer and the timer pin output and the timing for timer.
+ *
+ * Example
+ code
+ flexio_timer_config_t config = {
+ .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0),
+ .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow,
+ .triggerSource = kFLEXIO_TimerTriggerSourceInternal,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinSelect = 0,
+ .pinPolarity = kFLEXIO_PinActiveHigh,
+ .timerMode = kFLEXIO_TimerModeDual8BitBaudBit,
+ .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset,
+ .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput,
+ .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput,
+ .timerDisable = kFLEXIO_TimerDisableOnTimerCompare,
+ .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh,
+ .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable,
+ .timerStart = kFLEXIO_TimerStartBitEnabled
+ };
+ FLEXIO_SetTimerConfig(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param index Timer index
+ * param timerConfig Pointer to the flexio_timer_config_t structure
+*/
+void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig)
+{
+ base->TIMCFG[index] =
+ FLEXIO_TIMCFG_TIMOUT(timerConfig->timerOutput) | FLEXIO_TIMCFG_TIMDEC(timerConfig->timerDecrement) |
+ FLEXIO_TIMCFG_TIMRST(timerConfig->timerReset) | FLEXIO_TIMCFG_TIMDIS(timerConfig->timerDisable) |
+ FLEXIO_TIMCFG_TIMENA(timerConfig->timerEnable) | FLEXIO_TIMCFG_TSTOP(timerConfig->timerStop) |
+ FLEXIO_TIMCFG_TSTART(timerConfig->timerStart);
+
+ base->TIMCMP[index] = FLEXIO_TIMCMP_CMP(timerConfig->timerCompare);
+
+ base->TIMCTL[index] = FLEXIO_TIMCTL_TRGSEL(timerConfig->triggerSelect) |
+ FLEXIO_TIMCTL_TRGPOL(timerConfig->triggerPolarity) |
+ FLEXIO_TIMCTL_TRGSRC(timerConfig->triggerSource) |
+ FLEXIO_TIMCTL_PINCFG(timerConfig->pinConfig) | FLEXIO_TIMCTL_PINSEL(timerConfig->pinSelect) |
+ FLEXIO_TIMCTL_PINPOL(timerConfig->pinPolarity) | FLEXIO_TIMCTL_TIMOD(timerConfig->timerMode);
+}
+
+/*!
+ * brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * param base Pointer to the FlexIO simulated peripheral type.
+ * param handle Pointer to the handler for FlexIO simulated peripheral.
+ * param isr FlexIO simulated peripheral interrupt handler.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr)
+{
+ assert(base != NULL);
+ assert(handle != NULL);
+ assert(isr != NULL);
+
+ uint8_t index;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioHandle[index] == NULL)
+ {
+ /* Register FLEXIO simulated driver base, handle and isr. */
+ s_flexioType[index] = base;
+ s_flexioHandle[index] = handle;
+ s_flexioIsr[index] = isr;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * param base Pointer to the FlexIO simulated peripheral type.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UnregisterHandleIRQ(void *base)
+{
+ assert(base != NULL);
+
+ uint8_t index;
+
+ /* Find the index from base address mappings. */
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioType[index] == base)
+ {
+ /* Unregister FLEXIO simulated driver handle and isr. */
+ s_flexioType[index] = NULL;
+ s_flexioHandle[index] = NULL;
+ s_flexioIsr[index] = NULL;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+static void FLEXIO_CommonIRQHandler(void)
+{
+ uint8_t index;
+
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioHandle[index] != NULL)
+ {
+ s_flexioIsr[index](s_flexioType[index], s_flexioHandle[index]);
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void FLEXIO_DriverIRQHandler(void);
+void FLEXIO_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO0_DriverIRQHandler(void);
+void FLEXIO0_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO1_DriverIRQHandler(void);
+void FLEXIO1_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void UART2_FLEXIO_DriverIRQHandler(void);
+void UART2_FLEXIO_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO2_DriverIRQHandler(void);
+void FLEXIO2_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO3_DriverIRQHandler(void);
+void FLEXIO3_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.h
new file mode 100644
index 0000000000..c851d5e5d7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio.h
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_H_
+#define _FSL_FLEXIO_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup flexio_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO driver version. */
+#define FSL_FLEXIO_DRIVER_VERSION (MAKE_VERSION(2, 1, 0))
+/*@}*/
+
+/*! @brief Calculate FlexIO timer trigger.*/
+#define FLEXIO_TIMER_TRIGGER_SEL_PININPUT(x) ((uint32_t)(x) << 1U)
+#define FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(x) (((uint32_t)(x) << 2U) | 0x1U)
+#define FLEXIO_TIMER_TRIGGER_SEL_TIMn(x) (((uint32_t)(x) << 2U) | 0x3U)
+
+/*! @brief Define time of timer trigger polarity.*/
+typedef enum _flexio_timer_trigger_polarity
+{
+ kFLEXIO_TimerTriggerPolarityActiveHigh = 0x0U, /*!< Active high. */
+ kFLEXIO_TimerTriggerPolarityActiveLow = 0x1U, /*!< Active low. */
+} flexio_timer_trigger_polarity_t;
+
+/*! @brief Define type of timer trigger source.*/
+typedef enum _flexio_timer_trigger_source
+{
+ kFLEXIO_TimerTriggerSourceExternal = 0x0U, /*!< External trigger selected. */
+ kFLEXIO_TimerTriggerSourceInternal = 0x1U, /*!< Internal trigger selected. */
+} flexio_timer_trigger_source_t;
+
+/*! @brief Define type of timer/shifter pin configuration.*/
+typedef enum _flexio_pin_config
+{
+ kFLEXIO_PinConfigOutputDisabled = 0x0U, /*!< Pin output disabled. */
+ kFLEXIO_PinConfigOpenDrainOrBidirection = 0x1U, /*!< Pin open drain or bidirectional output enable. */
+ kFLEXIO_PinConfigBidirectionOutputData = 0x2U, /*!< Pin bidirectional output data. */
+ kFLEXIO_PinConfigOutput = 0x3U, /*!< Pin output. */
+} flexio_pin_config_t;
+
+/*! @brief Definition of pin polarity.*/
+typedef enum _flexio_pin_polarity
+{
+ kFLEXIO_PinActiveHigh = 0x0U, /*!< Active high. */
+ kFLEXIO_PinActiveLow = 0x1U, /*!< Active low. */
+} flexio_pin_polarity_t;
+
+/*! @brief Define type of timer work mode.*/
+typedef enum _flexio_timer_mode
+{
+ kFLEXIO_TimerModeDisabled = 0x0U, /*!< Timer Disabled. */
+ kFLEXIO_TimerModeDual8BitBaudBit = 0x1U, /*!< Dual 8-bit counters baud/bit mode. */
+ kFLEXIO_TimerModeDual8BitPWM = 0x2U, /*!< Dual 8-bit counters PWM mode. */
+ kFLEXIO_TimerModeSingle16Bit = 0x3U, /*!< Single 16-bit counter mode. */
+} flexio_timer_mode_t;
+
+/*! @brief Define type of timer initial output or timer reset condition.*/
+typedef enum _flexio_timer_output
+{
+ kFLEXIO_TimerOutputOneNotAffectedByReset = 0x0U, /*!< Logic one when enabled and is not affected by timer
+ reset. */
+ kFLEXIO_TimerOutputZeroNotAffectedByReset = 0x1U, /*!< Logic zero when enabled and is not affected by timer
+ reset. */
+ kFLEXIO_TimerOutputOneAffectedByReset = 0x2U, /*!< Logic one when enabled and on timer reset. */
+ kFLEXIO_TimerOutputZeroAffectedByReset = 0x3U, /*!< Logic zero when enabled and on timer reset. */
+} flexio_timer_output_t;
+
+/*! @brief Define type of timer decrement.*/
+typedef enum _flexio_timer_decrement_source
+{
+ kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput = 0x0U, /*!< Decrement counter on FlexIO clock, Shift clock
+ equals Timer output. */
+ kFLEXIO_TimerDecSrcOnTriggerInputShiftTimerOutput, /*!< Decrement counter on Trigger input (both edges),
+ Shift clock equals Timer output. */
+ kFLEXIO_TimerDecSrcOnPinInputShiftPinInput, /*!< Decrement counter on Pin input (both edges),
+ Shift clock equals Pin input. */
+ kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput /*!< Decrement counter on Trigger input (both edges),
+ Shift clock equals Trigger input. */
+#if (defined(FSL_FEATURE_FLEXIO_TIMCFG_TIMDCE_FIELD_WIDTH) && (FSL_FEATURE_FLEXIO_TIMCFG_TIMDCE_FIELD_WIDTH == 3))
+ ,
+ kFLEXIO_TimerDecSrcDiv16OnFlexIOClockShiftTimerOutput, /*!< Decrement counter on FlexIO clock divided by 16,
+ Shift clock equals Timer output. */
+ kFLEXIO_TimerDecSrcDiv256OnFlexIOClockShiftTimerOutput, /*!< Decrement counter on FlexIO clock divided by 256,
+ Shift clock equals Timer output. */
+ kFLEXIO_TimerRisSrcOnPinInputShiftPinInput, /*!< Decrement counter on Pin input (rising edges),
+ Shift clock equals Pin input. */
+ kFLEXIO_TimerRisSrcOnTriggerInputShiftTriggerInput /*!< Decrement counter on Trigger input (rising edges), Shift
+ clock equals Trigger input. */
+#endif /* FSL_FEATURE_FLEXIO_TIMCFG_TIMDCE_FIELD_WIDTH */
+} flexio_timer_decrement_source_t;
+
+/*! @brief Define type of timer reset condition.*/
+typedef enum _flexio_timer_reset_condition
+{
+ kFLEXIO_TimerResetNever = 0x0U, /*!< Timer never reset. */
+ kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput = 0x2U, /*!< Timer reset on Timer Pin equal to Timer Output. */
+ kFLEXIO_TimerResetOnTimerTriggerEqualToTimerOutput = 0x3U, /*!< Timer reset on Timer Trigger equal to
+ Timer Output. */
+ kFLEXIO_TimerResetOnTimerPinRisingEdge = 0x4U, /*!< Timer reset on Timer Pin rising edge. */
+ kFLEXIO_TimerResetOnTimerTriggerRisingEdge = 0x6U, /*!< Timer reset on Trigger rising edge. */
+ kFLEXIO_TimerResetOnTimerTriggerBothEdge = 0x7U, /*!< Timer reset on Trigger rising or falling edge. */
+} flexio_timer_reset_condition_t;
+
+/*! @brief Define type of timer disable condition.*/
+typedef enum _flexio_timer_disable_condition
+{
+ kFLEXIO_TimerDisableNever = 0x0U, /*!< Timer never disabled. */
+ kFLEXIO_TimerDisableOnPreTimerDisable = 0x1U, /*!< Timer disabled on Timer N-1 disable. */
+ kFLEXIO_TimerDisableOnTimerCompare = 0x2U, /*!< Timer disabled on Timer compare. */
+ kFLEXIO_TimerDisableOnTimerCompareTriggerLow = 0x3U, /*!< Timer disabled on Timer compare and Trigger Low. */
+ kFLEXIO_TimerDisableOnPinBothEdge = 0x4U, /*!< Timer disabled on Pin rising or falling edge. */
+ kFLEXIO_TimerDisableOnPinBothEdgeTriggerHigh = 0x5U, /*!< Timer disabled on Pin rising or falling edge provided
+ Trigger is high. */
+ kFLEXIO_TimerDisableOnTriggerFallingEdge = 0x6U, /*!< Timer disabled on Trigger falling edge. */
+} flexio_timer_disable_condition_t;
+
+/*! @brief Define type of timer enable condition.*/
+typedef enum _flexio_timer_enable_condition
+{
+ kFLEXIO_TimerEnabledAlways = 0x0U, /*!< Timer always enabled. */
+ kFLEXIO_TimerEnableOnPrevTimerEnable = 0x1U, /*!< Timer enabled on Timer N-1 enable. */
+ kFLEXIO_TimerEnableOnTriggerHigh = 0x2U, /*!< Timer enabled on Trigger high. */
+ kFLEXIO_TimerEnableOnTriggerHighPinHigh = 0x3U, /*!< Timer enabled on Trigger high and Pin high. */
+ kFLEXIO_TimerEnableOnPinRisingEdge = 0x4U, /*!< Timer enabled on Pin rising edge. */
+ kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh = 0x5U, /*!< Timer enabled on Pin rising edge and Trigger high. */
+ kFLEXIO_TimerEnableOnTriggerRisingEdge = 0x6U, /*!< Timer enabled on Trigger rising edge. */
+ kFLEXIO_TimerEnableOnTriggerBothEdge = 0x7U, /*!< Timer enabled on Trigger rising or falling edge. */
+} flexio_timer_enable_condition_t;
+
+/*! @brief Define type of timer stop bit generate condition.*/
+typedef enum _flexio_timer_stop_bit_condition
+{
+ kFLEXIO_TimerStopBitDisabled = 0x0U, /*!< Stop bit disabled. */
+ kFLEXIO_TimerStopBitEnableOnTimerCompare = 0x1U, /*!< Stop bit is enabled on timer compare. */
+ kFLEXIO_TimerStopBitEnableOnTimerDisable = 0x2U, /*!< Stop bit is enabled on timer disable. */
+ kFLEXIO_TimerStopBitEnableOnTimerCompareDisable = 0x3U, /*!< Stop bit is enabled on timer compare and timer
+ disable. */
+} flexio_timer_stop_bit_condition_t;
+
+/*! @brief Define type of timer start bit generate condition.*/
+typedef enum _flexio_timer_start_bit_condition
+{
+ kFLEXIO_TimerStartBitDisabled = 0x0U, /*!< Start bit disabled. */
+ kFLEXIO_TimerStartBitEnabled = 0x1U, /*!< Start bit enabled. */
+} flexio_timer_start_bit_condition_t;
+
+/*! @brief FlexIO as PWM channel output state */
+typedef enum _flexio_timer_output_state
+{
+ kFLEXIO_PwmLow = 0, /*!< The output state of PWM channel is low */
+ kFLEXIO_PwmHigh, /*!< The output state of PWM channel is high */
+} flexio_timer_output_state_t;
+
+/*! @brief Define type of timer polarity for shifter control. */
+typedef enum _flexio_shifter_timer_polarity
+{
+ kFLEXIO_ShifterTimerPolarityOnPositive = 0x0U, /*!< Shift on positive edge of shift clock. */
+ kFLEXIO_ShifterTimerPolarityOnNegitive = 0x1U, /*!< Shift on negative edge of shift clock. */
+} flexio_shifter_timer_polarity_t;
+
+/*! @brief Define type of shifter working mode.*/
+typedef enum _flexio_shifter_mode
+{
+ kFLEXIO_ShifterDisabled = 0x0U, /*!< Shifter is disabled. */
+ kFLEXIO_ShifterModeReceive = 0x1U, /*!< Receive mode. */
+ kFLEXIO_ShifterModeTransmit = 0x2U, /*!< Transmit mode. */
+ kFLEXIO_ShifterModeMatchStore = 0x4U, /*!< Match store mode. */
+ kFLEXIO_ShifterModeMatchContinuous = 0x5U, /*!< Match continuous mode. */
+#if FSL_FEATURE_FLEXIO_HAS_STATE_MODE
+ kFLEXIO_ShifterModeState = 0x6U, /*!< SHIFTBUF contents are used for storing
+ programmable state attributes. */
+#endif /* FSL_FEATURE_FLEXIO_HAS_STATE_MODE */
+#if FSL_FEATURE_FLEXIO_HAS_LOGIC_MODE
+ kFLEXIO_ShifterModeLogic = 0x7U, /*!< SHIFTBUF contents are used for implementing
+ programmable logic look up table. */
+#endif /* FSL_FEATURE_FLEXIO_HAS_LOGIC_MODE */
+} flexio_shifter_mode_t;
+
+/*! @brief Define type of shifter input source.*/
+typedef enum _flexio_shifter_input_source
+{
+ kFLEXIO_ShifterInputFromPin = 0x0U, /*!< Shifter input from pin. */
+ kFLEXIO_ShifterInputFromNextShifterOutput = 0x1U, /*!< Shifter input from Shifter N+1. */
+} flexio_shifter_input_source_t;
+
+/*! @brief Define of STOP bit configuration.*/
+typedef enum _flexio_shifter_stop_bit
+{
+ kFLEXIO_ShifterStopBitDisable = 0x0U, /*!< Disable shifter stop bit. */
+ kFLEXIO_ShifterStopBitLow = 0x2U, /*!< Set shifter stop bit to logic low level. */
+ kFLEXIO_ShifterStopBitHigh = 0x3U, /*!< Set shifter stop bit to logic high level. */
+} flexio_shifter_stop_bit_t;
+
+/*! @brief Define type of START bit configuration.*/
+typedef enum _flexio_shifter_start_bit
+{
+ kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable = 0x0U, /*!< Disable shifter start bit, transmitter loads
+ data on enable. */
+ kFLEXIO_ShifterStartBitDisabledLoadDataOnShift = 0x1U, /*!< Disable shifter start bit, transmitter loads
+ data on first shift. */
+ kFLEXIO_ShifterStartBitLow = 0x2U, /*!< Set shifter start bit to logic low level. */
+ kFLEXIO_ShifterStartBitHigh = 0x3U, /*!< Set shifter start bit to logic high level. */
+} flexio_shifter_start_bit_t;
+
+/*! @brief Define FlexIO shifter buffer type*/
+typedef enum _flexio_shifter_buffer_type
+{
+ kFLEXIO_ShifterBuffer = 0x0U, /*!< Shifter Buffer N Register. */
+ kFLEXIO_ShifterBufferBitSwapped = 0x1U, /*!< Shifter Buffer N Bit Byte Swapped Register. */
+ kFLEXIO_ShifterBufferByteSwapped = 0x2U, /*!< Shifter Buffer N Byte Swapped Register. */
+ kFLEXIO_ShifterBufferBitByteSwapped = 0x3U, /*!< Shifter Buffer N Bit Swapped Register. */
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP
+ kFLEXIO_ShifterBufferNibbleByteSwapped = 0x4U, /*!< Shifter Buffer N Nibble Byte Swapped Register. */
+#endif /*FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP*/
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP
+ kFLEXIO_ShifterBufferHalfWordSwapped = 0x5U, /*!< Shifter Buffer N Half Word Swapped Register. */
+#endif
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP
+ kFLEXIO_ShifterBufferNibbleSwapped = 0x6U, /*!< Shifter Buffer N Nibble Swapped Register. */
+#endif
+} flexio_shifter_buffer_type_t;
+
+/*! @brief Define FlexIO user configuration structure. */
+typedef struct _flexio_config_
+{
+ bool enableFlexio; /*!< Enable/disable FlexIO module */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode */
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode */
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers, fast access requires
+ the FlexIO clock to be at least twice the frequency of the bus clock. */
+} flexio_config_t;
+
+/*! @brief Define FlexIO timer configuration structure. */
+typedef struct _flexio_timer_config
+{
+ /* Trigger. */
+ uint32_t triggerSelect; /*!< The internal trigger selection number using MACROs. */
+ flexio_timer_trigger_polarity_t triggerPolarity; /*!< Trigger Polarity. */
+ flexio_timer_trigger_source_t triggerSource; /*!< Trigger Source, internal (see 'trgsel') or external. */
+ /* Pin. */
+ flexio_pin_config_t pinConfig; /*!< Timer Pin Configuration. */
+ uint32_t pinSelect; /*!< Timer Pin number Select. */
+ flexio_pin_polarity_t pinPolarity; /*!< Timer Pin Polarity. */
+ /* Timer. */
+ flexio_timer_mode_t timerMode; /*!< Timer work Mode. */
+ flexio_timer_output_t timerOutput; /*!< Configures the initial state of the Timer Output and
+ whether it is affected by the Timer reset. */
+ flexio_timer_decrement_source_t timerDecrement; /*!< Configures the source of the Timer decrement and the
+ source of the Shift clock. */
+ flexio_timer_reset_condition_t timerReset; /*!< Configures the condition that causes the timer counter
+ (and optionally the timer output) to be reset. */
+ flexio_timer_disable_condition_t timerDisable; /*!< Configures the condition that causes the Timer to be
+ disabled and stop decrementing. */
+ flexio_timer_enable_condition_t timerEnable; /*!< Configures the condition that causes the Timer to be
+ enabled and start decrementing. */
+ flexio_timer_stop_bit_condition_t timerStop; /*!< Timer STOP Bit generation. */
+ flexio_timer_start_bit_condition_t timerStart; /*!< Timer STRAT Bit generation. */
+ uint32_t timerCompare; /*!< Value for Timer Compare N Register. */
+} flexio_timer_config_t;
+
+/*! @brief Define FlexIO shifter configuration structure. */
+typedef struct _flexio_shifter_config
+{
+ /* Timer. */
+ uint32_t timerSelect; /*!< Selects which Timer is used for controlling the
+ logic/shift register and generating the Shift clock. */
+ flexio_shifter_timer_polarity_t timerPolarity; /*!< Timer Polarity. */
+ /* Pin. */
+ flexio_pin_config_t pinConfig; /*!< Shifter Pin Configuration. */
+ uint32_t pinSelect; /*!< Shifter Pin number Select. */
+ flexio_pin_polarity_t pinPolarity; /*!< Shifter Pin Polarity. */
+ /* Shifter. */
+ flexio_shifter_mode_t shifterMode; /*!< Configures the mode of the Shifter. */
+#if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH
+ uint32_t parallelWidth; /*!< Configures the parallel width when using parallel mode.*/
+#endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */
+ flexio_shifter_input_source_t inputSource; /*!< Selects the input source for the shifter. */
+ flexio_shifter_stop_bit_t shifterStop; /*!< Shifter STOP bit. */
+ flexio_shifter_start_bit_t shifterStart; /*!< Shifter START bit. */
+} flexio_shifter_config_t;
+
+/*! @brief typedef for FlexIO simulated driver interrupt handler.*/
+typedef void (*flexio_isr_t)(void *base, void *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to flexio bases for each instance. */
+extern FLEXIO_Type *const s_flexioBases[];
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to flexio clocks for each instance. */
+extern const clock_ip_name_t s_flexioClocks[];
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name FlexIO Initialization and De-initialization
+ * @{
+ */
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can used directly to call the FLEXIO_Configure().
+ *
+ * Example:
+ @code
+ flexio_config_t config;
+ FLEXIO_GetDefaultConfig(&config);
+ @endcode
+ *
+ * @param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig);
+
+/*!
+ * @brief Configures the FlexIO with a FlexIO configuration. The configuration structure
+ * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig().
+ *
+ * Example
+ @code
+ flexio_config_t config = {
+ .enableFlexio = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false
+ };
+ FLEXIO_Configure(base, &config);
+ @endcode
+ *
+ * @param base FlexIO peripheral base address
+ * @param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig);
+
+/*!
+ * @brief Gates the FlexIO clock. Call this API to stop the FlexIO clock.
+ *
+ * @note After calling this API, call the FLEXO_Init to use the FlexIO module.
+ *
+ * @param base FlexIO peripheral base address
+ */
+void FLEXIO_Deinit(FLEXIO_Type *base);
+
+/*!
+ * @brief Get instance number for FLEXIO module.
+ *
+ * @param base FLEXIO peripheral base address.
+ */
+uint32_t FLEXIO_GetInstance(FLEXIO_Type *base);
+
+/* @} */
+
+/*!
+ * @name FlexIO Basic Operation
+ * @{
+ */
+
+/*!
+ * @brief Resets the FlexIO module.
+ *
+ * @param base FlexIO peripheral base address
+ */
+void FLEXIO_Reset(FLEXIO_Type *base);
+
+/*!
+ * @brief Enables the FlexIO module operation.
+ *
+ * @param base FlexIO peripheral base address
+ * @param enable true to enable, false to disable.
+ */
+static inline void FLEXIO_Enable(FLEXIO_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+/*!
+ * @brief Reads the input data on each of the FlexIO pins.
+ *
+ * @param base FlexIO peripheral base address
+ * @return FlexIO pin input data
+ */
+static inline uint32_t FLEXIO_ReadPinInput(FLEXIO_Type *base)
+{
+ return base->PIN;
+}
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_STATE_MODE) && FSL_FEATURE_FLEXIO_HAS_STATE_MODE
+/*!
+ * @brief Gets the current state pointer for state mode use.
+ *
+ * @param base FlexIO peripheral base address
+ * @return current State pointer
+ */
+static inline uint8_t FLEXIO_GetShifterState(FLEXIO_Type *base)
+{
+ return ((uint8_t)(base->SHIFTSTATE) & FLEXIO_SHIFTSTATE_STATE_MASK);
+}
+#endif /*FSL_FEATURE_FLEXIO_HAS_STATE_MODE*/
+
+/*!
+ * @brief Configures the shifter with the shifter configuration. The configuration structure
+ * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper
+ * mode, select which timer controls the shifter to shift, whether to generate start bit/stop
+ * bit, and the polarity of start bit and stop bit.
+ *
+ * Example
+ @code
+ flexio_shifter_config_t config = {
+ .timerSelect = 0,
+ .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinPolarity = kFLEXIO_PinActiveLow,
+ .shifterMode = kFLEXIO_ShifterModeTransmit,
+ .inputSource = kFLEXIO_ShifterInputFromPin,
+ .shifterStop = kFLEXIO_ShifterStopBitHigh,
+ .shifterStart = kFLEXIO_ShifterStartBitLow
+ };
+ FLEXIO_SetShifterConfig(base, &config);
+ @endcode
+ *
+ * @param base FlexIO peripheral base address
+ * @param index Shifter index
+ * @param shifterConfig Pointer to flexio_shifter_config_t structure
+*/
+void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig);
+/*!
+ * @brief Configures the timer with the timer configuration. The configuration structure
+ * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper
+ * mode, select trigger source for timer and the timer pin output and the timing for timer.
+ *
+ * Example
+ @code
+ flexio_timer_config_t config = {
+ .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0),
+ .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow,
+ .triggerSource = kFLEXIO_TimerTriggerSourceInternal,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinSelect = 0,
+ .pinPolarity = kFLEXIO_PinActiveHigh,
+ .timerMode = kFLEXIO_TimerModeDual8BitBaudBit,
+ .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset,
+ .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput,
+ .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput,
+ .timerDisable = kFLEXIO_TimerDisableOnTimerCompare,
+ .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh,
+ .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable,
+ .timerStart = kFLEXIO_TimerStartBitEnabled
+ };
+ FLEXIO_SetTimerConfig(base, &config);
+ @endcode
+ *
+ * @param base FlexIO peripheral base address
+ * @param index Timer index
+ * @param timerConfig Pointer to the flexio_timer_config_t structure
+*/
+void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig);
+
+/*!
+ * @brief This function set the value of the prescaler on flexio channels
+ *
+ * @param base Pointer to the FlexIO simulated peripheral type.
+ * @param clocksource Set clock value
+ */
+static inline void FLEXIO_SetClockMode(FLEXIO_Type *base, uint8_t index, flexio_timer_decrement_source_t clocksource)
+{
+ uint32_t reg = base->TIMCFG[index];
+
+ reg &= ~FLEXIO_TIMCFG_TIMDEC_MASK;
+
+ reg |= FLEXIO_TIMCFG_TIMDEC(clocksource);
+
+ base->TIMCFG[index] = reg;
+}
+
+/* @} */
+
+/*!
+ * @name FlexIO Interrupt Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables the shifter status interrupt. The interrupt generates when the corresponding SSF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter status mask which can be calculated by (1 << shifter index)
+ * @note For multiple shifter status interrupt enable, for example, two shifter status enable, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_EnableShifterStatusInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTSIEN |= mask;
+}
+
+/*!
+ * @brief Disables the shifter status interrupt. The interrupt won't generate when the corresponding SSF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter status mask which can be calculated by (1 << shifter index)
+ * @note For multiple shifter status interrupt enable, for example, two shifter status enable, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_DisableShifterStatusInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTSIEN &= ~mask;
+}
+
+/*!
+ * @brief Enables the shifter error interrupt. The interrupt generates when the corresponding SEF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter error mask which can be calculated by (1 << shifter index)
+ * @note For multiple shifter error interrupt enable, for example, two shifter error enable, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_EnableShifterErrorInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTEIEN |= mask;
+}
+
+/*!
+ * @brief Disables the shifter error interrupt. The interrupt won't generate when the corresponding SEF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter error mask which can be calculated by (1 << shifter index)
+ * @note For multiple shifter error interrupt enable, for example, two shifter error enable, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_DisableShifterErrorInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTEIEN &= ~mask;
+}
+
+/*!
+ * @brief Enables the timer status interrupt. The interrupt generates when the corresponding SSF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The timer status mask which can be calculated by (1 << timer index)
+ * @note For multiple timer status interrupt enable, for example, two timer status enable, can calculate
+ * the mask by using ((1 << timer index0) | (1 << timer index1))
+ */
+static inline void FLEXIO_EnableTimerStatusInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->TIMIEN |= mask;
+}
+
+/*!
+ * @brief Disables the timer status interrupt. The interrupt won't generate when the corresponding SSF is set.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The timer status mask which can be calculated by (1 << timer index)
+ * @note For multiple timer status interrupt enable, for example, two timer status enable, can calculate
+ * the mask by using ((1 << timer index0) | (1 << timer index1))
+ */
+static inline void FLEXIO_DisableTimerStatusInterrupts(FLEXIO_Type *base, uint32_t mask)
+{
+ base->TIMIEN &= ~mask;
+}
+
+/* @} */
+
+/*!
+ * @name FlexIO Status Operation
+ * @{
+ */
+
+/*!
+ * @brief Gets the shifter status flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @return Shifter status flags
+ */
+static inline uint32_t FLEXIO_GetShifterStatusFlags(FLEXIO_Type *base)
+{
+ return ((base->SHIFTSTAT) & FLEXIO_SHIFTSTAT_SSF_MASK);
+}
+
+/*!
+ * @brief Clears the shifter status flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter status mask which can be calculated by (1 << shifter index)
+ * @note For clearing multiple shifter status flags, for example, two shifter status flags, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_ClearShifterStatusFlags(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTSTAT = mask;
+}
+
+/*!
+ * @brief Gets the shifter error flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @return Shifter error flags
+ */
+static inline uint32_t FLEXIO_GetShifterErrorFlags(FLEXIO_Type *base)
+{
+ return ((base->SHIFTERR) & FLEXIO_SHIFTERR_SEF_MASK);
+}
+
+/*!
+ * @brief Clears the shifter error flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter error mask which can be calculated by (1 << shifter index)
+ * @note For clearing multiple shifter error flags, for example, two shifter error flags, can calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ */
+static inline void FLEXIO_ClearShifterErrorFlags(FLEXIO_Type *base, uint32_t mask)
+{
+ base->SHIFTERR = mask;
+}
+
+/*!
+ * @brief Gets the timer status flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @return Timer status flags
+ */
+static inline uint32_t FLEXIO_GetTimerStatusFlags(FLEXIO_Type *base)
+{
+ return ((base->TIMSTAT) & FLEXIO_TIMSTAT_TSF_MASK);
+}
+
+/*!
+ * @brief Clears the timer status flags.
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The timer status mask which can be calculated by (1 << timer index)
+ * @note For clearing multiple timer status flags, for example, two timer status flags, can calculate
+ * the mask by using ((1 << timer index0) | (1 << timer index1))
+ */
+static inline void FLEXIO_ClearTimerStatusFlags(FLEXIO_Type *base, uint32_t mask)
+{
+ base->TIMSTAT = mask;
+}
+
+/* @} */
+
+/*!
+ * @name FlexIO DMA Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the shifter status DMA. The DMA request generates when the corresponding SSF is set.
+ *
+ * @note For multiple shifter status DMA enables, for example, calculate
+ * the mask by using ((1 << shifter index0) | (1 << shifter index1))
+ *
+ * @param base FlexIO peripheral base address
+ * @param mask The shifter status mask which can be calculated by (1 << shifter index)
+ * @param enable True to enable, false to disable.
+ */
+static inline void FLEXIO_EnableShifterStatusDMA(FLEXIO_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->SHIFTSDEN |= mask;
+ }
+ else
+ {
+ base->SHIFTSDEN &= ~mask;
+ }
+}
+
+/*!
+ * @brief Gets the shifter buffer address for the DMA transfer usage.
+ *
+ * @param base FlexIO peripheral base address
+ * @param type Shifter type of flexio_shifter_buffer_type_t
+ * @param index Shifter index
+ * @return Corresponding shifter buffer index
+ */
+uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index);
+
+/*!
+ * @brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * @param base Pointer to the FlexIO simulated peripheral type.
+ * @param handle Pointer to the handler for FlexIO simulated peripheral.
+ * @param isr FlexIO simulated peripheral interrupt handler.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr);
+
+/*!
+ * @brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * @param base Pointer to the FlexIO simulated peripheral type.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UnregisterHandleIRQ(void *base);
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /*_FSL_FLEXIO_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera.h
new file mode 100644
index 0000000000..93612a7188
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_CAMERA_H_
+#define _FSL_FLEXIO_CAMERA_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+/*!
+ * @addtogroup flexio_camera
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO Camera driver version 2.1.3. */
+#define FSL_FLEXIO_CAMERA_DRIVER_VERSION (MAKE_VERSION(2, 1, 3))
+/*@}*/
+
+/*! @brief Define the Camera CPI interface is constantly 8-bit width. */
+#define FLEXIO_CAMERA_PARALLEL_DATA_WIDTH (8U)
+
+/*! @brief Error codes for the Camera driver. */
+enum
+{
+ kStatus_FLEXIO_CAMERA_RxBusy = MAKE_STATUS(kStatusGroup_FLEXIO_CAMERA, 0), /*!< Receiver is busy. */
+ kStatus_FLEXIO_CAMERA_RxIdle = MAKE_STATUS(kStatusGroup_FLEXIO_CAMERA, 1), /*!< Camera receiver is idle. */
+};
+
+/*! @brief Define FlexIO Camera status mask. */
+enum _flexio_camera_status_flags
+{
+ kFLEXIO_CAMERA_RxDataRegFullFlag = 0x1U, /*!< Receive buffer full flag. */
+ kFLEXIO_CAMERA_RxErrorFlag = 0x2U, /*!< Receive buffer error flag. */
+};
+
+/*!
+ * @brief Define structure of configuring the FlexIO Camera device.
+ */
+typedef struct _flexio_camera_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO module base address. */
+ uint32_t datPinStartIdx; /*!< First data pin (D0) index for flexio_camera.
+ Then the successive following FLEXIO_CAMERA_DATA_WIDTH-1 pins
+ are used as D1-D7.*/
+ uint32_t pclkPinIdx; /*!< Pixel clock pin (PCLK) index for flexio_camera. */
+ uint32_t hrefPinIdx; /*!< Horizontal sync pin (HREF) index for flexio_camera. */
+
+ uint32_t shifterStartIdx; /*!< First shifter index used for flexio_camera data FIFO. */
+ uint32_t shifterCount; /*!< The count of shifters that are used as flexio_camera data FIFO. */
+ uint32_t timerIdx; /*!< Timer index used for flexio_camera in FlexIO. */
+} FLEXIO_CAMERA_Type;
+
+/*! @brief Define FlexIO Camera user configuration structure. */
+typedef struct _flexio_camera_config
+{
+ bool enablecamera; /*!< Enable/disable FlexIO Camera TX & RX. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode*/
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode*/
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers,
+ fast access requires the FlexIO clock to be at least
+ twice the frequency of the bus clock. */
+} flexio_camera_config_t;
+
+/*! @brief Define FlexIO Camera transfer structure. */
+typedef struct _flexio_camera_transfer
+{
+ uint32_t dataAddress; /*!< Transfer buffer*/
+ uint32_t dataNum; /*!< Transfer num*/
+} flexio_camera_transfer_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and configuration
+ * @{
+ */
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, and configures the FlexIO Camera.
+ *
+ * @param base Pointer to FLEXIO_CAMERA_Type structure
+ * @param config Pointer to flexio_camera_config_t structure
+ */
+void FLEXIO_CAMERA_Init(FLEXIO_CAMERA_Type *base, const flexio_camera_config_t *config);
+
+/*!
+ * @brief Resets the FLEXIO_CAMERA shifer and timer config.
+ *
+ * @note After calling this API, call FLEXO_CAMERA_Init to use the FlexIO Camera module.
+ *
+ * @param base Pointer to FLEXIO_CAMERA_Type structure
+ */
+void FLEXIO_CAMERA_Deinit(FLEXIO_CAMERA_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO Camera. The configuration
+ * can be used directly for calling the FLEXIO_CAMERA_Init().
+ * Example:
+ @code
+ flexio_camera_config_t config;
+ FLEXIO_CAMERA_GetDefaultConfig(&userConfig);
+ @endcode
+ * @param config Pointer to the flexio_camera_config_t structure
+*/
+void FLEXIO_CAMERA_GetDefaultConfig(flexio_camera_config_t *config);
+
+/*!
+ * @brief Enables/disables the FlexIO Camera module operation.
+ *
+ * @param base Pointer to the FLEXIO_CAMERA_Type
+ * @param enable True to enable, false does not have any effect.
+ */
+static inline void FLEXIO_CAMERA_Enable(FLEXIO_CAMERA_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexIO Camera status flags.
+ *
+ * @param base Pointer to FLEXIO_CAMERA_Type structure
+ * @return FlexIO shifter status flags
+ * @arg FLEXIO_SHIFTSTAT_SSF_MASK
+ * @arg 0
+ */
+uint32_t FLEXIO_CAMERA_GetStatusFlags(FLEXIO_CAMERA_Type *base);
+
+/*!
+ * @brief Clears the receive buffer full flag manually.
+ *
+ * @param base Pointer to the device.
+ * @param mask status flag
+ * The parameter can be any combination of the following values:
+ * @arg kFLEXIO_CAMERA_RxDataRegFullFlag
+ * @arg kFLEXIO_CAMERA_RxErrorFlag
+ */
+void FLEXIO_CAMERA_ClearStatusFlags(FLEXIO_CAMERA_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Switches on the interrupt for receive buffer full event.
+ *
+ * @param base Pointer to the device.
+ */
+void FLEXIO_CAMERA_EnableInterrupt(FLEXIO_CAMERA_Type *base);
+
+/*!
+ * @brief Switches off the interrupt for receive buffer full event.
+ *
+ * @param base Pointer to the device.
+ *
+ */
+void FLEXIO_CAMERA_DisableInterrupt(FLEXIO_CAMERA_Type *base);
+
+/*! @} */
+
+/*!
+ * @name DMA support
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO Camera receive DMA.
+ *
+ * @param base Pointer to FLEXIO_CAMERA_Type structure
+ * @param enable True to enable, false to disable.
+ *
+ * The FlexIO Camera mode can't work without the DMA or eDMA support,
+ * Usually, it needs at least two DMA or eDMA channels, one for transferring data from
+ * Camera, such as 0V7670 to FlexIO buffer, another is for transferring data from FlexIO
+ * buffer to LCD.
+ *
+ */
+static inline void FLEXIO_CAMERA_EnableRxDMA(FLEXIO_CAMERA_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterStartIdx, enable);
+}
+
+/*!
+ * @brief Gets the data from the receive buffer.
+ *
+ * @param base Pointer to the device.
+ * @return data Pointer to the buffer that keeps the data with count of base->shifterCount .
+ */
+static inline uint32_t FLEXIO_CAMERA_GetRxBufferAddress(FLEXIO_CAMERA_Type *base)
+{
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBuffer, (uint8_t)base->shifterStartIdx);
+}
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*@}*/
+
+#endif /*_FSL_FLEXIO_CAMERA_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera_edma.h
new file mode 100644
index 0000000000..ff71a44cfe
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_camera_edma.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_CAMERA_EDMA_H_
+#define _FSL_FLEXIO_CAMERA_EDMA_H_
+
+#include "fsl_flexio_camera.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexio_edma_camera
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO Camera EDMA driver version 2.1.3. */
+#define FSL_FLEXIO_CAMERA_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 1, 3))
+/*@}*/
+
+/*! @brief Forward declaration of the handle typedef. */
+typedef struct _flexio_camera_edma_handle flexio_camera_edma_handle_t;
+
+/*! @brief Camera transfer callback function. */
+typedef void (*flexio_camera_edma_transfer_callback_t)(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief Camera eDMA handle
+ */
+struct _flexio_camera_edma_handle
+{
+ flexio_camera_edma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< Camera callback function parameter.*/
+ size_t rxSize; /*!< Total bytes to be received. */
+ edma_handle_t *rxEdmaHandle; /*!< The eDMA RX channel used. */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the Camera handle, which is used in transactional functions.
+ *
+ * @param base Pointer to the FLEXIO_CAMERA_Type.
+ * @param handle Pointer to flexio_camera_edma_handle_t structure.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO Camera eDMA type/handle table out of range.
+ */
+status_t FLEXIO_CAMERA_TransferCreateHandleEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ flexio_camera_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *rxEdmaHandle);
+
+/*!
+ * @brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * @param base Pointer to the FLEXIO_CAMERA_Type.
+ * @param handle Pointer to the flexio_camera_edma_handle_t structure.
+ * @param xfer Camera eDMA transfer structure, see #flexio_camera_transfer_t.
+ * @retval kStatus_Success if succeeded, others failed.
+ * @retval kStatus_CAMERA_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_CAMERA_TransferReceiveEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ flexio_camera_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the receive data which used the eDMA.
+ *
+ * This function aborts the receive data which used the eDMA.
+ *
+ * @param base Pointer to the FLEXIO_CAMERA_Type.
+ * @param handle Pointer to the flexio_camera_edma_handle_t structure.
+ */
+void FLEXIO_CAMERA_TransferAbortReceiveEDMA(FLEXIO_CAMERA_Type *base, flexio_camera_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes to be received.
+ *
+ * This function gets the number of bytes still not received.
+ *
+ * @param base Pointer to the FLEXIO_CAMERA_Type.
+ * @param handle Pointer to the flexio_camera_edma_handle_t structure.
+ * @param count Number of bytes sent so far by the non-blocking transaction.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_InvalidArgument The count parameter is invalid.
+ */
+status_t FLEXIO_CAMERA_TransferGetReceiveCountEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ size_t *count);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_CAMERA_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.c
new file mode 100644
index 0000000000..9239527c6f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.c
@@ -0,0 +1,1377 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2c_master.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2c_master"
+#endif
+
+/*! @brief FLEXIO I2C transfer state */
+enum _flexio_i2c_master_transfer_states
+{
+ kFLEXIO_I2C_Idle = 0x0U, /*!< I2C bus idle */
+ kFLEXIO_I2C_Start = 0x1U, /*!< I2C start phase */
+ kFLEXIO_I2C_SendCommand = 0x2U, /*!< Send command byte phase */
+ kFLEXIO_I2C_SendData = 0x3U, /*!< Send data transfer phase*/
+ kFLEXIO_I2C_ReceiveDataBegin = 0x4U, /*!< Receive data begin transfer phase*/
+ kFLEXIO_I2C_ReceiveData = 0x5U, /*!< Receive data transfer phase*/
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Set up master transfer, send slave address and decide the initial
+ * transfer state.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param transfer pointer to flexio_i2c_master_transfer_t structure
+ */
+static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer);
+
+/*!
+ * @brief Master run transfer state machine to perform a byte of transfer.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ * @retval kStatus_Success Successfully run state machine
+ * @retval kStatus_FLEXIO_I2C_Nak Receive Nak during transfer
+ */
+static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*!
+ * @brief Complete transfer, disable interrupt and call callback.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param status flexio transfer status
+ */
+static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ status_t status);
+
+/*!
+ * @brief introduce function FLEXIO_I2C_MasterTransferStateMachineStart.
+ * This function was deal with Initial state, i2c start state.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ */
+static void FLEXIO_I2C_MasterTransferStateMachineStart(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle);
+
+/*!
+ * @brief introduce function FLEXIO_I2C_MasterTransferStateMachineSendCommand.
+ * This function was deal with Check address only needed for transfer with subaddress .
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool FLEXIO_I2C_MasterTransferStateMachineSendCommand(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*!
+ * @brief introduce function FLEXIO_I2C_MasterTransferStateMachineSendData.
+ * This function was deal with Send command byte.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool FLEXIO_I2C_MasterTransferStateMachineSendData(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*!
+ * @brief introduce function FLEXIO_I2C_MasterTransferStateMachineReceiveDataBegin.
+ * This function was deal with Receive Data Begin.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool FLEXIO_I2C_MasterTransferStateMachineReceiveDataBegin(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*!
+ * @brief introduce function Case_kFLEXIO_I2C_ReceiveDataBegin.
+ * This function was deal with Receive Data.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ *
+ * @return default is kStatus_Success when No abnormality.
+ * @return kStatus_FLEXIO_I2C_Nak when ReceiveNakFlag is not set.
+ * @return kStatus_FLEXIO_I2C_Timeout when time out.
+ */
+static status_t FLEXIO_I2C_MasterTransferStateMachineReceiveData(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_I2C_GetInstance(FLEXIO_I2C_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer)
+{
+ bool needRestart;
+ uint32_t byteCount;
+
+ /* Init the handle member. */
+ handle->transfer.slaveAddress = xfer->slaveAddress;
+ handle->transfer.direction = xfer->direction;
+ handle->transfer.subaddress = xfer->subaddress;
+ handle->transfer.subaddressSize = xfer->subaddressSize;
+ handle->transfer.data = xfer->data;
+ handle->transfer.dataSize = xfer->dataSize;
+ handle->transfer.flags = xfer->flags;
+ handle->transferSize = xfer->dataSize;
+
+ /* Initial state, i2c start state. */
+ handle->state = (uint8_t)kFLEXIO_I2C_Start;
+
+ /* Clear all status before transfer. */
+ FLEXIO_I2C_MasterClearStatusFlags(base, (uint32_t)kFLEXIO_I2C_ReceiveNakFlag);
+
+ /* Calculate whether need to send re-start. */
+ needRestart = (handle->transfer.subaddressSize != 0U) && (handle->transfer.direction == kFLEXIO_I2C_Read);
+ handle->needRestart = needRestart;
+
+ /* Calculate total byte count in a frame. */
+ byteCount = 1U;
+
+ if (!needRestart)
+ {
+ byteCount += handle->transfer.dataSize;
+ }
+
+ if (handle->transfer.subaddressSize != 0U)
+ {
+ byteCount += handle->transfer.subaddressSize;
+ }
+
+ /* Configure data count. */
+ if (FLEXIO_I2C_MasterSetTransferCount(base, (uint16_t)byteCount) != kStatus_Success)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure timer1 disable condition. */
+ uint32_t tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[1]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPreTimerDisable);
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = tmpConfig;
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+
+ return kStatus_Success;
+}
+
+static void FLEXIO_I2C_MasterTransferStateMachineStart(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle)
+{
+ if (handle->needRestart)
+ {
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Write);
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, handle->transfer.direction);
+ }
+ if (handle->transfer.subaddressSize == 0U)
+ {
+ if (handle->transfer.direction == kFLEXIO_I2C_Write)
+ {
+ /* Next state, send data. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendData;
+ }
+ else
+ {
+ /* Next state, receive data begin. */
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveDataBegin;
+ }
+ }
+ else
+ {
+ /* Next state, send command byte. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendCommand;
+ }
+}
+
+static bool FLEXIO_I2C_MasterTransferStateMachineSendCommand(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ if (handle->transfer.subaddressSize > 0U)
+ {
+ handle->transfer.subaddressSize--;
+ FLEXIO_I2C_MasterWriteByte(base, ((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize)));
+
+ if (handle->transfer.subaddressSize == 0U)
+ {
+ /* Load re-start in advance. */
+ if (handle->transfer.direction == kFLEXIO_I2C_Read)
+ {
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return false;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterRepeatedStart(base);
+ }
+ }
+ }
+ else
+ {
+ if (handle->transfer.direction == kFLEXIO_I2C_Write)
+ {
+ /* Send first byte of data. */
+ if (handle->transfer.dataSize > 0U)
+ {
+ /* Next state, send data. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendData;
+
+ FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data);
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStop(base);
+
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return false;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ }
+ }
+ else
+ {
+ (void)FLEXIO_I2C_MasterSetTransferCount(base, (uint16_t)(handle->transfer.dataSize + 1U));
+ /* Delay at least one clock cycle so that the restart setup time is up to spec standard. */
+ SDK_DelayAtLeastUs(1000000UL / base->baudrate, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Read);
+
+ /* Next state, receive data begin. */
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveDataBegin;
+ }
+ }
+ }
+ return true;
+}
+
+static bool FLEXIO_I2C_MasterTransferStateMachineSendData(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ /* Send one byte of data. */
+ if (handle->transfer.dataSize > 0U)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data);
+
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStop(base);
+
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return false;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ }
+ }
+ return true;
+}
+
+static bool FLEXIO_I2C_MasterTransferStateMachineReceiveDataBegin(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveData;
+ /* Send nak at the last receive byte. */
+ if (handle->transfer.dataSize == 1U)
+ {
+ FLEXIO_I2C_MasterEnableAck(base, false);
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return false;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterStop(base);
+ }
+ else
+ {
+ FLEXIO_I2C_MasterEnableAck(base, true);
+ }
+ }
+ else if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ /* Read one byte of data. */
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+ }
+ else
+ {
+ ; /* Avoid MISRA 2012 rule 15.7 */
+ }
+ return true;
+}
+
+static status_t FLEXIO_I2C_MasterTransferStateMachineReceiveData(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ *handle->transfer.data = FLEXIO_I2C_MasterReadByte(base);
+ handle->transfer.data++;
+ if (0U != handle->transfer.dataSize--)
+ {
+ if (handle->transfer.dataSize == 0U)
+ {
+ FLEXIO_I2C_MasterDisableInterrupts(base, (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ /* Return nak if ReceiveNakFlag is not set */
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) == 0U)
+ {
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+
+ /* Send nak at the last receive byte. */
+ if (handle->transfer.dataSize == 1U)
+ {
+ FLEXIO_I2C_MasterEnableAck(base, false);
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterStop(base);
+ }
+ }
+ }
+ else if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ if (handle->transfer.dataSize > 1U)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+ }
+ }
+ else
+ {
+ ; /* Avoid MISRA 2012 rule 15.7 */
+ }
+ return kStatus_Success;
+}
+
+static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+ status_t status;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ /* Clear receive nak flag. */
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+
+ if ((!((handle->state == (uint8_t)kFLEXIO_I2C_SendData) && (handle->transfer.dataSize == 0U))) &&
+ (!(((handle->state == (uint8_t)kFLEXIO_I2C_ReceiveData) ||
+ (handle->state == (uint8_t)kFLEXIO_I2C_ReceiveDataBegin)) &&
+ (handle->transfer.dataSize == 1U))))
+ {
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ FLEXIO_I2C_MasterAbortStop(base);
+
+ /* Delay one clk cycle to ensure the bus is idle. */
+ SDK_DelayAtLeastUs(1000000UL / base->baudrate, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+
+ if (((statusFlags & (uint8_t)kFLEXIO_I2C_RxFullFlag) != 0U) && (handle->state != (uint8_t)kFLEXIO_I2C_ReceiveData))
+ {
+ (void)FLEXIO_I2C_MasterReadByte(base);
+ }
+
+ switch (handle->state)
+ {
+ /* Initial state, i2c start state. */
+ case (uint8_t)kFLEXIO_I2C_Start:
+ /* Send address byte first. */
+ FLEXIO_I2C_MasterTransferStateMachineStart(base, handle);
+ break;
+
+ /* Check address only needed for transfer with subaddress */
+ case (uint8_t)kFLEXIO_I2C_SendCommand:
+ if (false == FLEXIO_I2C_MasterTransferStateMachineSendCommand(base, handle, statusFlags))
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+ break;
+
+ /* Send command byte. */
+ case (uint8_t)kFLEXIO_I2C_SendData:
+ if (false == FLEXIO_I2C_MasterTransferStateMachineSendData(base, handle, statusFlags))
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+ break;
+
+ case (uint8_t)kFLEXIO_I2C_ReceiveDataBegin:
+ if (false == FLEXIO_I2C_MasterTransferStateMachineReceiveDataBegin(base, handle, statusFlags))
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+ break;
+
+ case (uint8_t)kFLEXIO_I2C_ReceiveData:
+ status = FLEXIO_I2C_MasterTransferStateMachineReceiveData(base, handle, statusFlags);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ break;
+
+ default:
+ /* Add comment to avoid MISRA violation */
+ break;
+ }
+
+ return kStatus_Success;
+}
+
+static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ status_t status)
+{
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, status, handle->userData);
+ }
+}
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+/*!
+ * brief Make sure the bus isn't already pulled down.
+ *
+ * Check the FLEXIO pin status to see whether either of SDA and SCL pin is pulled down.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * retval kStatus_Success
+ * retval kStatus_FLEXIO_I2C_Busy
+ */
+status_t FLEXIO_I2C_CheckForBusyBus(FLEXIO_I2C_Type *base)
+{
+ uint32_t mask;
+ /* If in certain loops the SDA/SCL is continuously pulled down, then return bus busy status. */
+ /* The loop count is determined by maximum CPU clock frequency */
+ for (uint32_t i = 0U; i < SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY / 600000U; ++i)
+ {
+ mask = 1UL << base->SDAPinIndex | 1UL << base->SCLPinIndex;
+ if ((FLEXIO_ReadPinInput(base->flexioBase) & mask) == mask)
+ {
+ return kStatus_Success;
+ }
+ }
+ return kStatus_FLEXIO_I2C_Busy;
+}
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, and configures the FlexIO I2C
+ * hardware configuration.
+ *
+ * Example
+ code
+ FLEXIO_I2C_Type base = {
+ .flexioBase = FLEXIO,
+ .SDAPinIndex = 0,
+ .SCLPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_i2c_master_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 100000
+ };
+ FLEXIO_I2C_MasterInit(base, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param masterConfig Pointer to flexio_i2c_master_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+ * retval kStatus_Success Initialization successful
+ * retval kStatus_InvalidArgument The source clock exceed upper range limitation
+*/
+status_t FLEXIO_I2C_MasterInit(FLEXIO_I2C_Type *base, flexio_i2c_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert((base != NULL) && (masterConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t controlVal = 0;
+ uint16_t timerDiv = 0;
+ status_t result = kStatus_Success;
+
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[2];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection;
+ shifterConfig.pinSelect = base->SDAPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[2];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDAPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitLow;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 and timer 1 for generating bit clock. */
+ /* timer 1 is used to config baudrate */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ /* Set TIMCMP = (baud rate divider / 2) - 1. */
+ timerDiv = (uint16_t)(srcClock_Hz / masterConfig->baudRate_Bps) / 2U - 1U;
+ /* Calculate and assign the actual baudrate. */
+ base->baudrate = srcClock_Hz / (2U * ((uint32_t)timerDiv + 1U));
+
+ timerConfig.timerCompare = timerDiv;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+
+ /* timer 0 is used to config total shift clock edges */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ /* Set TIMCMP when confinguring transfer bytes. */
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 4. Configure the timer 2 for controlling shifters. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerCompare;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ /* Set TIMCMP[15:0] = (number of bits x 2) - 1. */
+ timerConfig.timerCompare = 8U * 2U - 1U;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[2], &timerConfig);
+
+ /* Configure FLEXIO I2C Master. */
+ controlVal = base->flexioBase->CTRL;
+ controlVal &=
+ ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ controlVal |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster));
+ if (!masterConfig->enableInDoze)
+ {
+ controlVal |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = controlVal;
+ /* Disable internal IRQs. */
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+ return result;
+}
+
+/*!
+ * brief De-initializes the FlexIO I2C master peripheral. Calling this API Resets the FlexIO I2C master
+ * shifer and timer config, module can't work unless the FLEXIO_I2C_MasterInit is called.
+ *
+ * param base pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterDeinit(FLEXIO_I2C_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[2]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[2]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[2]] = 0;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[0]);
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[1]);
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[0]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[1]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[2]);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can be used directly for calling the FLEXIO_I2C_MasterInit().
+ *
+ * Example:
+ code
+ flexio_i2c_master_config_t config;
+ FLEXIO_I2C_MasterGetDefaultConfig(&config);
+ endcode
+ * param masterConfig Pointer to flexio_i2c_master_config_t structure.
+*/
+void FLEXIO_I2C_MasterGetDefaultConfig(flexio_i2c_master_config_t *masterConfig)
+{
+ assert(masterConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->enableInDoze = false;
+ masterConfig->enableInDebug = true;
+ masterConfig->enableFastAccess = false;
+
+ /* Default baud rate at 100kbps. */
+ masterConfig->baudRate_Bps = 100000U;
+}
+
+/*!
+ * brief Gets the FlexIO I2C master status flags.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * return Status flag, use status flag to AND #_flexio_i2c_master_status_flags can get the related status.
+ */
+
+uint32_t FLEXIO_I2C_MasterGetStatusFlags(FLEXIO_I2C_Type *base)
+{
+ uint32_t status = 0;
+
+ status =
+ ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 1U);
+ status |=
+ (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 2U);
+
+ return status;
+}
+
+/*!
+ * brief Clears the FlexIO I2C master status flags.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_I2C_RxFullFlag
+ * arg kFLEXIO_I2C_ReceiveNakFlag
+ */
+
+void FLEXIO_I2C_MasterClearStatusFlags(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Enables the FlexIO i2c master interrupt requests.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Interrupt source.
+ * Currently only one interrupt request source:
+ * arg kFLEXIO_I2C_TransferCompleteInterruptEnable
+ */
+void FLEXIO_I2C_MasterEnableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO I2C master interrupt requests.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_I2C_MasterDisableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sets the FlexIO I2C master transfer baudrate.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param baudRate_Bps the baud rate value in HZ
+ * param srcClock_Hz source clock in HZ
+ */
+void FLEXIO_I2C_MasterSetBaudRate(FLEXIO_I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ uint16_t timerDiv = 0;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Set TIMCMP = (baud rate divider / 2) - 1.*/
+ timerDiv = (uint16_t)((srcClock_Hz / baudRate_Bps) / 2U - 1U);
+
+ flexioBase->TIMCMP[base->timerIndex[1]] = timerDiv;
+
+ /* Calculate and assign the actual baudrate. */
+ base->baudrate = srcClock_Hz / (2U * ((uint32_t)timerDiv + 1U));
+}
+
+/*!
+ * brief Sets the number of bytes to be transferred from a start signal to a stop signal.
+ *
+ * note Call this API before a transfer begins because the timer generates a number of clocks according
+ * to the number of bytes that need to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param count Number of bytes need to be transferred from a start signal to a re-start/stop signal
+ * retval kStatus_Success Successfully configured the count.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ */
+status_t FLEXIO_I2C_MasterSetTransferCount(FLEXIO_I2C_Type *base, uint16_t count)
+{
+ /* Calculate whether the transfer count is larger than the max value compare register can achieve */
+ if (count > ((0xFFFFUL - 1UL) / (16UL + 1UL + 1UL)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t timerConfig = 0U;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ flexioBase->TIMCMP[base->timerIndex[0]] = (uint32_t)count * 18U + 1U;
+ timerConfig = flexioBase->TIMCFG[base->timerIndex[0]];
+ timerConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ timerConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare);
+ flexioBase->TIMCFG[base->timerIndex[0]] = timerConfig;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sends START + 7-bit address to the bus.
+ *
+ * note This API should be called when the transfer configuration is ready to send a START signal
+ * and 7-bit address to the bus. This is a non-blocking API, which returns directly after the address
+ * is put into the data register but the address transfer is not finished on the bus. Ensure that
+ * the kFLEXIO_I2C_RxFullFlag status is asserted before calling this API.
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param address 7-bit address.
+ * param direction transfer direction.
+ * This parameter is one of the values in flexio_i2c_direction_t:
+ * arg kFLEXIO_I2C_Write: Transmit
+ * arg kFLEXIO_I2C_Read: Receive
+ */
+
+void FLEXIO_I2C_MasterStart(FLEXIO_I2C_Type *base, uint8_t address, flexio_i2c_direction_t direction)
+{
+ uint32_t data;
+
+ data = ((uint32_t)address) << 1U | ((direction == kFLEXIO_I2C_Read) ? 1U : 0U);
+
+ FLEXIO_I2C_MasterWriteByte(base, data);
+}
+
+/*!
+ * brief Sends the repeated start signal on the bus.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterRepeatedStart(FLEXIO_I2C_Type *base)
+{
+ /* Prepare for RESTART condition, no stop.*/
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+}
+
+/*!
+ * brief Sends the stop signal on the bus.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterStop(FLEXIO_I2C_Type *base)
+{
+ /* Prepare normal stop. */
+ (void)FLEXIO_I2C_MasterSetTransferCount(base, 0x0U);
+ FLEXIO_I2C_MasterWriteByte(base, 0x0U);
+}
+
+/*!
+ * brief Sends the stop signal when transfer is still on-going.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterAbortStop(FLEXIO_I2C_Type *base)
+{
+ uint32_t tmpConfig;
+
+ /* Prepare abort stop. */
+ /* Disable timer 0. */
+ tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[0]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPinBothEdge);
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = tmpConfig;
+
+ /* Disable timer 1. */
+ tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[1]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPinBothEdge);
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = tmpConfig;
+}
+
+/*!
+ * brief Configures the sent ACK/NAK for the following byte.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param enable True to configure send ACK, false configure to send NAK.
+ */
+void FLEXIO_I2C_MasterEnableAck(FLEXIO_I2C_Type *base, bool enable)
+{
+ uint32_t tmpConfig = 0;
+
+ tmpConfig = base->flexioBase->SHIFTCFG[base->shifterIndex[0]];
+ tmpConfig &= ~FLEXIO_SHIFTCFG_SSTOP_MASK;
+ if (enable)
+ {
+ tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitLow);
+ }
+ else
+ {
+ tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitHigh);
+ }
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = tmpConfig;
+}
+
+/*!
+ * brief Sends a buffer of data in bytes.
+ *
+ * note This function blocks via polling until all bytes have been sent.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param txBuff The data bytes to send.
+ * param txSize The number of data bytes to send.
+ * retval kStatus_Success Successfully write data.
+ * retval kStatus_FLEXIO_I2C_Nak Receive NAK during writing data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterWriteBlocking(FLEXIO_I2C_Type *base, const uint8_t *txBuff, uint8_t txSize)
+{
+ assert(txBuff != NULL);
+ assert(txSize != 0U);
+
+ uint32_t status;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ while (0U != txSize--)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, *txBuff++);
+
+ /* Wait until data transfer complete. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == ((status = FLEXIO_I2C_MasterGetStatusFlags(base)) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == ((status = FLEXIO_I2C_MasterGetStatusFlags(base)) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+
+ if ((status & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks via polling until all bytes have been received.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param rxBuff The buffer to store the received bytes.
+ * param rxSize The number of data bytes to be received.
+ * retval kStatus_Success Successfully read data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterReadBlocking(FLEXIO_I2C_Type *base, uint8_t *rxBuff, uint8_t rxSize)
+{
+ assert(rxBuff != NULL);
+ assert(rxSize != 0U);
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ while (0U != rxSize--)
+ {
+ /* Wait until data transfer complete. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ *rxBuff++ = FLEXIO_I2C_MasterReadByte(base);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a master polling transfer on the I2C bus.
+ *
+ * note The API does not return until the transfer succeeds or fails due
+ * to receiving NAK.
+ *
+ * param base pointer to FLEXIO_I2C_Type structure.
+ * param xfer pointer to flexio_i2c_master_transfer_t structure.
+ * return status of status_t.
+ */
+status_t FLEXIO_I2C_MasterTransferBlocking(FLEXIO_I2C_Type *base, flexio_i2c_master_transfer_t *xfer)
+{
+ assert(xfer != NULL);
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+ /* Return an error if the bus is already in use not by us.*/
+ status_t status = FLEXIO_I2C_CheckForBusyBus(base);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+ flexio_i2c_master_handle_t tmpHandle;
+ uint32_t statusFlags;
+ status_t result = kStatus_Success;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Zero the handle. */
+ (void)memset(&tmpHandle, 0, sizeof(tmpHandle));
+
+ /* Set up transfer machine. */
+ result = FLEXIO_I2C_MasterTransferInitStateMachine(base, &tmpHandle, xfer);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ do
+ {
+ /* Wait either tx empty or rx full flag is asserted. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == ((statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base)) &
+ ((uint32_t)kFLEXIO_I2C_TxEmptyFlag | (uint32_t)kFLEXIO_I2C_RxFullFlag))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == ((statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base)) &
+ ((uint32_t)kFLEXIO_I2C_TxEmptyFlag | (uint32_t)kFLEXIO_I2C_RxFullFlag)))
+ {
+ }
+#endif
+ FLEXIO_ClearTimerStatusFlags(base->flexioBase, ((1UL << base->timerIndex[0]) | (1UL << base->timerIndex[1])));
+ result = FLEXIO_I2C_MasterTransferRunStateMachine(base, &tmpHandle, statusFlags);
+
+ } while ((tmpHandle.state != (uint8_t)kFLEXIO_I2C_Idle) && (result == kStatus_Success));
+
+ /* Timer disable on timer compare, wait until bit clock TSF set, which means timer disable and stop has been sent.
+ */
+ while (0U == (FLEXIO_GetTimerStatusFlags(base->flexioBase) & (1UL << base->timerIndex[1])))
+ {
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the I2C handle which is used in transactional functions.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param handle Pointer to flexio_i2c_master_handle_t structure to store the transfer state.
+ * param callback Pointer to user callback function.
+ * param userData User param passed to the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/isr table out of range.
+ */
+status_t FLEXIO_I2C_MasterTransferCreateHandle(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Clear pending NVIC IRQ before enable NVIC IRQ. */
+ NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_I2C_GetInstance(base)]);
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2C_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2C_MasterTransferHandleIRQ);
+}
+
+/*!
+ * brief Performs a master interrupt non-blocking transfer on the I2C bus.
+ *
+ * note The API returns immediately after the transfer initiates.
+ * Call FLEXIO_I2C_MasterTransferGetCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXIO_I2C_Busy, the transfer
+ * is finished.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * param xfer pointer to flexio_i2c_master_transfer_t structure
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_FLEXIO_I2C_Busy FlexIO I2C is not idle, is running another transfer.
+ */
+status_t FLEXIO_I2C_MasterTransferNonBlocking(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ status_t result = kStatus_Success;
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+ /* Return an error if the bus is already in use not by us.*/
+ result = FLEXIO_I2C_CheckForBusyBus(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+ if (handle->state != (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ return kStatus_FLEXIO_I2C_Busy;
+ }
+ else
+ {
+ /* Set up transfer machine. */
+ result = FLEXIO_I2C_MasterTransferInitStateMachine(base, handle, xfer);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* Enable both tx empty and rxfull interrupt. */
+ FLEXIO_I2C_MasterEnableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief Aborts an interrupt non-blocking transfer early.
+ *
+ * note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2C_MasterTransferAbort(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupts. */
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ /* Reset to idle state. */
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+}
+
+/*!
+ * brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_I2C_MasterTransferGetCount(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle, size_t *count)
+{
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state == (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->transferSize - handle->transfer.dataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Master interrupt handler.
+ *
+ * param i2cType Pointer to FLEXIO_I2C_Type structure
+ * param i2cHandle Pointer to flexio_i2c_master_transfer_t structure
+ */
+void FLEXIO_I2C_MasterTransferHandleIRQ(void *i2cType, void *i2cHandle)
+{
+ FLEXIO_I2C_Type *base = (FLEXIO_I2C_Type *)i2cType;
+ flexio_i2c_master_handle_t *handle = (flexio_i2c_master_handle_t *)i2cHandle;
+ uint32_t statusFlags;
+ status_t result;
+
+ statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base);
+
+ result = FLEXIO_I2C_MasterTransferRunStateMachine(base, handle, statusFlags);
+
+ if (handle->state == (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ FLEXIO_I2C_MasterTransferComplete(base, handle, result);
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.h
new file mode 100644
index 0000000000..8bf4707c8b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2c_master.h
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_I2C_MASTER_H_
+#define _FSL_FLEXIO_I2C_MASTER_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+
+/*!
+ * @addtogroup flexio_i2c_master
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_FLEXIO_I2C_MASTER_DRIVER_VERSION (MAKE_VERSION(2, 5, 0))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef I2C_RETRY_TIMES
+#define I2C_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief FlexIO I2C transfer status*/
+enum
+{
+ kStatus_FLEXIO_I2C_Busy = MAKE_STATUS(kStatusGroup_FLEXIO_I2C, 0), /*!< I2C is busy doing transfer. */
+ kStatus_FLEXIO_I2C_Idle = MAKE_STATUS(kStatusGroup_FLEXIO_I2C, 1), /*!< I2C is busy doing transfer. */
+ kStatus_FLEXIO_I2C_Nak = MAKE_STATUS(kStatusGroup_FLEXIO_I2C, 2), /*!< NAK received during transfer. */
+ kStatus_FLEXIO_I2C_Timeout = MAKE_STATUS(kStatusGroup_FLEXIO_I2C, 3), /*!< Timeout polling status flags. */
+};
+
+/*! @brief Define FlexIO I2C master interrupt mask. */
+enum _flexio_i2c_master_interrupt
+{
+ kFLEXIO_I2C_TxEmptyInterruptEnable = 0x1U, /*!< Tx buffer empty interrupt enable. */
+ kFLEXIO_I2C_RxFullInterruptEnable = 0x2U, /*!< Rx buffer full interrupt enable. */
+};
+
+/*! @brief Define FlexIO I2C master status mask. */
+enum _flexio_i2c_master_status_flags
+{
+ kFLEXIO_I2C_TxEmptyFlag = 0x1U, /*!< Tx shifter empty flag. */
+ kFLEXIO_I2C_RxFullFlag = 0x2U, /*!< Rx shifter full/Transfer complete flag. */
+ kFLEXIO_I2C_ReceiveNakFlag = 0x4U, /*!< Receive NAK flag. */
+};
+
+/*! @brief Direction of master transfer.*/
+typedef enum _flexio_i2c_direction
+{
+ kFLEXIO_I2C_Write = 0x0U, /*!< Master send to slave. */
+ kFLEXIO_I2C_Read = 0x1U, /*!< Master receive from slave. */
+} flexio_i2c_direction_t;
+
+/*! @brief Define FlexIO I2C master access structure typedef. */
+typedef struct _flexio_i2c_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO base pointer. */
+ uint8_t SDAPinIndex; /*!< Pin select for I2C SDA. */
+ uint8_t SCLPinIndex; /*!< Pin select for I2C SCL. */
+ uint8_t shifterIndex[2]; /*!< Shifter index used in FlexIO I2C. */
+ uint8_t timerIndex[3]; /*!< Timer index used in FlexIO I2C. */
+ uint32_t baudrate; /*!< Master transfer baudrate, used to calculate delay time. */
+} FLEXIO_I2C_Type;
+
+/*! @brief Define FlexIO I2C master user configuration structure. */
+typedef struct _flexio_i2c_master_config
+{
+ bool enableMaster; /*!< Enables the FlexIO I2C peripheral at initialization time. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode. */
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode. */
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers, fast access requires
+ the FlexIO clock to be at least twice the frequency of the bus clock. */
+ uint32_t baudRate_Bps; /*!< Baud rate in Bps. */
+} flexio_i2c_master_config_t;
+
+/*! @brief Define FlexIO I2C master transfer structure. */
+typedef struct _flexio_i2c_master_transfer
+{
+ uint32_t flags; /*!< Transfer flag which controls the transfer, reserved for FlexIO I2C. */
+ uint8_t slaveAddress; /*!< 7-bit slave address. */
+ flexio_i2c_direction_t direction; /*!< Transfer direction, read or write. */
+ uint32_t subaddress; /*!< Sub address. Transferred MSB first. */
+ uint8_t subaddressSize; /*!< Size of command buffer. */
+ uint8_t volatile *data; /*!< Transfer buffer. */
+ volatile size_t dataSize; /*!< Transfer size. */
+} flexio_i2c_master_transfer_t;
+
+/*! @brief FlexIO I2C master handle typedef. */
+typedef struct _flexio_i2c_master_handle flexio_i2c_master_handle_t;
+
+/*! @brief FlexIO I2C master transfer callback typedef. */
+typedef void (*flexio_i2c_master_transfer_callback_t)(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Define FlexIO I2C master handle structure. */
+struct _flexio_i2c_master_handle
+{
+ flexio_i2c_master_transfer_t transfer; /*!< FlexIO I2C master transfer copy. */
+ size_t transferSize; /*!< Total bytes to be transferred. */
+ uint8_t state; /*!< Transfer state maintained during transfer. */
+ flexio_i2c_master_transfer_callback_t completionCallback; /*!< Callback function called at transfer event. */
+ /*!< Callback function called at transfer event. */
+ void *userData; /*!< Callback parameter passed to callback function. */
+ bool needRestart; /*!< Whether master needs to send re-start signal. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+/*!
+ * @brief Make sure the bus isn't already pulled down.
+ *
+ * Check the FLEXIO pin status to see whether either of SDA and SCL pin is pulled down.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure..
+ * @retval kStatus_Success
+ * @retval kStatus_FLEXIO_I2C_Busy
+ */
+status_t FLEXIO_I2C_CheckForBusyBus(FLEXIO_I2C_Type *base);
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, and configures the FlexIO I2C
+ * hardware configuration.
+ *
+ * Example
+ @code
+ FLEXIO_I2C_Type base = {
+ .flexioBase = FLEXIO,
+ .SDAPinIndex = 0,
+ .SCLPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_i2c_master_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 100000
+ };
+ FLEXIO_I2C_MasterInit(base, &config, srcClock_Hz);
+ @endcode
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param masterConfig Pointer to flexio_i2c_master_config_t structure.
+ * @param srcClock_Hz FlexIO source clock in Hz.
+ * @retval kStatus_Success Initialization successful
+ * @retval kStatus_InvalidArgument The source clock exceed upper range limitation
+*/
+status_t FLEXIO_I2C_MasterInit(FLEXIO_I2C_Type *base, flexio_i2c_master_config_t *masterConfig, uint32_t srcClock_Hz);
+
+/*!
+ * @brief De-initializes the FlexIO I2C master peripheral. Calling this API Resets the FlexIO I2C master
+ * shifer and timer config, module can't work unless the FLEXIO_I2C_MasterInit is called.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterDeinit(FLEXIO_I2C_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can be used directly for calling the FLEXIO_I2C_MasterInit().
+ *
+ * Example:
+ @code
+ flexio_i2c_master_config_t config;
+ FLEXIO_I2C_MasterGetDefaultConfig(&config);
+ @endcode
+ * @param masterConfig Pointer to flexio_i2c_master_config_t structure.
+*/
+void FLEXIO_I2C_MasterGetDefaultConfig(flexio_i2c_master_config_t *masterConfig);
+
+/*!
+ * @brief Enables/disables the FlexIO module operation.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param enable Pass true to enable module, false does not have any effect.
+ */
+static inline void FLEXIO_I2C_MasterEnable(FLEXIO_I2C_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexIO I2C master status flags.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure
+ * @return Status flag, use status flag to AND #_flexio_i2c_master_status_flags can get the related status.
+ */
+
+uint32_t FLEXIO_I2C_MasterGetStatusFlags(FLEXIO_I2C_Type *base);
+
+/*!
+ * @brief Clears the FlexIO I2C master status flags.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * @arg kFLEXIO_I2C_RxFullFlag
+ * @arg kFLEXIO_I2C_ReceiveNakFlag
+ */
+
+void FLEXIO_I2C_MasterClearStatusFlags(FLEXIO_I2C_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the FlexIO i2c master interrupt requests.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param mask Interrupt source.
+ * Currently only one interrupt request source:
+ * @arg kFLEXIO_I2C_TransferCompleteInterruptEnable
+ */
+void FLEXIO_I2C_MasterEnableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the FlexIO I2C master interrupt requests.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param mask Interrupt source.
+ */
+void FLEXIO_I2C_MasterDisableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Sets the FlexIO I2C master transfer baudrate.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure
+ * @param baudRate_Bps the baud rate value in HZ
+ * @param srcClock_Hz source clock in HZ
+ */
+void FLEXIO_I2C_MasterSetBaudRate(FLEXIO_I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Sends START + 7-bit address to the bus.
+ *
+ * @note This API should be called when the transfer configuration is ready to send a START signal
+ * and 7-bit address to the bus. This is a non-blocking API, which returns directly after the address
+ * is put into the data register but the address transfer is not finished on the bus. Ensure that
+ * the kFLEXIO_I2C_RxFullFlag status is asserted before calling this API.
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param address 7-bit address.
+ * @param direction transfer direction.
+ * This parameter is one of the values in flexio_i2c_direction_t:
+ * @arg kFLEXIO_I2C_Write: Transmit
+ * @arg kFLEXIO_I2C_Read: Receive
+ */
+
+void FLEXIO_I2C_MasterStart(FLEXIO_I2C_Type *base, uint8_t address, flexio_i2c_direction_t direction);
+
+/*!
+ * @brief Sends the stop signal on the bus.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterStop(FLEXIO_I2C_Type *base);
+
+/*!
+ * @brief Sends the repeated start signal on the bus.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterRepeatedStart(FLEXIO_I2C_Type *base);
+
+/*!
+ * @brief Sends the stop signal when transfer is still on-going.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterAbortStop(FLEXIO_I2C_Type *base);
+
+/*!
+ * @brief Configures the sent ACK/NAK for the following byte.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param enable True to configure send ACK, false configure to send NAK.
+ */
+void FLEXIO_I2C_MasterEnableAck(FLEXIO_I2C_Type *base, bool enable);
+
+/*!
+ * @brief Sets the number of bytes to be transferred from a start signal to a stop signal.
+ *
+ * @note Call this API before a transfer begins because the timer generates a number of clocks according
+ * to the number of bytes that need to be transferred.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param count Number of bytes need to be transferred from a start signal to a re-start/stop signal
+ * @retval kStatus_Success Successfully configured the count.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ */
+status_t FLEXIO_I2C_MasterSetTransferCount(FLEXIO_I2C_Type *base, uint16_t count);
+
+/*!
+ * @brief Writes one byte of data to the I2C bus.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is put into the
+ * data register but the data transfer is not finished on the bus. Ensure that
+ * the TxEmptyFlag is asserted before calling this API.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param data a byte of data.
+ */
+static inline void FLEXIO_I2C_MasterWriteByte(FLEXIO_I2C_Type *base, uint32_t data)
+{
+ base->flexioBase->SHIFTBUFBBS[base->shifterIndex[0]] = data;
+}
+
+/*!
+ * @brief Reads one byte of data from the I2C bus.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is read from the
+ * data register. Ensure that the data is ready in the register.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @return data byte read.
+ */
+static inline uint8_t FLEXIO_I2C_MasterReadByte(FLEXIO_I2C_Type *base)
+{
+ return (uint8_t)(base->flexioBase->SHIFTBUFBIS[base->shifterIndex[1]]);
+}
+
+/*!
+ * @brief Sends a buffer of data in bytes.
+ *
+ * @note This function blocks via polling until all bytes have been sent.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param txBuff The data bytes to send.
+ * @param txSize The number of data bytes to send.
+ * @retval kStatus_Success Successfully write data.
+ * @retval kStatus_FLEXIO_I2C_Nak Receive NAK during writing data.
+ * @retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterWriteBlocking(FLEXIO_I2C_Type *base, const uint8_t *txBuff, uint8_t txSize);
+
+/*!
+ * @brief Receives a buffer of bytes.
+ *
+ * @note This function blocks via polling until all bytes have been received.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param rxBuff The buffer to store the received bytes.
+ * @param rxSize The number of data bytes to be received.
+ * @retval kStatus_Success Successfully read data.
+ * @retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterReadBlocking(FLEXIO_I2C_Type *base, uint8_t *rxBuff, uint8_t rxSize);
+
+/*!
+ * @brief Performs a master polling transfer on the I2C bus.
+ *
+ * @note The API does not return until the transfer succeeds or fails due
+ * to receiving NAK.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure.
+ * @param xfer pointer to flexio_i2c_master_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t FLEXIO_I2C_MasterTransferBlocking(FLEXIO_I2C_Type *base, flexio_i2c_master_transfer_t *xfer);
+/*@}*/
+
+/*Transactional APIs*/
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the I2C handle which is used in transactional functions.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param handle Pointer to flexio_i2c_master_handle_t structure to store the transfer state.
+ * @param callback Pointer to user callback function.
+ * @param userData User param passed to the callback function.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/isr table out of range.
+ */
+status_t FLEXIO_I2C_MasterTransferCreateHandle(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a master interrupt non-blocking transfer on the I2C bus.
+ *
+ * @note The API returns immediately after the transfer initiates.
+ * Call FLEXIO_I2C_MasterTransferGetCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXIO_I2C_Busy, the transfer
+ * is finished.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure
+ * @param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param xfer pointer to flexio_i2c_master_transfer_t structure
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_FLEXIO_I2C_Busy FlexIO I2C is not idle, is running another transfer.
+ */
+status_t FLEXIO_I2C_MasterTransferNonBlocking(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer);
+
+/*!
+ * @brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure.
+ * @param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_I2C_MasterTransferGetCount(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts an interrupt non-blocking transfer early.
+ *
+ * @note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base Pointer to FLEXIO_I2C_Type structure
+ * @param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2C_MasterTransferAbort(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle);
+
+/*!
+ * @brief Master interrupt handler.
+ *
+ * @param i2cType Pointer to FLEXIO_I2C_Type structure
+ * @param i2cHandle Pointer to flexio_i2c_master_transfer_t structure
+ */
+void FLEXIO_I2C_MasterTransferHandleIRQ(void *i2cType, void *i2cHandle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /*_FSL_FLEXIO_I2C_MASTER_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.c
new file mode 100644
index 0000000000..087e0d691d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2s.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2s"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*!@brief _sai_transfer_state*/
+enum
+{
+ kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO_I2S is busy */
+ kFLEXIO_I2S_Idle, /*!< Transfer is done. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Receive a piece of data in non-blocking way.
+ *
+ * @param base FLEXIO I2S base pointer
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size);
+
+/*!
+ * @brief sends a piece of data in non-blocking way.
+ *
+ * @param base FLEXIO I2S base pointer
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+ uint32_t temp = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ temp = (uint32_t)(*txData);
+ data |= (temp << (8U * j));
+ txData++;
+ }
+ base->flexioBase->SHIFTBUFBIS[base->txShifterIndex] = data << (32U - bitWidth);
+ data = 0;
+ }
+}
+
+static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ data = (base->flexioBase->SHIFTBUFBIS[base->rxShifterIndex]);
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ *rxData = (uint8_t)((data >> (8U * j)) & 0xFFU);
+ rxData++;
+ }
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO I2S.
+ *
+ * This API configures FlexIO pins and shifter to I2S and configures the FlexIO I2S with a configuration structure.
+ * The configuration structure can be filled by the user, or be set with default values by
+ * FLEXIO_I2S_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the FlexIO I2S driver. Otherwise, any access to the FlexIO I2S module can cause hard fault
+ * because the clock is not enabled.
+ *
+ * param base FlexIO I2S base pointer
+ * param config FlexIO I2S configure structure.
+ */
+void FLEXIO_I2S_Init(FLEXIO_I2S_Type *base, const flexio_i2s_config_t *config)
+{
+ assert((base != NULL) && (config != NULL));
+
+ flexio_shifter_config_t shifterConfig = {0};
+ flexio_timer_config_t timerConfig = {0};
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2S_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* reset Flexio */
+ FLEXIO_Reset(base->flexioBase);
+
+ /* Set shifter for I2S Tx data */
+ shifterConfig.timerSelect = base->bclkTimerIndex;
+ shifterConfig.pinSelect = base->txPinIndex;
+ shifterConfig.timerPolarity = config->txTimerPolarity;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinPolarity = config->txPinPolarity;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+ else
+ {
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->txShifterIndex, &shifterConfig);
+
+ /* Set shifter for I2S Rx Data */
+ shifterConfig.timerSelect = base->bclkTimerIndex;
+ shifterConfig.pinSelect = base->rxPinIndex;
+ shifterConfig.timerPolarity = config->rxTimerPolarity;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinPolarity = config->rxPinPolarity;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->rxShifterIndex, &shifterConfig);
+
+ /* Set Timer to I2S frame sync */
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->txPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->fsPinIndex;
+ timerConfig.pinPolarity = config->fsPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ else
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->bclkPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->fsPinIndex;
+ timerConfig.pinPolarity = config->fsPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdge;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ FLEXIO_SetTimerConfig(base->flexioBase, base->fsTimerIndex, &timerConfig);
+
+ /* Set Timer to I2S bit clock */
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinSelect = base->bclkPinIndex;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinPolarity = config->bclkPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ else
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->fsTimerIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinSelect = base->bclkPinIndex;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinPolarity = config->bclkPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompareTriggerLow;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ FLEXIO_SetTimerConfig(base->flexioBase, base->bclkTimerIndex, &timerConfig);
+
+ /* If enable flexio I2S */
+ if (config->enableI2S)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+ else
+ {
+ base->flexioBase->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*!
+ * brief Sets the FlexIO I2S configuration structure to default values.
+ *
+ * The purpose of this API is to get the configuration structure initialized for use in FLEXIO_I2S_Init().
+ * Users may use the initialized structure unchanged in FLEXIO_I2S_Init() or modify
+ * some fields of the structure before calling FLEXIO_I2S_Init().
+ *
+ * param config pointer to master configuration structure
+ */
+void FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->masterSlave = kFLEXIO_I2S_Master;
+ config->enableI2S = true;
+ config->txPinPolarity = kFLEXIO_PinActiveHigh;
+ config->rxPinPolarity = kFLEXIO_PinActiveHigh;
+ config->bclkPinPolarity = kFLEXIO_PinActiveHigh;
+ config->fsPinPolarity = kFLEXIO_PinActiveLow;
+ config->txTimerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ config->rxTimerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+}
+
+/*!
+ * brief De-initializes the FlexIO I2S.
+ *
+ * Calling this API resets the FlexIO I2S shifter and timer config. After calling this API,
+ * call the FLEXO_I2S_Init to use the FlexIO I2S module.
+ *
+ * param base FlexIO I2S base pointer
+ */
+void FLEXIO_I2S_Deinit(FLEXIO_I2S_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->txShifterIndex] = 0;
+ base->flexioBase->SHIFTCTL[base->txShifterIndex] = 0;
+ base->flexioBase->SHIFTCFG[base->rxShifterIndex] = 0;
+ base->flexioBase->SHIFTCTL[base->rxShifterIndex] = 0;
+ base->flexioBase->TIMCFG[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCTL[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCFG[base->bclkTimerIndex] = 0;
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = 0;
+ base->flexioBase->TIMCTL[base->bclkTimerIndex] = 0;
+}
+
+/*!
+ * brief Enables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param mask interrupt source
+ */
+void FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
+ }
+}
+
+/*!
+ * brief Gets the FlexIO I2S status flags.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * return Status flag, which are ORed by the enumerators in the _flexio_i2s_status_flags.
+ */
+uint32_t FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type *base)
+{
+ uint32_t status = 0;
+ status = ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->txShifterIndex)) >> base->txShifterIndex);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) >> (base->rxShifterIndex))
+ << 1U);
+ return status;
+}
+
+/*!
+ * brief Disables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base pointer to FLEXIO_I2S_Type structure
+ * param mask interrupt source
+ */
+void FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
+ }
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format in master mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param format Pointer to FlexIO I2S audio data format structure.
+ * param srcClock_Hz I2S master clock source frequency in Hz.
+ */
+void FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format, uint32_t srcClock_Hz)
+{
+ uint32_t timDiv = srcClock_Hz / (format->sampleRate_Hz * format->bitWidth * 2U);
+ uint32_t bclkDiv = 0;
+
+ /* Shall keep bclk and fs div an integer */
+ if ((timDiv % 2UL) != 0UL)
+ {
+ timDiv += 1U;
+ }
+ /* Set Frame sync timer cmp */
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * timDiv - 1U);
+
+ /* Set bit clock timer cmp */
+ bclkDiv = ((timDiv / 2U - 1U) | ((format->bitWidth * 2UL - 1UL) << 8U));
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(bclkDiv);
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format in slave mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param format Pointer to FlexIO I2S audio data format structure.
+ */
+void FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format)
+{
+ /* Set Frame sync timer cmp */
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 4UL - 3UL);
+
+ /* Set bit clock timer cmp */
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 2UL - 1UL);
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks via polling until data is ready to be sent.
+ *
+ * param base FlexIO I2S base pointer.
+ * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * param txData Pointer to the data to be written.
+ * param size Bytes to be written.
+ * retval kStatus_Success Successfully write data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+#if I2S_RETRY_TIMES
+ uint32_t waitTimes = I2S_RETRY_TIMES;
+#endif
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ /* Wait until it can write data */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) &&
+ (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
+ {
+ }
+#endif
+
+ FLEXIO_I2S_WriteNonBlocking(base, bitWidth, txData, bytesPerWord);
+ txData = (uint8_t *)((uint32_t)txData + bytesPerWord);
+ }
+
+ /* Wait until the last data is sent */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) && (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
+ {
+ }
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a piece of data using a blocking method.
+ *
+ * note This function blocks via polling until data is ready to be sent.
+ *
+ * param base FlexIO I2S base pointer
+ * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * param rxData Pointer to the data to be read.
+ * param size Bytes to be read.
+ * retval kStatus_Success Successfully read data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+#if I2S_RETRY_TIMES
+ uint32_t waitTimes = I2S_RETRY_TIMES;
+#endif
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ /* Wait until data is received */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while ((!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL)) &&
+ (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL))
+ {
+ }
+#endif
+
+ FLEXIO_I2S_ReadNonBlocking(base, bitWidth, rxData, bytesPerWord);
+ rxData = (uint8_t *)((uint32_t)rxData + bytesPerWord);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the FlexIO I2S handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * param callback FlexIO I2S callback function, which is called while finished a block.
+ * param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Store callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferTxHandleIRQ);
+
+ /* Set the TX/RX state. */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the FlexIO I2S receive handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * param callback FlexIO I2S callback function, which is called while finished a block.
+ * param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Store callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferRxHandleIRQ);
+
+ /* Set the TX/RX state. */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format.
+ *
+ * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle FlexIO I2S handle pointer.
+ * param format Pointer to audio data format structure.
+ * param srcClock_Hz FlexIO I2S bit clock source frequency in Hz. This parameter should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Set the bitWidth to handle */
+ handle->bitWidth = format->bitWidth;
+
+ /* Set sample rate */
+ if (srcClock_Hz != 0UL)
+ {
+ /* It is master */
+ FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
+ }
+ else
+ {
+ FLEXIO_I2S_SlaveSetFormat(base, format);
+ }
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on FlexIO I2S.
+ *
+ * note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status and check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param xfer Pointer to flexio_i2s_transfer_t structure
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_FLEXIO_I2S_TxBusy Previous transmission still not finished, data not all written to TX register yet.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+ if ((xfer->dataSize == 0U) || (xfer->data == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Add into queue */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
+
+ /* Enable Tx transfer */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on FlexIO I2S.
+ *
+ * note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status to check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param xfer Pointer to flexio_i2s_transfer_t structure
+ * retval kStatus_Success Successfully start the data receive.
+ * retval kStatus_FLEXIO_I2S_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ if ((xfer->dataSize == 0U) || (xfer->data == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Add into queue */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Enable interrupt */
+ FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
+
+ /* Enable Rx transfer */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current receive.
+ *
+ * note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop rx transfer and disable interrupt */
+ FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Gets the remaining bytes to be sent.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param count Bytes sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets the remaining bytes to be received.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * return count Bytes received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * param i2sHandle Pointer to flexio_i2s_handle_t structure
+ */
+void FLEXIO_I2S_TransferTxHandleIRQ(void *i2sBase, void *i2sHandle)
+{
+ assert(i2sHandle != NULL);
+
+ flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
+ FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
+ uint8_t *buffer = handle->queue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle error */
+ if ((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->txShifterIndex)) != 0UL)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, (1UL << base->txShifterIndex));
+ }
+ /* Handle transfer */
+ if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) != 0UL) &&
+ (handle->queue[handle->queueDriver].data != NULL))
+ {
+ FLEXIO_I2S_WriteNonBlocking(base, handle->bitWidth, buffer, dataSize);
+
+ /* Update internal counter */
+ handle->queue[handle->queueDriver].dataSize -= dataSize;
+ handle->queue[handle->queueDriver].data =
+ (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
+ }
+
+ /* If finished a block, call the callback function */
+ if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
+ {
+ (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->queue[handle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortSend(base, handle);
+ }
+}
+
+/*!
+ * brief Rx interrupt handler.
+ *
+ * param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * param i2sHandle Pointer to flexio_i2s_handle_t structure.
+ */
+void FLEXIO_I2S_TransferRxHandleIRQ(void *i2sBase, void *i2sHandle)
+{
+ assert(i2sHandle != NULL);
+
+ flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
+ FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
+ uint8_t *buffer = handle->queue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle transfer */
+ if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_RxDataRegFullFlag) != 0UL) &&
+ (handle->queue[handle->queueDriver].data != NULL))
+ {
+ FLEXIO_I2S_ReadNonBlocking(base, handle->bitWidth, buffer, dataSize);
+
+ /* Update internal state */
+ handle->queue[handle->queueDriver].dataSize -= dataSize;
+ handle->queue[handle->queueDriver].data =
+ (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
+ }
+
+ /* If finished a block, call the callback function */
+ if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
+ {
+ (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->queue[handle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortReceive(base, handle);
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.h
new file mode 100644
index 0000000000..3497d7c7ac
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s.h
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_I2S_H_
+#define _FSL_FLEXIO_I2S_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+
+/*!
+ * @addtogroup flexio_i2s
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO I2S driver version 2.2.0. */
+#define FSL_FLEXIO_I2S_DRIVER_VERSION (MAKE_VERSION(2, 2, 0))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef I2S_RETRY_TIMES
+#define I2S_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief FlexIO I2S transfer status */
+enum
+{
+ kStatus_FLEXIO_I2S_Idle = MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 0), /*!< FlexIO I2S is in idle state */
+ kStatus_FLEXIO_I2S_TxBusy = MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 1), /*!< FlexIO I2S Tx is busy */
+ kStatus_FLEXIO_I2S_RxBusy = MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 2), /*!< FlexIO I2S Tx is busy */
+ kStatus_FLEXIO_I2S_Error = MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 3), /*!< FlexIO I2S error occurred */
+ kStatus_FLEXIO_I2S_QueueFull = MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 4), /*!< FlexIO I2S transfer queue is full. */
+ kStatus_FLEXIO_I2S_Timeout =
+ MAKE_STATUS(kStatusGroup_FLEXIO_I2S, 5), /*!< FlexIO I2S timeout polling status flags. */
+};
+
+/*! @brief Define FlexIO I2S access structure typedef */
+typedef struct _flexio_i2s_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO base pointer */
+ uint8_t txPinIndex; /*!< Tx data pin index in FlexIO pins */
+ uint8_t rxPinIndex; /*!< Rx data pin index */
+ uint8_t bclkPinIndex; /*!< Bit clock pin index */
+ uint8_t fsPinIndex; /*!< Frame sync pin index */
+ uint8_t txShifterIndex; /*!< Tx data shifter index */
+ uint8_t rxShifterIndex; /*!< Rx data shifter index */
+ uint8_t bclkTimerIndex; /*!< Bit clock timer index */
+ uint8_t fsTimerIndex; /*!< Frame sync timer index */
+} FLEXIO_I2S_Type;
+
+/*! @brief Master or slave mode */
+typedef enum _flexio_i2s_master_slave
+{
+ kFLEXIO_I2S_Master = 0x0U, /*!< Master mode */
+ kFLEXIO_I2S_Slave = 0x1U /*!< Slave mode */
+} flexio_i2s_master_slave_t;
+
+/*! @brief _flexio_i2s_interrupt_enable Define FlexIO FlexIO I2S interrupt mask. */
+enum
+{
+ kFLEXIO_I2S_TxDataRegEmptyInterruptEnable = 0x1U, /*!< Transmit buffer empty interrupt enable. */
+ kFLEXIO_I2S_RxDataRegFullInterruptEnable = 0x2U, /*!< Receive buffer full interrupt enable. */
+};
+
+/*! @brief _flexio_i2s_status_flags Define FlexIO FlexIO I2S status mask. */
+enum
+{
+ kFLEXIO_I2S_TxDataRegEmptyFlag = 0x1U, /*!< Transmit buffer empty flag. */
+ kFLEXIO_I2S_RxDataRegFullFlag = 0x2U, /*!< Receive buffer full flag. */
+};
+
+/*! @brief FlexIO I2S configure structure */
+typedef struct _flexio_i2s_config
+{
+ bool enableI2S; /*!< Enable FlexIO I2S */
+ flexio_i2s_master_slave_t masterSlave; /*!< Master or slave */
+ flexio_pin_polarity_t txPinPolarity; /*!< Tx data pin polarity, active high or low */
+ flexio_pin_polarity_t rxPinPolarity; /*!< Rx data pin polarity */
+ flexio_pin_polarity_t bclkPinPolarity; /*!< Bit clock pin polarity */
+ flexio_pin_polarity_t fsPinPolarity; /*!< Frame sync pin polarity */
+ flexio_shifter_timer_polarity_t txTimerPolarity; /*!< Tx data valid on bclk rising or falling edge */
+ flexio_shifter_timer_polarity_t rxTimerPolarity; /*!< Rx data valid on bclk rising or falling edge */
+} flexio_i2s_config_t;
+
+/*! @brief FlexIO I2S audio format, FlexIO I2S only support the same format in Tx and Rx */
+typedef struct _flexio_i2s_format
+{
+ uint8_t bitWidth; /*!< Bit width of audio data, always 8/16/24/32 bits */
+ uint32_t sampleRate_Hz; /*!< Sample rate of the audio data */
+} flexio_i2s_format_t;
+
+/*!@brief FlexIO I2S transfer queue size, user can refine it according to use case. */
+#define FLEXIO_I2S_XFER_QUEUE_SIZE (4U)
+
+/*! @brief Audio sample rate */
+typedef enum _flexio_i2s_sample_rate
+{
+ kFLEXIO_I2S_SampleRate8KHz = 8000U, /*!< Sample rate 8000Hz */
+ kFLEXIO_I2S_SampleRate11025Hz = 11025U, /*!< Sample rate 11025Hz */
+ kFLEXIO_I2S_SampleRate12KHz = 12000U, /*!< Sample rate 12000Hz */
+ kFLEXIO_I2S_SampleRate16KHz = 16000U, /*!< Sample rate 16000Hz */
+ kFLEXIO_I2S_SampleRate22050Hz = 22050U, /*!< Sample rate 22050Hz */
+ kFLEXIO_I2S_SampleRate24KHz = 24000U, /*!< Sample rate 24000Hz */
+ kFLEXIO_I2S_SampleRate32KHz = 32000U, /*!< Sample rate 32000Hz */
+ kFLEXIO_I2S_SampleRate44100Hz = 44100U, /*!< Sample rate 44100Hz */
+ kFLEXIO_I2S_SampleRate48KHz = 48000U, /*!< Sample rate 48000Hz */
+ kFLEXIO_I2S_SampleRate96KHz = 96000U /*!< Sample rate 96000Hz */
+} flexio_i2s_sample_rate_t;
+
+/*! @brief Audio word width */
+typedef enum _flexio_i2s_word_width
+{
+ kFLEXIO_I2S_WordWidth8bits = 8U, /*!< Audio data width 8 bits */
+ kFLEXIO_I2S_WordWidth16bits = 16U, /*!< Audio data width 16 bits */
+ kFLEXIO_I2S_WordWidth24bits = 24U, /*!< Audio data width 24 bits */
+ kFLEXIO_I2S_WordWidth32bits = 32U /*!< Audio data width 32 bits */
+} flexio_i2s_word_width_t;
+
+/*! @brief Define FlexIO I2S transfer structure. */
+typedef struct _flexio_i2s_transfer
+{
+ uint8_t *data; /*!< Data buffer start pointer */
+ size_t dataSize; /*!< Bytes to be transferred. */
+} flexio_i2s_transfer_t;
+
+typedef struct _flexio_i2s_handle flexio_i2s_handle_t;
+
+/*! @brief FlexIO I2S xfer callback prototype */
+typedef void (*flexio_i2s_callback_t)(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Define FlexIO I2S handle structure. */
+struct _flexio_i2s_handle
+{
+ uint32_t state; /*!< Internal state */
+ flexio_i2s_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+ uint8_t bitWidth; /*!< Bit width for transfer, 8/16/24/32bits */
+ flexio_i2s_transfer_t queue[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO I2S.
+ *
+ * This API configures FlexIO pins and shifter to I2S and configures the FlexIO I2S with a configuration structure.
+ * The configuration structure can be filled by the user, or be set with default values by
+ * FLEXIO_I2S_GetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the FlexIO I2S driver. Otherwise, any access to the FlexIO I2S module can cause hard fault
+ * because the clock is not enabled.
+ *
+ * @param base FlexIO I2S base pointer
+ * @param config FlexIO I2S configure structure.
+ */
+void FLEXIO_I2S_Init(FLEXIO_I2S_Type *base, const flexio_i2s_config_t *config);
+
+/*!
+ * @brief Sets the FlexIO I2S configuration structure to default values.
+ *
+ * The purpose of this API is to get the configuration structure initialized for use in FLEXIO_I2S_Init().
+ * Users may use the initialized structure unchanged in FLEXIO_I2S_Init() or modify
+ * some fields of the structure before calling FLEXIO_I2S_Init().
+ *
+ * @param config pointer to master configuration structure
+ */
+void FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t *config);
+
+/*!
+ * @brief De-initializes the FlexIO I2S.
+ *
+ * Calling this API resets the FlexIO I2S shifter and timer config. After calling this API,
+ * call the FLEXO_I2S_Init to use the FlexIO I2S module.
+ *
+ * @param base FlexIO I2S base pointer
+ */
+void FLEXIO_I2S_Deinit(FLEXIO_I2S_Type *base);
+
+/*!
+ * @brief Enables/disables the FlexIO I2S module operation.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type
+ * @param enable True to enable, false dose not have any effect.
+ */
+static inline void FLEXIO_I2S_Enable(FLEXIO_I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexIO I2S status flags.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @return Status flag, which are ORed by the enumerators in the _flexio_i2s_status_flags.
+ */
+uint32_t FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type *base);
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @param mask interrupt source
+ */
+void FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * @param base pointer to FLEXIO_I2S_Type structure
+ * @param mask interrupt source
+ */
+void FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask);
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO I2S Tx DMA requests.
+ *
+ * @param base FlexIO I2S base pointer
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void FLEXIO_I2S_TxEnableDMA(FLEXIO_I2S_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->txShifterIndex, enable);
+}
+
+/*!
+ * @brief Enables/disables the FlexIO I2S Rx DMA requests.
+ *
+ * @param base FlexIO I2S base pointer
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void FLEXIO_I2S_RxEnableDMA(FLEXIO_I2S_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->rxShifterIndex, enable);
+}
+
+/*!
+ * @brief Gets the FlexIO I2S send data register address.
+ *
+ * This function returns the I2S data register address, mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @return FlexIO i2s send data register address.
+ */
+static inline uint32_t FLEXIO_I2S_TxGetDataRegisterAddress(FLEXIO_I2S_Type *base)
+{
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBufferBitSwapped, base->txShifterIndex);
+}
+
+/*!
+ * @brief Gets the FlexIO I2S receive data register address.
+ *
+ * This function returns the I2S data register address, mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @return FlexIO i2s receive data register address.
+ */
+static inline uint32_t FLEXIO_I2S_RxGetDataRegisterAddress(FLEXIO_I2S_Type *base)
+{
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBufferBitSwapped, base->rxShifterIndex);
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Configures the FlexIO I2S audio format in master mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @param format Pointer to FlexIO I2S audio data format structure.
+ * @param srcClock_Hz I2S master clock source frequency in Hz.
+ */
+void FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Configures the FlexIO I2S audio format in slave mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @param format Pointer to FlexIO I2S audio data format structure.
+ */
+void FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format);
+
+/*!
+ * @brief Sends data using a blocking method.
+ *
+ * @note This function blocks via polling until data is ready to be sent.
+ *
+ * @param base FlexIO I2S base pointer.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param txData Pointer to the data to be written.
+ * @param size Bytes to be written.
+ * @retval kStatus_Success Successfully write data.
+ * @retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size);
+
+/*!
+ * @brief Writes data into a data register.
+ *
+ * @param base FlexIO I2S base pointer.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param data Data to be written.
+ */
+static inline void FLEXIO_I2S_WriteData(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint32_t data)
+{
+ base->flexioBase->SHIFTBUFBIS[base->txShifterIndex] = (data << (32U - bitWidth));
+}
+
+/*!
+ * @brief Receives a piece of data using a blocking method.
+ *
+ * @note This function blocks via polling until data is ready to be sent.
+ *
+ * @param base FlexIO I2S base pointer
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param rxData Pointer to the data to be read.
+ * @param size Bytes to be read.
+ * @retval kStatus_Success Successfully read data.
+ * @retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size);
+
+/*!
+ * @brief Reads a data from the data register.
+ *
+ * @param base FlexIO I2S base pointer
+ * @return Data read from data register.
+ */
+static inline uint32_t FLEXIO_I2S_ReadData(FLEXIO_I2S_Type *base)
+{
+ return base->flexioBase->SHIFTBUFBIS[base->rxShifterIndex];
+}
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO I2S handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure
+ * @param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * @param callback FlexIO I2S callback function, which is called while finished a block.
+ * @param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Configures the FlexIO I2S audio format.
+ *
+ * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle FlexIO I2S handle pointer.
+ * @param format Pointer to audio data format structure.
+ * @param srcClock_Hz FlexIO I2S bit clock source frequency in Hz. This parameter should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Initializes the FlexIO I2S receive handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * @param callback FlexIO I2S callback function, which is called while finished a block.
+ * @param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs an interrupt non-blocking send transfer on FlexIO I2S.
+ *
+ * @note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status and check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * @param xfer Pointer to flexio_i2s_transfer_t structure
+ * @retval kStatus_Success Successfully start the data transmission.
+ * @retval kStatus_FLEXIO_I2S_TxBusy Previous transmission still not finished, data not all written to TX register yet.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on FlexIO I2S.
+ *
+ * @note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status to check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * @param xfer Pointer to flexio_i2s_transfer_t structure
+ * @retval kStatus_Success Successfully start the data receive.
+ * @retval kStatus_FLEXIO_I2S_RxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the current send.
+ *
+ * @note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle);
+
+/*!
+ * @brief Aborts the current receive.
+ *
+ * @note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes to be sent.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * @param count Bytes sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets the remaining bytes to be received.
+ *
+ * @param base Pointer to FLEXIO_I2S_Type structure.
+ * @param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * @param count Bytes recieved.
+ * @return count Bytes received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * @param i2sHandle Pointer to flexio_i2s_handle_t structure
+ */
+void FLEXIO_I2S_TransferTxHandleIRQ(void *i2sBase, void *i2sHandle);
+
+/*!
+ * @brief Rx interrupt handler.
+ *
+ * @param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * @param i2sHandle Pointer to flexio_i2s_handle_t structure.
+ */
+void FLEXIO_I2S_TransferRxHandleIRQ(void *i2sBase, void *i2sHandle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_FLEXIO_I2S_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_dma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_dma.h
new file mode 100644
index 0000000000..8fee244404
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_dma.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_I2S_DMA_H_
+#define _FSL_FLEXIO_I2S_DMA_H_
+
+#include "fsl_flexio_i2s.h"
+#include "fsl_dma.h"
+
+/*!
+ * @addtogroup flexio_dma_i2s
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO I2S DMA driver version 2.1.7. */
+#define FSL_FLEXIO_I2S_DMA_DRIVER_VERSION (MAKE_VERSION(2, 1, 7))
+/*@}*/
+
+typedef struct _flexio_i2s_dma_handle flexio_i2s_dma_handle_t;
+
+/*! @brief FlexIO I2S DMA transfer callback function for finish and error */
+typedef void (*flexio_i2s_dma_callback_t)(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO I2S DMA transfer handle, users should not touch the content of the handle.*/
+struct _flexio_i2s_dma_handle
+{
+ dma_handle_t *dmaHandle; /*!< DMA handler for FlexIO I2S send */
+ uint8_t bytesPerFrame; /*!< Bytes in a frame */
+ uint32_t state; /*!< Internal state for FlexIO I2S DMA transfer */
+ flexio_i2s_dma_callback_t callback; /*!< Callback for users while transfer finish or error occurred */
+ void *userData; /*!< User callback parameter */
+ flexio_i2s_transfer_t queue[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name DMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO I2S DMA handle.
+ *
+ * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
+ * transactional APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param callback FlexIO I2S DMA callback function called while finished a block.
+ * @param userData User parameter for callback.
+ * @param dmaHandle DMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferTxCreateHandleDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ flexio_i2s_dma_callback_t callback,
+ void *userData,
+ dma_handle_t *dmaHandle);
+
+/*!
+ * @brief Initializes the FlexIO I2S Rx DMA handle.
+ *
+ * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
+ * APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param callback FlexIO I2S DMA callback function called while finished a block.
+ * @param userData User parameter for callback.
+ * @param dmaHandle DMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferRxCreateHandleDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ flexio_i2s_dma_callback_t callback,
+ void *userData,
+ dma_handle_t *dmaHandle);
+
+/*!
+ * @brief Configures the FlexIO I2S Tx audio format.
+ *
+ * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the DMA parameter according to the format.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer
+ * @param format Pointer to FlexIO I2S audio data format structure.
+ * @param srcClock_Hz FlexIO I2S clock source frequency in Hz. It should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormatDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Performs a non-blocking FlexIO I2S transfer using DMA.
+ *
+ * @note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether FLEXIO I2S transfer finished.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a FlexIO I2S DMA send successfully.
+ * @retval kStatus_InvalidArgument The input arguments is invalid.
+ * @retval kStatus_TxBusy FlexIO I2S is busy sending data.
+ */
+status_t FLEXIO_I2S_TransferSendDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking FlexIO I2S receive using DMA.
+ *
+ * @note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status to check whether the FlexIO I2S transfer is finished.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a FlexIO I2S DMA receive successfully.
+ * @retval kStatus_InvalidArgument The input arguments is invalid.
+ * @retval kStatus_RxBusy FlexIO I2S is busy receiving data.
+ */
+status_t FLEXIO_I2S_TransferReceiveDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_dma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO I2S transfer using DMA.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortSendDMA(FLEXIO_I2S_Type *base, flexio_i2s_dma_handle_t *handle);
+
+/*!
+ * @brief Aborts a FlexIO I2S receive using DMA.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortReceiveDMA(FLEXIO_I2S_Type *base, flexio_i2s_dma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes to be sent.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param count Bytes sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCountDMA(FLEXIO_I2S_Type *base, flexio_i2s_dma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets the remaining bytes to be received.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param count Bytes received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCountDMA(FLEXIO_I2S_Type *base, flexio_i2s_dma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.c
new file mode 100644
index 0000000000..faa1541530
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2s_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2s_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for flexio_i2s_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_i2s_edma_private_handle
+{
+ FLEXIO_I2S_Type *base;
+ flexio_i2s_edma_handle_t *handle;
+} flexio_i2s_edma_private_handle_t;
+
+/*!@brief _flexio_i2s_edma_transfer_state */
+enum
+{
+ kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO I2S is busy */
+ kFLEXIO_I2S_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static flexio_i2s_edma_private_handle_t s_edmaPrivateHandle[2];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief FLEXIO I2S EDMA callback for send.
+ *
+ * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief FLEXIO I2S EDMA callback for receive.
+ *
+ * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
+ flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (flexio_i2sHandle->callback != NULL)
+ {
+ (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortSendEDMA(privHandle->base, flexio_i2sHandle);
+ }
+}
+
+static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
+ flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (flexio_i2sHandle->callback != NULL)
+ {
+ (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortReceiveEDMA(privHandle->base, flexio_i2sHandle);
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO I2S eDMA handle.
+ *
+ * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
+ * transactional APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer.
+ * param callback FlexIO I2S eDMA callback function called while finished a block.
+ * param userData User parameter for callback.
+ * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set flexio_i2s base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set FLEXIO I2S state to idle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ s_edmaPrivateHandle[0].base = base;
+ s_edmaPrivateHandle[0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, FLEXIO_I2S_TxEDMACallback, &s_edmaPrivateHandle[0]);
+}
+
+/*!
+ * brief Initializes the FlexIO I2S Rx eDMA handle.
+ *
+ * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
+ * APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer.
+ * param callback FlexIO I2S eDMA callback function called while finished a block.
+ * param userData User parameter for callback.
+ * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set flexio_i2s base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set FLEXIO I2S state to idle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ s_edmaPrivateHandle[1].base = base;
+ s_edmaPrivateHandle[1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, FLEXIO_I2S_RxEDMACallback, &s_edmaPrivateHandle[1]);
+}
+
+/*!
+ * brief Configures the FlexIO I2S Tx audio format.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to format.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer
+ * param format Pointer to FlexIO I2S audio data format structure.
+ * param srcClock_Hz FlexIO I2S clock source frequency in Hz, it should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to FLEXIO I2S registers */
+ if (srcClock_Hz != 0UL)
+ {
+ /* It is master */
+ FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
+ }
+ else
+ {
+ FLEXIO_I2S_SlaveSetFormat(base, format);
+ }
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ handle->bytesPerFrame = format->bitWidth / 8U;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO I2S transfer using DMA.
+ *
+ * note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether the FlexIO I2S transfer is finished.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a FlexIO I2S eDMA send successfully.
+ * retval kStatus_InvalidArgument The input arguments is invalid.
+ * retval kStatus_TxBusy FlexIO I2S is busy sending data.
+ */
+status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = FLEXIO_I2S_TxGetDataRegisterAddress(base) + (4UL - handle->bytesPerFrame);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Update the queue state */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (uint32_t *)destAddr, handle->bytesPerFrame,
+ handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
+ handle->nbytes = handle->bytesPerFrame;
+
+ (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ FLEXIO_I2S_TxEnableDMA(base, true);
+
+ /* Enable FLEXIO I2S Tx clock */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO I2S receive using eDMA.
+ *
+ * note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status and check whether the FlexIO I2S transfer is
+ * finished.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a FlexIO I2S eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input arguments is invalid.
+ * retval kStatus_RxBusy FlexIO I2S is busy receiving data.
+ */
+status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = FLEXIO_I2S_RxGetDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Update queue state */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
+ handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
+ handle->nbytes = handle->bytesPerFrame;
+
+ (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ FLEXIO_I2S_RxEnableDMA(base, true);
+
+ /* Enable FLEXIO I2S Rx clock */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a FlexIO I2S transfer using eDMA.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ FLEXIO_I2S_TxEnableDMA(base, false);
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+}
+
+/*!
+ * brief Aborts a FlexIO I2S receive using eDMA.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ FLEXIO_I2S_RxEnableDMA(base, false);
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+}
+
+/*!
+ * brief Gets the remaining bytes to be sent.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param count Bytes sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Get the remaining bytes to be received.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param count Bytes received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.h
new file mode 100644
index 0000000000..a3a0ef1264
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_i2s_edma.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_I2S_EDMA_H_
+#define _FSL_FLEXIO_I2S_EDMA_H_
+
+#include "fsl_flexio_i2s.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexio_edma_i2s
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO I2S EDMA driver version 2.1.7. */
+#define FSL_FLEXIO_I2S_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 1, 7))
+/*@}*/
+
+typedef struct _flexio_i2s_edma_handle flexio_i2s_edma_handle_t;
+
+/*! @brief FlexIO I2S eDMA transfer callback function for finish and error */
+typedef void (*flexio_i2s_edma_callback_t)(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO I2S DMA transfer handle, users should not touch the content of the handle.*/
+struct _flexio_i2s_edma_handle
+{
+ edma_handle_t *dmaHandle; /*!< DMA handler for FlexIO I2S send */
+ uint8_t bytesPerFrame; /*!< Bytes in a frame */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint32_t state; /*!< Internal state for FlexIO I2S eDMA transfer */
+ flexio_i2s_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurred */
+ void *userData; /*!< User callback parameter */
+ edma_tcd_t tcd[FLEXIO_I2S_XFER_QUEUE_SIZE + 1U]; /*!< TCD pool for eDMA transfer. */
+ flexio_i2s_transfer_t queue[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[FLEXIO_I2S_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO I2S eDMA handle.
+ *
+ * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
+ * transactional APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S eDMA handle pointer.
+ * @param callback FlexIO I2S eDMA callback function called while finished a block.
+ * @param userData User parameter for callback.
+ * @param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Initializes the FlexIO I2S Rx eDMA handle.
+ *
+ * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
+ * APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S eDMA handle pointer.
+ * @param callback FlexIO I2S eDMA callback function called while finished a block.
+ * @param userData User parameter for callback.
+ * @param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Configures the FlexIO I2S Tx audio format.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to format.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S eDMA handle pointer
+ * @param format Pointer to FlexIO I2S audio data format structure.
+ * @param srcClock_Hz FlexIO I2S clock source frequency in Hz, it should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Performs a non-blocking FlexIO I2S transfer using DMA.
+ *
+ * @note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether the FlexIO I2S transfer is finished.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a FlexIO I2S eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input arguments is invalid.
+ * @retval kStatus_TxBusy FlexIO I2S is busy sending data.
+ */
+status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking FlexIO I2S receive using eDMA.
+ *
+ * @note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status and check whether the FlexIO I2S transfer is
+ * finished.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a FlexIO I2S eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input arguments is invalid.
+ * @retval kStatus_RxBusy FlexIO I2S is busy receiving data.
+ */
+status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO I2S transfer using eDMA.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a FlexIO I2S receive using eDMA.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes to be sent.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param count Bytes sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Get the remaining bytes to be received.
+ *
+ * @param base FlexIO I2S peripheral base address.
+ * @param handle FlexIO I2S DMA handle pointer.
+ * @param count Bytes received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd.h
new file mode 100644
index 0000000000..f5f1e4ecb7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd.h
@@ -0,0 +1,685 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_MCULCD_H_
+#define _FSL_FLEXIO_MCULCD_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+
+/*!
+ * @addtogroup flexio_mculcd
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO MCULCD driver version. */
+#define FSL_FLEXIO_MCULCD_DRIVER_VERSION (MAKE_VERSION(2, 0, 7))
+/*@}*/
+
+#ifndef FLEXIO_MCULCD_WAIT_COMPLETE_TIME
+/*!
+ * @brief The delay time to wait for FLEXIO transmit complete.
+ *
+ * Currently there is no method to detect whether the data has been
+ * sent out from the shifter, so the driver use a software delay for this. When
+ * the data is written to shifter buffer, the driver call the delay
+ * function to wait for the data shift out.
+ * If this value is too small, then the last few bytes might be lost when writing
+ * data using interrupt method or DMA method.
+ */
+#define FLEXIO_MCULCD_WAIT_COMPLETE_TIME 512
+#endif
+
+#ifndef FLEXIO_MCULCD_DATA_BUS_WIDTH
+/*!
+ * @brief The data bus width, must be 8 or 16.
+ */
+#define FLEXIO_MCULCD_DATA_BUS_WIDTH 16UL
+#endif
+
+#if (16UL != FLEXIO_MCULCD_DATA_BUS_WIDTH) && (8UL != FLEXIO_MCULCD_DATA_BUS_WIDTH)
+#error Only support data bus 8-bit or 16-bit
+#endif
+
+/*! @brief FlexIO LCD transfer status */
+enum
+{
+ kStatus_FLEXIO_MCULCD_Idle = MAKE_STATUS(kStatusGroup_FLEXIO_MCULCD, 0), /*!< FlexIO LCD is idle. */
+ kStatus_FLEXIO_MCULCD_Busy = MAKE_STATUS(kStatusGroup_FLEXIO_MCULCD, 1), /*!< FlexIO LCD is busy */
+ kStatus_FLEXIO_MCULCD_Error = MAKE_STATUS(kStatusGroup_FLEXIO_MCULCD, 2), /*!< FlexIO LCD error occurred */
+};
+
+/*! @brief Define FlexIO MCULCD pixel format. */
+typedef enum _flexio_mculcd_pixel_format
+{
+ kFLEXIO_MCULCD_RGB565 = 0, /*!< RGB565, 16-bit. */
+ kFLEXIO_MCULCD_BGR565, /*!< BGR565, 16-bit. */
+ kFLEXIO_MCULCD_RGB888, /*!< RGB888, 24-bit. */
+ kFLEXIO_MCULCD_BGR888, /*!< BGR888, 24-bit. */
+} flexio_mculcd_pixel_format_t;
+
+/*! @brief Define FlexIO MCULCD bus type. */
+typedef enum _flexio_mculcd_bus
+{
+ kFLEXIO_MCULCD_8080, /*!< Using Intel 8080 bus. */
+ kFLEXIO_MCULCD_6800, /*!< Using Motorola 6800 bus. */
+} flexio_mculcd_bus_t;
+
+/*! @brief Define FlexIO MCULCD interrupt mask. */
+enum _flexio_mculcd_interrupt_enable
+{
+ kFLEXIO_MCULCD_TxEmptyInterruptEnable = (1U << 0U), /*!< Transmit buffer empty interrupt enable. */
+ kFLEXIO_MCULCD_RxFullInterruptEnable = (1U << 1U), /*!< Receive buffer full interrupt enable. */
+};
+
+/*! @brief Define FlexIO MCULCD status mask. */
+enum _flexio_mculcd_status_flags
+{
+ kFLEXIO_MCULCD_TxEmptyFlag = (1U << 0U), /*!< Transmit buffer empty flag. */
+ kFLEXIO_MCULCD_RxFullFlag = (1U << 1U), /*!< Receive buffer full flag. */
+};
+
+/*! @brief Define FlexIO MCULCD DMA mask. */
+enum _flexio_mculcd_dma_enable
+{
+ kFLEXIO_MCULCD_TxDmaEnable = 0x1U, /*!< Tx DMA request source */
+ kFLEXIO_MCULCD_RxDmaEnable = 0x2U, /*!< Rx DMA request source */
+};
+
+/*! @brief Function to set or clear the CS and RS pin. */
+typedef void (*flexio_mculcd_pin_func_t)(bool set);
+
+/*! @brief Define FlexIO MCULCD access structure typedef. */
+typedef struct _flexio_mculcd_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO base pointer. */
+ flexio_mculcd_bus_t busType; /*!< The bus type, 8080 or 6800. */
+ uint8_t dataPinStartIndex; /*!< Start index of the data pin, the FlexIO pin dataPinStartIndex
+ to (dataPinStartIndex + FLEXIO_MCULCD_DATA_BUS_WIDTH -1)
+ will be used for data transfer. Only support data bus width 8 and 16. */
+ uint8_t ENWRPinIndex; /*!< Pin select for WR(8080 mode), EN(6800 mode). */
+ uint8_t RDPinIndex; /*!< Pin select for RD(8080 mode), not used in 6800 mode. */
+ uint8_t txShifterStartIndex; /*!< Start index of shifters used for data write, it must be 0 or 4. */
+ uint8_t txShifterEndIndex; /*!< End index of shifters used for data write. */
+ uint8_t rxShifterStartIndex; /*!< Start index of shifters used for data read. */
+ uint8_t rxShifterEndIndex; /*!< End index of shifters used for data read, it must be 3 or 7. */
+ uint8_t timerIndex; /*!< Timer index used in FlexIO MCULCD. */
+ flexio_mculcd_pin_func_t setCSPin; /*!< Function to set or clear the CS pin. */
+ flexio_mculcd_pin_func_t setRSPin; /*!< Function to set or clear the RS pin. */
+ flexio_mculcd_pin_func_t setRDWRPin; /*!< Function to set or clear the RD/WR pin, only used in 6800 mode. */
+} FLEXIO_MCULCD_Type;
+
+/*! @brief Define FlexIO MCULCD configuration structure. */
+typedef struct _flexio_mculcd_config
+{
+ bool enable; /*!< Enable/disable FlexIO MCULCD after configuration. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode. */
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode. */
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers,
+ fast access requires the FlexIO clock to be at least
+ twice the frequency of the bus clock. */
+ uint32_t baudRate_Bps; /*!< Baud rate in Bps. */
+} flexio_mculcd_config_t;
+
+/*! @brief Transfer mode.*/
+typedef enum _flexio_mculcd_transfer_mode
+{
+ kFLEXIO_MCULCD_ReadArray, /*!< Read data into an array. */
+ kFLEXIO_MCULCD_WriteArray, /*!< Write data from an array. */
+ kFLEXIO_MCULCD_WriteSameValue, /*!< Write the same value many times. */
+} flexio_mculcd_transfer_mode_t;
+
+/*! @brief Define FlexIO MCULCD transfer structure. */
+typedef struct _flexio_mculcd_transfer
+{
+ uint32_t command; /*!< Command to send. */
+ flexio_mculcd_transfer_mode_t mode; /*!< Transfer mode. */
+ uint32_t dataAddrOrSameValue; /*!< When sending the same value for many times,
+ this is the value to send. When writing or reading array,
+ this is the address of the data array. */
+ size_t dataSize; /*!< How many bytes to transfer. */
+} flexio_mculcd_transfer_t;
+
+/*! @brief typedef for flexio_mculcd_handle_t in advance. */
+typedef struct _flexio_mculcd_handle flexio_mculcd_handle_t;
+
+/*! @brief FlexIO MCULCD callback for finished transfer.
+ *
+ * When transfer finished, the callback function is called and returns the
+ * @p status as kStatus_FLEXIO_MCULCD_Idle.
+ */
+typedef void (*flexio_mculcd_transfer_callback_t)(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Define FlexIO MCULCD handle structure. */
+struct _flexio_mculcd_handle
+{
+ uint32_t dataAddrOrSameValue; /*!< When sending the same value for many times,
+ this is the value to send. When writing or reading array,
+ this is the address of the data array. */
+ size_t dataCount; /*!< Total count to be transferred. */
+ volatile size_t remainingCount; /*!< Remaining count to transfer. */
+ volatile uint32_t state; /*!< FlexIO MCULCD internal state. */
+ flexio_mculcd_transfer_callback_t completionCallback; /*!< FlexIO MCULCD transfer completed callback. */
+ void *userData; /*!< Callback parameter. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name FlexIO MCULCD Configuration
+ * @{
+ */
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, configures the
+ * FlexIO MCULCD hardware, and configures the FlexIO MCULCD with FlexIO MCULCD
+ * configuration.
+ * The configuration structure can be filled by the user, or be set with default
+ * values
+ * by the @ref FLEXIO_MCULCD_GetDefaultConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param config Pointer to the flexio_mculcd_config_t structure.
+ * @param srcClock_Hz FlexIO source clock in Hz.
+ * @retval kStatus_Success Initialization success.
+ * @retval kStatus_InvalidArgument Initialization failed because of invalid
+ * argument.
+ */
+status_t FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type *base, flexio_mculcd_config_t *config, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Resets the FLEXIO_MCULCD timer and shifter configuration.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ */
+void FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO MCULCD.
+ *
+ * The default configuration value is:
+ * @code
+ * config->enable = true;
+ * config->enableInDoze = false;
+ * config->enableInDebug = true;
+ * config->enableFastAccess = true;
+ * config->baudRate_Bps = 96000000U;
+ * @endcode
+ * @param config Pointer to the flexio_mculcd_config_t structure.
+ */
+void FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t *config);
+
+/*@}*/
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets FlexIO MCULCD status flags.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @return status flag; OR'ed value or the @ref _flexio_mculcd_status_flags.
+ *
+ * @note Don't use this function with DMA APIs.
+ */
+uint32_t FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Clears FlexIO MCULCD status flags.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param mask Status to clear, it is the OR'ed value of @ref
+ * _flexio_mculcd_status_flags.
+ *
+ * @note Don't use this function with DMA APIs.
+ */
+void FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the FlexIO MCULCD interrupt.
+ *
+ * This function enables the FlexIO MCULCD interrupt.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param mask Interrupts to enable, it is the OR'ed value of @ref
+ * _flexio_mculcd_interrupt_enable.
+ */
+void FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the FlexIO MCULCD interrupt.
+ *
+ * This function disables the FlexIO MCULCD interrupt.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param mask Interrupts to disable, it is the OR'ed value of @ref
+ * _flexio_mculcd_interrupt_enable.
+ */
+void FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO MCULCD transmit DMA.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void FLEXIO_MCULCD_EnableTxDMA(FLEXIO_MCULCD_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, (1UL << base->txShifterStartIndex), enable);
+}
+
+/*!
+ * @brief Enables/disables the FlexIO MCULCD receive DMA.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void FLEXIO_MCULCD_EnableRxDMA(FLEXIO_MCULCD_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, (1UL << base->rxShifterEndIndex), enable);
+}
+
+/*!
+ * @brief Gets the FlexIO MCULCD transmit data register address.
+ *
+ * This function returns the MCULCD data register address, which is mainly used
+ * by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @return FlexIO MCULCD transmit data register address.
+ */
+static inline uint32_t FLEXIO_MCULCD_GetTxDataRegisterAddress(FLEXIO_MCULCD_Type *base)
+{
+ return (uint32_t) & (base->flexioBase->SHIFTBUF[base->txShifterStartIndex]);
+}
+
+/*!
+ * @brief Gets the FlexIO MCULCD receive data register address.
+ *
+ * This function returns the MCULCD data register address, which is mainly used
+ * by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @return FlexIO MCULCD receive data register address.
+ */
+static inline uint32_t FLEXIO_MCULCD_GetRxDataRegisterAddress(FLEXIO_MCULCD_Type *base)
+{
+ return (uint32_t) & (base->flexioBase->SHIFTBUF[base->rxShifterStartIndex]);
+}
+
+/*@}*/
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Set desired baud rate.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param baudRate_Bps Desired baud rate.
+ * @param srcClock_Hz FLEXIO clock frequency in Hz.
+ * @retval kStatus_Success Set successfully.
+ * @retval kStatus_InvalidArgument Could not set the baud rate.
+ */
+status_t FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Configures the FLEXIO MCULCD to multiple beats write mode.
+ *
+ * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
+ * multiple beats write mode using this function. After write operation, the configuration
+ * is cleared by @ref FLEXIO_MCULCD_ClearSingleBeatWriteConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
+ *
+ * Clear the write configuration set by @ref FLEXIO_MCULCD_SetSingleBeatWriteConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Configures the FLEXIO MCULCD to multiple beats read mode.
+ *
+ * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
+ * to multiple beats read mode using this function. After read operation, the configuration
+ * is cleared by @ref FLEXIO_MCULCD_ClearSingleBeatReadConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
+ *
+ * Clear the read configuration set by @ref FLEXIO_MCULCD_SetSingleBeatReadConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Configures the FLEXIO MCULCD to multiple beats write mode.
+ *
+ * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
+ * multiple beats write mode using this function. After write operation, the configuration
+ * is cleared by FLEXIO_MCULCD_ClearMultBeatsWriteConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
+ *
+ * Clear the write configuration set by FLEXIO_MCULCD_SetMultBeatsWriteConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Configures the FLEXIO MCULCD to multiple beats read mode.
+ *
+ * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
+ * to multiple beats read mode using this function. After read operation, the configuration
+ * is cleared by FLEXIO_MCULCD_ClearMultBeatsReadConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
+ *
+ * Clear the read configuration set by FLEXIO_MCULCD_SetMultBeatsReadConfig.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * @note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Enables/disables the FlexIO MCULCD module operation.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type.
+ * @param enable True to enable, false does not have any effect.
+ */
+static inline void FLEXIO_MCULCD_Enable(FLEXIO_MCULCD_Type *base, bool enable)
+{
+ if (enable)
+ {
+ FLEXIO_Enable(base->flexioBase, enable);
+ }
+}
+
+/*!
+ * @brief Read data from the FLEXIO MCULCD RX shifter buffer.
+ *
+ * Read data from the RX shift buffer directly, it does no check whether the
+ * buffer is empty or not.
+ *
+ * If the data bus width is 8-bit:
+ * @code
+ * uint8_t value;
+ * value = (uint8_t)FLEXIO_MCULCD_ReadData(base);
+ * @endcode
+ *
+ * If the data bus width is 16-bit:
+ * @code
+ * uint16_t value;
+ * value = (uint16_t)FLEXIO_MCULCD_ReadData(base);
+ * @endcode
+ *
+ * @note This function returns the RX shifter buffer value (32-bit) directly.
+ * The return value should be converted according to data bus width.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @return The data read out.
+ *
+ * @note Don't use this function with DMA APIs.
+ */
+uint32_t FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type *base);
+
+/*!
+ * @brief Write data into the FLEXIO MCULCD TX shifter buffer.
+ *
+ * Write data into the TX shift buffer directly, it does no check whether the
+ * buffer is full or not.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param data The data to write.
+ *
+ * @note Don't use this function with DMA APIs.
+ */
+static inline void FLEXIO_MCULCD_WriteData(FLEXIO_MCULCD_Type *base, uint32_t data)
+{
+ base->flexioBase->SHIFTBUF[base->txShifterStartIndex] = data;
+}
+
+/*!
+ * @brief Assert the nCS to start transfer.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ */
+static inline void FLEXIO_MCULCD_StartTransfer(FLEXIO_MCULCD_Type *base)
+{
+ base->setCSPin(false);
+}
+
+/*!
+ * @brief De-assert the nCS to stop transfer.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ */
+static inline void FLEXIO_MCULCD_StopTransfer(FLEXIO_MCULCD_Type *base)
+{
+ base->setCSPin(true);
+}
+
+/*!
+ * @brief Wait for transmit data send out finished.
+ *
+ * Currently there is no effective method to wait for the data send out
+ * from the shiter, so here use a while loop to wait.
+ *
+ * @note This is an internal used function.
+ */
+void FLEXIO_MCULCD_WaitTransmitComplete(void);
+
+/*!
+ * @brief Send command in blocking way.
+ *
+ * This function sends the command and returns when the command has been sent
+ * out.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param command The command to send.
+ */
+void FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type *base, uint32_t command);
+
+/*!
+ * @brief Send data array in blocking way.
+ *
+ * This function sends the data array and returns when the data sent out.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param data The data array to send.
+ * @param size How many bytes to write.
+ */
+void FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type *base, const void *data, size_t size);
+
+/*!
+ * @brief Read data into array in blocking way.
+ *
+ * This function reads the data into array and returns when the data read
+ * finished.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param data The array to save the data.
+ * @param size How many bytes to read.
+ */
+void FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size);
+
+/*!
+ * @brief Send the same value many times in blocking way.
+ *
+ * This function sends the same value many times. It could be used to clear the
+ * LCD screen. If the data bus width is 8, this function will send LSB 8 bits of
+ * @p sameValue for @p size times. If the data bus is 16, this function will send
+ * LSB 16 bits of @p sameValue for @p size / 2 times.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param sameValue The same value to send.
+ * @param size How many bytes to send.
+ */
+void FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type *base, uint32_t sameValue, size_t size);
+
+/*!
+ * @brief Performs a polling transfer.
+ *
+ * @note The API does not return until the transfer finished.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param xfer pointer to flexio_mculcd_transfer_t structure.
+ */
+void FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_transfer_t *xfer);
+/*@}*/
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO MCULCD handle, which is used in transactional
+ * functions.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_handle_t *handle,
+ flexio_mculcd_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which
+ * returns right away. When all data is sent out/received, the callback
+ * function is called.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * @param xfer FlexIO MCULCD transfer structure. See #flexio_mculcd_transfer_t.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_MCULCD_Busy MCULCD is busy with another transfer.
+ */
+status_t FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_handle_t *handle,
+ flexio_mculcd_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the data transfer, which used IRQ.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ */
+void FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle);
+
+/*!
+ * @brief Gets the data transfer status which used IRQ.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * @param count How many bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_Success Get the transferred count Successfully.
+ * @retval kStatus_NoTransferInProgress No transfer in process.
+ */
+status_t FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, size_t *count);
+
+/*!
+ * @brief FlexIO MCULCD IRQ handler function.
+ *
+ * @param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ */
+void FLEXIO_MCULCD_TransferHandleIRQ(void *base, void *handle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /*_FSL_FLEXIO_MCULCD_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_edma.h
new file mode 100644
index 0000000000..200440baae
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_edma.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_MCULCD_EDMA_H_
+#define _FSL_FLEXIO_MCULCD_EDMA_H_
+
+#include "fsl_edma.h"
+#include "fsl_flexio_mculcd.h"
+
+/*!
+ * @addtogroup flexio_edma_mculcd
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*@{*/
+/*! @brief FlexIO MCULCD EDMA driver version. */
+#define FSL_FLEXIO_MCULCD_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+/*! @brief typedef for flexio_mculcd_edma_handle_t in advance. */
+typedef struct _flexio_mculcd_edma_handle flexio_mculcd_edma_handle_t;
+
+/*! @brief FlexIO MCULCD master callback for transfer complete.
+ *
+ * When transfer finished, the callback function is called and returns the
+ * @p status as kStatus_FLEXIO_MCULCD_Idle.
+ */
+typedef void (*flexio_mculcd_edma_transfer_callback_t)(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO MCULCD eDMA transfer handle, users should not touch the
+ * content of the handle.*/
+struct _flexio_mculcd_edma_handle
+{
+ FLEXIO_MCULCD_Type *base; /*!< Pointer to the FLEXIO_MCULCD_Type. */
+ uint8_t txShifterNum; /*!< Number of shifters used for TX. */
+ uint8_t rxShifterNum; /*!< Number of shifters used for RX. */
+ uint32_t minorLoopBytes; /*!< eDMA transfer minor loop bytes. */
+ edma_modulo_t txEdmaModulo; /*!< Modulo value for the FlexIO shifter buffer access. */
+ edma_modulo_t rxEdmaModulo; /*!< Modulo value for the FlexIO shifter buffer access. */
+ uint32_t dataAddrOrSameValue; /*!< When sending the same value for many times,
+ this is the value to send. When writing or
+ reading array, this is the address of the
+ data array. */
+ size_t dataCount; /*!< Total count to be transferred. */
+ volatile size_t remainingCount; /*!< Remaining count still not transfered. */
+ volatile uint32_t state; /*!< FlexIO MCULCD driver internal state. */
+ edma_handle_t *txDmaHandle; /*!< DMA handle for MCULCD TX */
+ edma_handle_t *rxDmaHandle; /*!< DMA handle for MCULCD RX */
+ flexio_mculcd_edma_transfer_callback_t completionCallback; /*!< Callback for MCULCD DMA transfer */
+ void *userData; /*!< User Data for MCULCD DMA callback */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXO MCULCD master eDMA handle.
+ *
+ * This function initializes the FLEXO MCULCD master eDMA handle which can be
+ * used for other FLEXO MCULCD transactional APIs. For a specified FLEXO MCULCD
+ * instance, call this API once to get the initialized handle.
+ *
+ * @param base Pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to flexio_mculcd_edma_handle_t structure to store the
+ * transfer state.
+ * @param callback MCULCD transfer complete callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @param txDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA TX,
+ * the DMA request source of this handle should be the first of TX shifters.
+ * @param rxDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA RX,
+ * the DMA request source of this handle should be the last of RX shifters.
+ * @retval kStatus_Success Successfully create the handle.
+ */
+status_t FLEXIO_MCULCD_TransferCreateHandleEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ flexio_mculcd_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txDmaHandle,
+ edma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Performs a non-blocking FlexIO MCULCD transfer using eDMA.
+ *
+ * This function returns immediately after transfer initiates. To check whether
+ * the transfer is completed, user could:
+ * 1. Use the transfer completed callback;
+ * 2. Polling function FLEXIO_MCULCD_GetTransferCountEDMA
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle pointer to flexio_mculcd_edma_handle_t structure to store the
+ * transfer state.
+ * @param xfer Pointer to FlexIO MCULCD transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_MCULCD_Busy FlexIO MCULCD is not idle, it is running another
+ * transfer.
+ */
+status_t FLEXIO_MCULCD_TransferEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ flexio_mculcd_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO MCULCD transfer using eDMA.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle FlexIO MCULCD eDMA handle pointer.
+ */
+void FLEXIO_MCULCD_TransferAbortEDMA(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes for FlexIO MCULCD eDMA transfer.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle FlexIO MCULCD eDMA handle pointer.
+ * @param count Number of count transferred so far by the eDMA transaction.
+ * @retval kStatus_Success Get the transferred count Successfully.
+ * @retval kStatus_NoTransferInProgress No transfer in process.
+ */
+status_t FLEXIO_MCULCD_TransferGetCountEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif /* _FSL_FLEXIO_MCULCD_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_smartdma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_smartdma.h
new file mode 100644
index 0000000000..bbc8d4fa5b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_mculcd_smartdma.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019, 2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_MCULCD_SMARTDMA_H_
+#define _FSL_FLEXIO_MCULCD_SMARTDMA_H_
+
+#include "fsl_smartdma.h"
+#include "fsl_flexio_mculcd.h"
+
+/*!
+ * @addtogroup flexio_smartdma_mculcd
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*@{*/
+/*! @brief FlexIO MCULCD SMARTDMA driver version. */
+#define FSL_FLEXIO_MCULCD_SMARTDMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+/*@}*/
+
+/*! @brief SMARTDMA transfer size should be multiple of 64 bytes. */
+#define FLEXIO_MCULCD_SMARTDMA_TX_LEN_ALIGN 64U
+
+/*! @brief SMARTDMA transfer memory address should be 4 byte aligned. */
+#define FLEXIO_MCULCD_SMARTDMA_TX_ADDR_ALIGN 4U
+
+/*! @brief typedef for flexio_mculcd_smartdma_handle_t in advance. */
+typedef struct _flexio_mculcd_smartdma_handle flexio_mculcd_smartdma_handle_t;
+
+/*! @brief FlexIO MCULCD master callback for transfer complete.
+ *
+ * When transfer finished, the callback function is called and returns the
+ * @p status as kStatus_FLEXIO_MCULCD_Idle.
+ */
+typedef void (*flexio_mculcd_smartdma_transfer_callback_t)(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_smartdma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO MCULCD SMARTDMA transfer handle, users should not touch the
+ * content of the handle.*/
+struct _flexio_mculcd_smartdma_handle
+{
+ FLEXIO_MCULCD_Type *base; /*!< Pointer to the FLEXIO_MCULCD_Type. */
+ size_t dataCount; /*!< Total count to be transferred. */
+ uint32_t dataAddrOrSameValue; /*!< When sending the same value for many times,
+ this is the value to send. When writing or reading array,
+ this is the address of the data array. */
+ size_t dataCountUsingEzh; /*!< Data transfered using SMARTDMA. */
+ volatile size_t remainingCount; /*!< Remaining count to transfer. */
+ volatile uint32_t state; /*!< FlexIO MCULCD driver internal state. */
+ uint8_t smartdmaApi; /*!< The SMARTDMA API used during transfer. */
+ bool needColorConvert; /*!< Need color convert or not. */
+ uint8_t blockingXferBuffer[FLEXIO_MCULCD_SMARTDMA_TX_LEN_ALIGN * 3 /
+ 2]; /*!< Used for blocking method color space convet. */
+ flexio_mculcd_smartdma_transfer_callback_t completionCallback; /*!< Callback for MCULCD SMARTDMA transfer */
+ void *userData; /*!< User Data for MCULCD SMARTDMA callback */
+ smartdma_flexio_mculcd_param_t smartdmaParam; /*!< SMARTDMA function parameters. */
+ uint32_t smartdmaStack[1]; /*!< SMARTDMA function stack. */
+};
+
+/*! @brief FlexIO MCULCD SMARTDMA configuration. */
+typedef struct _flexio_mculcd_smartdma_config
+{
+ flexio_mculcd_pixel_format_t inputPixelFormat; /*!< The pixel format in the frame buffer. */
+ flexio_mculcd_pixel_format_t outputPixelFormat; /*!< The pixel format on the 8080/68k bus. */
+} flexio_mculcd_smartdma_config_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name SMARTDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXO MCULCD master SMARTDMA handle.
+ *
+ * This function initializes the FLEXO MCULCD master SMARTDMA handle which can be
+ * used for other FLEXO MCULCD transactional APIs. For a specified FLEXO MCULCD
+ * instance, call this API once to get the initialized handle.
+ *
+ * @param base Pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle Pointer to flexio_mculcd_smartdma_handle_t structure to store the
+ * transfer state.
+ * @param config Pointer to the configuration.
+ * @param callback MCULCD transfer complete callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @retval kStatus_Success Successfully create the handle.
+ */
+status_t FLEXIO_MCULCD_TransferCreateHandleSMARTDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_smartdma_handle_t *handle,
+ const flexio_mculcd_smartdma_config_t *config,
+ flexio_mculcd_smartdma_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a non-blocking FlexIO MCULCD transfer using SMARTDMA.
+ *
+ * This function returns immediately after transfer initiates. Use the callback
+ * function to check whether the transfer is completed.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle pointer to flexio_mculcd_smartdma_handle_t structure to store the
+ * transfer state.
+ * @param xfer Pointer to FlexIO MCULCD transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_MCULCD_Busy FlexIO MCULCD is not idle, it is running another
+ * transfer.
+ */
+status_t FLEXIO_MCULCD_TransferSMARTDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_smartdma_handle_t *handle,
+ flexio_mculcd_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO MCULCD transfer using SMARTDMA.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle FlexIO MCULCD SMARTDMA handle pointer.
+ */
+void FLEXIO_MCULCD_TransferAbortSMARTDMA(FLEXIO_MCULCD_Type *base, flexio_mculcd_smartdma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes for FlexIO MCULCD SMARTDMA transfer.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle FlexIO MCULCD SMARTDMA handle pointer.
+ * @param count Number of count transferred so far by the SMARTDMA transaction.
+ * @retval kStatus_Success Get the transferred count Successfully.
+ * @retval kStatus_NoTransferInProgress No transfer in process.
+ */
+status_t FLEXIO_MCULCD_TransferGetCountSMARTDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_smartdma_handle_t *handle,
+ size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif /* _FSL_FLEXIO_MCULCD_SMARTDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.c
new file mode 100644
index 0000000000..06542d9120
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.c
@@ -0,0 +1,1553 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_spi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_spi"
+#endif
+
+/*! @brief FLEXIO SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
+enum _flexio_spi_transfer_states
+{
+ kFLEXIO_SPI_Idle = 0x0U, /*!< Nothing in the transmitter/receiver's queue. */
+ kFLEXIO_SPI_Busy, /*!< Transmiter/Receive's queue is not finished. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Send a piece of data for SPI.
+ *
+ * This function computes the number of data to be written into D register or Tx FIFO,
+ * and write the data into it. At the same time, this function updates the values in
+ * master handle structure.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure
+ * @param handle Pointer to SPI master handle structure.
+ */
+static void FLEXIO_SPI_TransferSendTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
+
+/*!
+ * @brief Receive a piece of data for SPI master.
+ *
+ * This function computes the number of data to receive from D register or Rx FIFO,
+ * and write the data to destination address. At the same time, this function updates
+ * the values in master handle structure.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure
+ * @param handle Pointer to SPI master handle structure.
+ */
+static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_SPI_GetInstance(FLEXIO_SPI_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static void FLEXIO_SPI_TransferSendTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ uint32_t tmpData = FLEXIO_SPI_DUMMYDATA;
+
+ if (handle->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (handle->bytePerFrame == 1U)
+ {
+ tmpData = (uint32_t) * (handle->txData);
+ handle->txData++;
+ }
+ else if (handle->bytePerFrame == 2U)
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(handle->txData[0]) << 8U;
+ tmpData += (uint32_t)handle->txData[1];
+ }
+ else
+ {
+ tmpData = (uint32_t)(handle->txData[1]) << 8U;
+ tmpData += (uint32_t)handle->txData[0];
+ }
+ handle->txData += 2U;
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(handle->txData[0]) << 24U;
+ tmpData += (uint32_t)(handle->txData[1]) << 16U;
+ tmpData += (uint32_t)(handle->txData[2]) << 8U;
+ tmpData += (uint32_t)handle->txData[3];
+ }
+ else
+ {
+ tmpData = (uint32_t)(handle->txData[3]) << 24U;
+ tmpData += (uint32_t)(handle->txData[2]) << 16U;
+ tmpData += (uint32_t)(handle->txData[1]) << 8U;
+ tmpData += (uint32_t)handle->txData[0];
+ }
+ handle->txData += 4U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ handle->txRemainingBytes -= handle->bytePerFrame;
+
+ FLEXIO_SPI_WriteData(base, handle->direction, tmpData);
+
+ if (0U == handle->txRemainingBytes)
+ {
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+ }
+}
+
+static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ uint32_t tmpData;
+
+ tmpData = FLEXIO_SPI_ReadData(base, handle->direction);
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->bytePerFrame == 1U)
+ {
+ *handle->rxData = (uint8_t)tmpData;
+ }
+ else if (handle->bytePerFrame == 2U)
+ {
+ if (handle->direction == kFLEXIO_SPI_LsbFirst)
+ {
+ *handle->rxData = (uint8_t)(tmpData >> 8);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *handle->rxData = (uint8_t)tmpData;
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 8);
+ }
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_LsbFirst)
+ {
+ *handle->rxData = (uint8_t)(tmpData >> 24U);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 16U);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 8U);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *handle->rxData = (uint8_t)tmpData;
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 8U);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 16U);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 24U);
+ }
+ }
+ handle->rxData++;
+ }
+ handle->rxRemainingBytes -= handle->bytePerFrame;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI master hardware,
+ * and configures the FlexIO SPI with FlexIO SPI master configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_MasterGetDefaultConfig().
+ *
+ * note 1.FlexIO SPI master only support CPOL = 0, which means clock inactive low.
+ * 2.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI master communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 2*2=4. If FlexIO SPI master communicates with FlexIO
+ * SPI slave, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ *
+ * Example
+ code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_spi_master_config_t config = {
+ .enableMaster = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 500000,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_MasterInit(&spiDev, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param masterConfig Pointer to the flexio_spi_master_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+*/
+void FLEXIO_SPI_MasterInit(FLEXIO_SPI_Type *base, flexio_spi_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(base != NULL);
+ assert(masterConfig != NULL);
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_SPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO SPI Master */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster));
+ if (!masterConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->SDOPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitLow;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDIPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 for SCK. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->SCKPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+ /* Low 8-bits are used to configure baudrate. */
+ timerDiv = (uint16_t)(srcClock_Hz / masterConfig->baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+ /* High 8-bits are used to configure shift clock edges(transfer width). */
+ timerCmp = ((uint16_t)masterConfig->dataMode * 2U - 1U) << 8U;
+ timerCmp |= timerDiv;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 4. Configure the timer 1 for CSn. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->timerIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->CSnPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ timerConfig.timerCompare = 0xFFFFU; /* Never compare. */
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+}
+
+/*!
+ * brief Resets the FlexIO SPI timer and shifter config.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_MasterDeinit(FLEXIO_SPI_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO SPI master. The configuration
+ * can be used directly by calling the FLEXIO_SPI_MasterConfigure().
+ * Example:
+ code
+ flexio_spi_master_config_t masterConfig;
+ FLEXIO_SPI_MasterGetDefaultConfig(&masterConfig);
+ endcode
+ * param masterConfig Pointer to the flexio_spi_master_config_t structure.
+*/
+void FLEXIO_SPI_MasterGetDefaultConfig(flexio_spi_master_config_t *masterConfig)
+{
+ assert(masterConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->enableInDoze = false;
+ masterConfig->enableInDebug = true;
+ masterConfig->enableFastAccess = false;
+ /* Default baud rate 500kbps. */
+ masterConfig->baudRate_Bps = 500000U;
+ /* Default CPHA = 0. */
+ masterConfig->phase = kFLEXIO_SPI_ClockPhaseFirstEdge;
+ /* Default bit count at 8. */
+ masterConfig->dataMode = kFLEXIO_SPI_8BitMode;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI slave hardware
+ * configuration, and configures the FlexIO SPI with FlexIO SPI slave configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_SlaveGetDefaultConfig().
+ *
+ * note 1.Only one timer is needed in the FlexIO SPI slave. As a result, the second timer index is ignored.
+ * 2.FlexIO SPI slave only support CPOL = 0, which means clock inactive low.
+ * 3.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI slave communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 3*2=6. If FlexIO SPI slave communicates with FlexIO
+ * SPI master, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ * Example
+ code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0}
+ };
+ flexio_spi_slave_config_t config = {
+ .enableSlave = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_SlaveInit(&spiDev, &config);
+ endcode
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveInit(FLEXIO_SPI_Type *base, flexio_spi_slave_config_t *slaveConfig)
+{
+ assert((base != NULL) && (slaveConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_SPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO SPI Slave */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(slaveConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(slaveConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(slaveConfig->enableSlave));
+ if (!slaveConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->SDOPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDIPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 for shift clock. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->CSnPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCKPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerRisingEdge;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ }
+ else
+ {
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTriggerFallingEdge;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+ }
+
+ timerConfig.timerCompare = (uint32_t)slaveConfig->dataMode * 2U - 1U;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+}
+
+/*!
+ * brief Gates the FlexIO clock.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_SlaveDeinit(FLEXIO_SPI_Type *base)
+{
+ FLEXIO_SPI_MasterDeinit(base);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO SPI slave. The configuration
+ * can be used directly for calling the FLEXIO_SPI_SlaveConfigure().
+ * Example:
+ code
+ flexio_spi_slave_config_t slaveConfig;
+ FLEXIO_SPI_SlaveGetDefaultConfig(&slaveConfig);
+ endcode
+ * param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveGetDefaultConfig(flexio_spi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->enableSlave = true;
+ slaveConfig->enableInDoze = false;
+ slaveConfig->enableInDebug = true;
+ slaveConfig->enableFastAccess = false;
+ /* Default CPHA = 0. */
+ slaveConfig->phase = kFLEXIO_SPI_ClockPhaseFirstEdge;
+ /* Default bit count at 8. */
+ slaveConfig->dataMode = kFLEXIO_SPI_8BitMode;
+}
+
+/*!
+ * brief Enables the FlexIO SPI interrupt.
+ *
+ * This function enables the FlexIO SPI interrupt.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask interrupt source. The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_RxFullInterruptEnable
+ * arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_EnableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO SPI interrupt.
+ *
+ * This function disables the FlexIO SPI interrupt.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask interrupt source The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_RxFullInterruptEnable
+ * arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_DisableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Enables/disables the FlexIO SPI transmit DMA. This function enables/disables the FlexIO SPI Tx DMA,
+ * which means that asserting the kFLEXIO_SPI_TxEmptyFlag does/doesn't trigger the DMA request.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask SPI DMA source.
+ * param enable True means enable DMA, false means disable DMA.
+ */
+void FLEXIO_SPI_EnableDMA(FLEXIO_SPI_Type *base, uint32_t mask, bool enable)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxDmaEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[0], enable);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxDmaEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[1], enable);
+ }
+}
+
+/*!
+ * brief Gets FlexIO SPI status flags.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * return status flag; Use the status flag to AND the following flag mask and get the status.
+ * arg kFLEXIO_SPI_TxEmptyFlag
+ * arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+uint32_t FLEXIO_SPI_GetStatusFlags(FLEXIO_SPI_Type *base)
+{
+ uint32_t shifterStatus = FLEXIO_GetShifterStatusFlags(base->flexioBase);
+ uint32_t status = 0;
+
+ status = ((shifterStatus & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |= (((shifterStatus & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1])) << 1U);
+
+ return status;
+}
+
+/*!
+ * brief Clears FlexIO SPI status flags.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask status flag
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_TxEmptyFlag
+ * arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+void FLEXIO_SPI_ClearStatusFlags(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sets baud rate for the FlexIO SPI transfer, which is only used for the master.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param baudRate_Bps Baud Rate needed in Hz.
+ * param srcClockHz SPI source clock frequency in Hz.
+ */
+void FLEXIO_SPI_MasterSetBaudRate(FLEXIO_SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClockHz)
+{
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Set TIMCMP[7:0] = (baud rate divider / 2) - 1.*/
+ timerDiv = (uint16_t)(srcClockHz / baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+
+ timerCmp = (uint16_t)(flexioBase->TIMCMP[base->timerIndex[0]]);
+ timerCmp &= 0xFF00U;
+ timerCmp |= timerDiv;
+
+ flexioBase->TIMCMP[base->timerIndex[0]] = timerCmp;
+}
+
+/*!
+ * brief Sends a buffer of data bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been sent.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param direction Shift direction of MSB first or LSB first.
+ * param buffer The data bytes to send.
+ * param size The number of data bytes to send.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_WriteBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ const uint8_t *buffer,
+ size_t size)
+{
+ assert(buffer != NULL);
+ assert(size != 0U);
+
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != size--)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ FLEXIO_SPI_WriteData(base, direction, *buffer++);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been received.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param direction Shift direction of MSB first or LSB first.
+ * param buffer The buffer to store the received bytes.
+ * param size The number of data bytes to be received.
+ * param direction Shift direction of MSB first or LSB first.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_ReadBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ uint8_t *buffer,
+ size_t size)
+{
+ assert(buffer != NULL);
+ assert(size != 0U);
+
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != size--)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ *buffer++ = (uint8_t)FLEXIO_SPI_ReadData(base, direction);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks via polling until all bytes have been received.
+ *
+ * param base pointer to FLEXIO_SPI_Type structure
+ * param xfer FlexIO SPI transfer structure, see #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_transfer_t *xfer)
+{
+ flexio_spi_shift_direction_t direction;
+ uint8_t bytesPerFrame;
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)(base->flexioBase->TIMCMP[base->timerIndex[0]]);
+ uint32_t tmpData = FLEXIO_SPI_DUMMYDATA;
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ timerCmp &= 0x00FFU;
+
+ if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
+ }
+ else
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
+ }
+
+ /* Configure the values in handle. */
+ switch (dataFormat)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_32bitMsb:
+ dataMode = (32UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 4U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_32bitLsb:
+ dataMode = (32UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 4U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+
+ default:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ dataMode |= timerCmp;
+
+ /* Transfer size should be bytesPerFrame divisible. */
+ if ((xfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ while (xfer->dataSize != 0U)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ if (xfer->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (bytesPerFrame == 1U)
+ {
+ tmpData = (uint32_t) * (xfer->txData);
+ xfer->txData++;
+ }
+ else if (bytesPerFrame == 2U)
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(xfer->txData[0]) << 8U;
+ tmpData += (uint32_t)xfer->txData[1];
+ }
+ else
+ {
+ tmpData = (uint32_t)(xfer->txData[1]) << 8U;
+ tmpData += (uint32_t)xfer->txData[0];
+ }
+ xfer->txData += 2U;
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(xfer->txData[0]) << 24U;
+ tmpData += (uint32_t)(xfer->txData[1]) << 16U;
+ tmpData += (uint32_t)(xfer->txData[2]) << 8U;
+ tmpData += (uint32_t)xfer->txData[3];
+ }
+ else
+ {
+ tmpData = (uint32_t)(xfer->txData[3]) << 24U;
+ tmpData += (uint32_t)(xfer->txData[2]) << 16U;
+ tmpData += (uint32_t)(xfer->txData[1]) << 8U;
+ tmpData += (uint32_t)xfer->txData[0];
+ }
+ xfer->txData += 4U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ xfer->dataSize -= bytesPerFrame;
+
+ FLEXIO_SPI_WriteData(base, direction, tmpData);
+
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ tmpData = FLEXIO_SPI_ReadData(base, direction);
+
+ if (xfer->rxData != NULL)
+ {
+ if (bytesPerFrame == 1U)
+ {
+ *xfer->rxData = (uint8_t)tmpData;
+ }
+ else if (bytesPerFrame == 2U)
+ {
+ if (direction == kFLEXIO_SPI_LsbFirst)
+ {
+ *xfer->rxData = (uint8_t)(tmpData >> 8);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *xfer->rxData = (uint8_t)tmpData;
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 8);
+ }
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_LsbFirst)
+ {
+ *xfer->rxData = (uint8_t)(tmpData >> 24U);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 16U);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 8U);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *xfer->rxData = (uint8_t)tmpData;
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 8U);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 16U);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 24U);
+ }
+ }
+ xfer->rxData++;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the FlexIO SPI Master handle, which is used in transactional functions.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Clear pending NVIC IRQ before enable NVIC IRQ. */
+ NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_SPI_MasterTransferHandleIRQ);
+}
+
+/*!
+ * brief Master transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
+ uint32_t tmpData = FLEXIO_SPI_DUMMYDATA;
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+
+ timerCmp &= 0x00FFU;
+
+ /* Check if SPI is busy. */
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Busy)
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if the argument is legal. */
+ if ((xfer->txData == NULL) && (xfer->rxData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Timer1 controls the CS signal which enables/disables(asserts/deasserts) when timer0 enable/disable. Timer0
+ enables when tx shifter is written and disables when timer compare. The timer compare event causes the
+ transmit shift registers to load which generates a tx register empty event. Since when timer stop bit is
+ disabled, a timer enable condition can be detected in the same cycle as a timer disable condition, so if
+ software writes the tx register upon the detection of tx register empty event, the timer enable condition
+ is triggered again, then the CS signal can remain low until software no longer writes the tx register. */
+ if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
+ }
+ else
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
+ }
+
+ /* Configure the values in handle */
+ switch (dataFormat)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitMsb:
+ dataMode = (32UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 4U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitLsb:
+ dataMode = (32UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 4U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ dataMode |= timerCmp;
+
+ /* Transfer size should be bytesPerFrame divisible. */
+ if ((xfer->dataSize % handle->bytePerFrame) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ handle->state = (uint32_t)kFLEXIO_SPI_Busy;
+ handle->txData = xfer->txData;
+ handle->rxData = xfer->rxData;
+ handle->rxRemainingBytes = xfer->dataSize;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Send first byte of data to trigger the rx interrupt. */
+ if (handle->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (handle->bytePerFrame == 1U)
+ {
+ tmpData = (uint32_t) * (handle->txData);
+ handle->txData++;
+ }
+ else if (handle->bytePerFrame == 2U)
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(handle->txData[0]) << 8U;
+ tmpData += (uint32_t)handle->txData[1];
+ }
+ else
+ {
+ tmpData = (uint32_t)(handle->txData[1]) << 8U;
+ tmpData += (uint32_t)handle->txData[0];
+ }
+ handle->txData += 2U;
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint32_t)(handle->txData[0]) << 24U;
+ tmpData += (uint32_t)(handle->txData[1]) << 16U;
+ tmpData += (uint32_t)(handle->txData[2]) << 8U;
+ tmpData += (uint32_t)handle->txData[3];
+ }
+ else
+ {
+ tmpData = (uint32_t)(handle->txData[3]) << 24U;
+ tmpData += (uint32_t)(handle->txData[2]) << 16U;
+ tmpData += (uint32_t)(handle->txData[1]) << 8U;
+ tmpData += (uint32_t)handle->txData[0];
+ }
+ handle->txData += 4U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ handle->txRemainingBytes = xfer->dataSize - handle->bytePerFrame;
+
+ FLEXIO_SPI_WriteData(base, handle->direction, tmpData);
+
+ /* Enable transmit and receive interrupt to handle rx. */
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the data transfer status which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCount(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return remaing bytes in different cases. */
+ if (handle->rxData != NULL)
+ {
+ *count = handle->transferSize - handle->rxRemainingBytes;
+ }
+ else
+ {
+ *count = handle->transferSize - handle->txRemainingBytes;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the master data transfer, which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferAbort(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+
+ /* Transfer finished, set the state to idle. */
+ handle->state = (uint32_t)kFLEXIO_SPI_Idle;
+
+ /* Clear the internal state. */
+ handle->rxRemainingBytes = 0;
+ handle->txRemainingBytes = 0;
+}
+
+/*!
+ * brief FlexIO SPI master IRQ handler function.
+ *
+ * param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * param spiHandle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferHandleIRQ(void *spiType, void *spiHandle)
+{
+ assert(spiHandle != NULL);
+
+ flexio_spi_master_handle_t *handle = (flexio_spi_master_handle_t *)spiHandle;
+ FLEXIO_SPI_Type *base;
+ uint32_t status;
+
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Idle)
+ {
+ return;
+ }
+
+ base = (FLEXIO_SPI_Type *)spiType;
+ status = FLEXIO_SPI_GetStatusFlags(base);
+
+ /* Handle rx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U) && (handle->rxRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferReceiveTransaction(base, handle);
+ }
+
+ /* Handle tx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U) && (handle->txRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferSendTransaction(base, handle);
+ }
+
+ /* All the transfer finished. */
+ if ((handle->txRemainingBytes == 0U) && (handle->rxRemainingBytes == 0U))
+ {
+ FLEXIO_SPI_MasterTransferAbort(base, handle);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_FLEXIO_SPI_Idle, handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO SPI Slave handle, which is used in transactional functions.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_SlaveTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Clear pending NVIC IRQ before enable NVIC IRQ. */
+ NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_SPI_SlaveTransferHandleIRQ);
+}
+
+/*!
+ * brief Slave transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ * param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy SPI is not idle; it is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+
+ /* Check if SPI is busy. */
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Busy)
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if the argument is legal. */
+ if ((xfer->txData == NULL) && (xfer->rxData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* SCK timer use CS pin as inverted trigger so timer should be disbaled on trigger falling edge(CS re-asserts). */
+ /* However if CPHA is first edge mode, timer will restart each time right after timer compare event occur and
+ before CS pin re-asserts, which triggers another shifter load. To avoid this, when in CS dis-continuous mode,
+ timer should disable in timer compare rather than trigger falling edge(CS re-asserts), and in CS continuous mode,
+ tx/rx shifters should be flushed after transfer finishes and before next transfer starts. */
+ FLEXIO_SPI_FlushShifters(base);
+ if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
+ }
+ else
+ {
+ if ((base->flexioBase->SHIFTCTL[base->shifterIndex[0]] & FLEXIO_SHIFTCTL_TIMPOL_MASK) ==
+ FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive))
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
+ FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare);
+ }
+ else
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
+ FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
+ }
+ }
+
+ /* Configure the values in handle */
+ switch (dataFormat)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = 8U * 2U - 1U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = 8U * 2U - 1U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = 16U * 2U - 1U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = 16U * 2U - 1U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitMsb:
+ dataMode = 32UL * 2UL - 1UL;
+ handle->bytePerFrame = 4U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitLsb:
+ dataMode = 32UL * 2UL - 1UL;
+ handle->bytePerFrame = 4U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ dataMode = 8UL * 2UL - 1UL;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ /* Transfer size should be bytesPerFrame divisible. */
+ if ((xfer->dataSize % handle->bytePerFrame) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ handle->state = (uint32_t)kFLEXIO_SPI_Busy;
+ handle->txData = xfer->txData;
+ handle->rxData = xfer->rxData;
+ handle->txRemainingBytes = xfer->dataSize;
+ handle->rxRemainingBytes = xfer->dataSize;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Enable transmit and receive interrupt to handle tx and rx. */
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief FlexIO SPI slave IRQ handler function.
+ *
+ * param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * param spiHandle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_SlaveTransferHandleIRQ(void *spiType, void *spiHandle)
+{
+ assert(spiHandle != NULL);
+
+ flexio_spi_master_handle_t *handle = (flexio_spi_master_handle_t *)spiHandle;
+ FLEXIO_SPI_Type *base;
+ uint32_t status;
+
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Idle)
+ {
+ return;
+ }
+
+ base = (FLEXIO_SPI_Type *)spiType;
+ status = FLEXIO_SPI_GetStatusFlags(base);
+
+ /* Handle tx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U) && (handle->txRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferSendTransaction(base, handle);
+ }
+
+ /* Handle rx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U) && (handle->rxRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferReceiveTransaction(base, handle);
+ }
+
+ /* All the transfer finished. */
+ if ((handle->txRemainingBytes == 0U) && (handle->rxRemainingBytes == 0U))
+ {
+ FLEXIO_SPI_SlaveTransferAbort(base, handle);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_FLEXIO_SPI_Idle, handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Flush tx/rx shifters.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ */
+void FLEXIO_SPI_FlushShifters(FLEXIO_SPI_Type *base)
+{
+ /* Disable then re-enable to flush the tx shifter. */
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] &= ~FLEXIO_SHIFTCTL_SMOD_MASK;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] |= FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
+ /* Read to flush the rx shifter. */
+ (void)base->flexioBase->SHIFTBUF[base->shifterIndex[1]];
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.h
new file mode 100644
index 0000000000..61c1034fc2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi.h
@@ -0,0 +1,719 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_SPI_H_
+#define _FSL_FLEXIO_SPI_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+
+/*!
+ * @addtogroup flexio_spi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO SPI driver version. */
+#define FSL_FLEXIO_SPI_DRIVER_VERSION (MAKE_VERSION(2, 3, 0))
+/*@}*/
+
+#ifndef FLEXIO_SPI_DUMMYDATA
+/*! @brief FlexIO SPI dummy transfer data, the data is sent while txData is NULL. */
+#define FLEXIO_SPI_DUMMYDATA (0xFFFFFFFFU)
+#endif
+
+/*! @brief Retry times for waiting flag. */
+#ifndef SPI_RETRY_TIMES
+#define SPI_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief Get the transfer data format of width and bit order. */
+#define FLEXIO_SPI_XFER_DATA_FORMAT(flag) ((flag) & (0x7U))
+
+/*! @brief Error codes for the FlexIO SPI driver. */
+enum
+{
+ kStatus_FLEXIO_SPI_Busy = MAKE_STATUS(kStatusGroup_FLEXIO_SPI, 1), /*!< FlexIO SPI is busy. */
+ kStatus_FLEXIO_SPI_Idle = MAKE_STATUS(kStatusGroup_FLEXIO_SPI, 2), /*!< SPI is idle */
+ kStatus_FLEXIO_SPI_Error = MAKE_STATUS(kStatusGroup_FLEXIO_SPI, 3), /*!< FlexIO SPI error. */
+ kStatus_FLEXIO_SPI_Timeout =
+ MAKE_STATUS(kStatusGroup_FLEXIO_SPI, 4), /*!< FlexIO SPI timeout polling status flags. */
+};
+
+/*! @brief FlexIO SPI clock phase configuration. */
+typedef enum _flexio_spi_clock_phase
+{
+ kFLEXIO_SPI_ClockPhaseFirstEdge = 0x0U, /*!< First edge on SPSCK occurs at the middle of the first
+ * cycle of a data transfer. */
+ kFLEXIO_SPI_ClockPhaseSecondEdge = 0x1U, /*!< First edge on SPSCK occurs at the start of the
+ * first cycle of a data transfer. */
+} flexio_spi_clock_phase_t;
+
+/*! @brief FlexIO SPI data shifter direction options. */
+typedef enum _flexio_spi_shift_direction
+{
+ kFLEXIO_SPI_MsbFirst = 0, /*!< Data transfers start with most significant bit. */
+ kFLEXIO_SPI_LsbFirst = 1, /*!< Data transfers start with least significant bit. */
+} flexio_spi_shift_direction_t;
+
+/*! @brief FlexIO SPI data length mode options. */
+typedef enum _flexio_spi_data_bitcount_mode
+{
+ kFLEXIO_SPI_8BitMode = 0x08U, /*!< 8-bit data transmission mode. */
+ kFLEXIO_SPI_16BitMode = 0x10U, /*!< 16-bit data transmission mode. */
+ kFLEXIO_SPI_32BitMode = 0x20U, /*!< 32-bit data transmission mode. */
+} flexio_spi_data_bitcount_mode_t;
+
+/*! @brief Define FlexIO SPI interrupt mask. */
+enum _flexio_spi_interrupt_enable
+{
+ kFLEXIO_SPI_TxEmptyInterruptEnable = 0x1U, /*!< Transmit buffer empty interrupt enable. */
+ kFLEXIO_SPI_RxFullInterruptEnable = 0x2U, /*!< Receive buffer full interrupt enable. */
+};
+
+/*! @brief Define FlexIO SPI status mask. */
+enum _flexio_spi_status_flags
+{
+ kFLEXIO_SPI_TxBufferEmptyFlag = 0x1U, /*!< Transmit buffer empty flag. */
+ kFLEXIO_SPI_RxBufferFullFlag = 0x2U, /*!< Receive buffer full flag. */
+};
+
+/*! @brief Define FlexIO SPI DMA mask. */
+enum _flexio_spi_dma_enable
+{
+ kFLEXIO_SPI_TxDmaEnable = 0x1U, /*!< Tx DMA request source */
+ kFLEXIO_SPI_RxDmaEnable = 0x2U, /*!< Rx DMA request source */
+ kFLEXIO_SPI_DmaAllEnable = 0x3U, /*!< All DMA request source*/
+};
+
+/*! @brief Define FlexIO SPI transfer flags.
+ * @note Use kFLEXIO_SPI_csContinuous and one of the other flags to OR together to form the transfer flag. */
+enum _flexio_spi_transfer_flags
+{
+ kFLEXIO_SPI_8bitMsb = 0x0U, /*!< FlexIO SPI 8-bit MSB first */
+ kFLEXIO_SPI_8bitLsb = 0x1U, /*!< FlexIO SPI 8-bit LSB first */
+ kFLEXIO_SPI_16bitMsb = 0x2U, /*!< FlexIO SPI 16-bit MSB first */
+ kFLEXIO_SPI_16bitLsb = 0x3U, /*!< FlexIO SPI 16-bit LSB first */
+ kFLEXIO_SPI_32bitMsb = 0x4U, /*!< FlexIO SPI 32-bit MSB first */
+ kFLEXIO_SPI_32bitLsb = 0x5U, /*!< FlexIO SPI 32-bit LSB first */
+ kFLEXIO_SPI_csContinuous = 0x8U, /*!< Enable the CS signal continuous mode */
+};
+
+/*! @brief Define FlexIO SPI access structure typedef. */
+typedef struct _flexio_spi_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO base pointer. */
+ uint8_t SDOPinIndex; /*!< Pin select for data output. To set SDO pin in Hi-Z state, user needs to mux the pin as
+ GPIO input and disable all pull up/down in application. */
+ uint8_t SDIPinIndex; /*!< Pin select for data input. */
+ uint8_t SCKPinIndex; /*!< Pin select for clock. */
+ uint8_t CSnPinIndex; /*!< Pin select for enable. */
+ uint8_t shifterIndex[2]; /*!< Shifter index used in FlexIO SPI. */
+ uint8_t timerIndex[2]; /*!< Timer index used in FlexIO SPI. */
+} FLEXIO_SPI_Type;
+
+/*! @brief Define FlexIO SPI master configuration structure. */
+typedef struct _flexio_spi_master_config
+{
+ bool enableMaster; /*!< Enable/disable FlexIO SPI master after configuration. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode. */
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode. */
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers,
+ fast access requires the FlexIO clock to be at least
+ twice the frequency of the bus clock. */
+ uint32_t baudRate_Bps; /*!< Baud rate in Bps. */
+ flexio_spi_clock_phase_t phase; /*!< Clock phase. */
+ flexio_spi_data_bitcount_mode_t dataMode; /*!< 8bit or 16bit mode. */
+} flexio_spi_master_config_t;
+
+/*! @brief Define FlexIO SPI slave configuration structure. */
+typedef struct _flexio_spi_slave_config
+{
+ bool enableSlave; /*!< Enable/disable FlexIO SPI slave after configuration. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode. */
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode. */
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers,
+ fast access requires the FlexIO clock to be at least
+ twice the frequency of the bus clock. */
+ flexio_spi_clock_phase_t phase; /*!< Clock phase. */
+ flexio_spi_data_bitcount_mode_t dataMode; /*!< 8bit or 16bit mode. */
+} flexio_spi_slave_config_t;
+
+/*! @brief Define FlexIO SPI transfer structure. */
+typedef struct _flexio_spi_transfer
+{
+ uint8_t *txData; /*!< Send buffer. */
+ uint8_t *rxData; /*!< Receive buffer. */
+ size_t dataSize; /*!< Transfer bytes. */
+ uint8_t flags; /*!< FlexIO SPI control flag, MSB first or LSB first. */
+} flexio_spi_transfer_t;
+
+/*! @brief typedef for flexio_spi_master_handle_t in advance. */
+typedef struct _flexio_spi_master_handle flexio_spi_master_handle_t;
+
+/*! @brief Slave handle is the same with master handle. */
+typedef flexio_spi_master_handle_t flexio_spi_slave_handle_t;
+
+/*! @brief FlexIO SPI master callback for finished transmit */
+typedef void (*flexio_spi_master_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO SPI slave callback for finished transmit */
+typedef void (*flexio_spi_slave_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Define FlexIO SPI handle structure. */
+struct _flexio_spi_master_handle
+{
+ uint8_t *txData; /*!< Transfer buffer. */
+ uint8_t *rxData; /*!< Receive buffer. */
+ size_t transferSize; /*!< Total bytes to be transferred. */
+ volatile size_t txRemainingBytes; /*!< Send data remaining in bytes. */
+ volatile size_t rxRemainingBytes; /*!< Receive data remaining in bytes. */
+ volatile uint32_t state; /*!< FlexIO SPI internal state. */
+ uint8_t bytePerFrame; /*!< SPI mode, 2bytes or 1byte in a frame */
+ flexio_spi_shift_direction_t direction; /*!< Shift direction. */
+ flexio_spi_master_transfer_callback_t callback; /*!< FlexIO SPI callback. */
+ void *userData; /*!< Callback parameter. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name FlexIO SPI Configuration
+ * @{
+ */
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI master hardware,
+ * and configures the FlexIO SPI with FlexIO SPI master configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_MasterGetDefaultConfig().
+ *
+ * @note 1.FlexIO SPI master only support CPOL = 0, which means clock inactive low.
+ * 2.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI master communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 2*2=4. If FlexIO SPI master communicates with FlexIO
+ * SPI slave, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ *
+ * Example
+ @code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_spi_master_config_t config = {
+ .enableMaster = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 500000,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_MasterInit(&spiDev, &config, srcClock_Hz);
+ @endcode
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param masterConfig Pointer to the flexio_spi_master_config_t structure.
+ * @param srcClock_Hz FlexIO source clock in Hz.
+*/
+void FLEXIO_SPI_MasterInit(FLEXIO_SPI_Type *base, flexio_spi_master_config_t *masterConfig, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Resets the FlexIO SPI timer and shifter config.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_MasterDeinit(FLEXIO_SPI_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO SPI master. The configuration
+ * can be used directly by calling the FLEXIO_SPI_MasterConfigure().
+ * Example:
+ @code
+ flexio_spi_master_config_t masterConfig;
+ FLEXIO_SPI_MasterGetDefaultConfig(&masterConfig);
+ @endcode
+ * @param masterConfig Pointer to the flexio_spi_master_config_t structure.
+*/
+void FLEXIO_SPI_MasterGetDefaultConfig(flexio_spi_master_config_t *masterConfig);
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI slave hardware
+ * configuration, and configures the FlexIO SPI with FlexIO SPI slave configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_SlaveGetDefaultConfig().
+ *
+ * @note 1.Only one timer is needed in the FlexIO SPI slave. As a result, the second timer index is ignored.
+ * 2.FlexIO SPI slave only support CPOL = 0, which means clock inactive low.
+ * 3.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI slave communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 3*2=6. If FlexIO SPI slave communicates with FlexIO
+ * SPI master, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ * Example
+ @code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0}
+ };
+ flexio_spi_slave_config_t config = {
+ .enableSlave = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_SlaveInit(&spiDev, &config);
+ @endcode
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveInit(FLEXIO_SPI_Type *base, flexio_spi_slave_config_t *slaveConfig);
+
+/*!
+ * @brief Gates the FlexIO clock.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_SlaveDeinit(FLEXIO_SPI_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO SPI slave. The configuration
+ * can be used directly for calling the FLEXIO_SPI_SlaveConfigure().
+ * Example:
+ @code
+ flexio_spi_slave_config_t slaveConfig;
+ FLEXIO_SPI_SlaveGetDefaultConfig(&slaveConfig);
+ @endcode
+ * @param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveGetDefaultConfig(flexio_spi_slave_config_t *slaveConfig);
+
+/*@}*/
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets FlexIO SPI status flags.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @return status flag; Use the status flag to AND the following flag mask and get the status.
+ * @arg kFLEXIO_SPI_TxEmptyFlag
+ * @arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+uint32_t FLEXIO_SPI_GetStatusFlags(FLEXIO_SPI_Type *base);
+
+/*!
+ * @brief Clears FlexIO SPI status flags.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param mask status flag
+ * The parameter can be any combination of the following values:
+ * @arg kFLEXIO_SPI_TxEmptyFlag
+ * @arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+void FLEXIO_SPI_ClearStatusFlags(FLEXIO_SPI_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the FlexIO SPI interrupt.
+ *
+ * This function enables the FlexIO SPI interrupt.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param mask interrupt source. The parameter can be any combination of the following values:
+ * @arg kFLEXIO_SPI_RxFullInterruptEnable
+ * @arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_EnableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the FlexIO SPI interrupt.
+ *
+ * This function disables the FlexIO SPI interrupt.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param mask interrupt source The parameter can be any combination of the following values:
+ * @arg kFLEXIO_SPI_RxFullInterruptEnable
+ * @arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_DisableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask);
+
+/*@}*/
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO SPI transmit DMA. This function enables/disables the FlexIO SPI Tx DMA,
+ * which means that asserting the kFLEXIO_SPI_TxEmptyFlag does/doesn't trigger the DMA request.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param mask SPI DMA source.
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+void FLEXIO_SPI_EnableDMA(FLEXIO_SPI_Type *base, uint32_t mask, bool enable);
+
+/*!
+ * @brief Gets the FlexIO SPI transmit data register address for MSB first transfer.
+ *
+ * This function returns the SPI data register address, which is mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @return FlexIO SPI transmit data register address.
+ */
+static inline uint32_t FLEXIO_SPI_GetTxDataRegisterAddress(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction)
+{
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBufferBitSwapped,
+ base->shifterIndex[0]) +
+ 3U;
+ }
+ else
+ {
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBuffer, base->shifterIndex[0]);
+ }
+}
+
+/*!
+ * @brief Gets the FlexIO SPI receive data register address for the MSB first transfer.
+ *
+ * This function returns the SPI data register address, which is mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @return FlexIO SPI receive data register address.
+ */
+static inline uint32_t FLEXIO_SPI_GetRxDataRegisterAddress(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction)
+{
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBufferBitSwapped, base->shifterIndex[1]);
+ }
+ else
+ {
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBuffer, base->shifterIndex[1]) + 3U;
+ }
+}
+
+/*@}*/
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO SPI module operation.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type.
+ * @param enable True to enable, false does not have any effect.
+ */
+static inline void FLEXIO_SPI_Enable(FLEXIO_SPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*!
+ * @brief Sets baud rate for the FlexIO SPI transfer, which is only used for the master.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param baudRate_Bps Baud Rate needed in Hz.
+ * @param srcClockHz SPI source clock frequency in Hz.
+ */
+void FLEXIO_SPI_MasterSetBaudRate(FLEXIO_SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClockHz);
+
+/*!
+ * @brief Writes one byte of data, which is sent using the MSB method.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is put into the
+ * data register but the data transfer is not finished on the bus. Ensure that
+ * the TxEmptyFlag is asserted before calling this API.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @param data 8/16/32 bit data.
+ */
+static inline void FLEXIO_SPI_WriteData(FLEXIO_SPI_Type *base, flexio_spi_shift_direction_t direction, uint32_t data)
+{
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ base->flexioBase->SHIFTBUFBBS[base->shifterIndex[0]] = data;
+ }
+ else
+ {
+ base->flexioBase->SHIFTBUF[base->shifterIndex[0]] = data;
+ }
+}
+
+/*!
+ * @brief Reads 8 bit/16 bit data.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is read from the
+ * data register. Ensure that the RxFullFlag is asserted before calling this API.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @return 8 bit/16 bit data received.
+ */
+static inline uint32_t FLEXIO_SPI_ReadData(FLEXIO_SPI_Type *base, flexio_spi_shift_direction_t direction)
+{
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ return (uint32_t)(base->flexioBase->SHIFTBUFBIS[base->shifterIndex[1]]);
+ }
+ else
+ {
+ return (uint32_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+ }
+}
+
+/*!
+ * @brief Sends a buffer of data bytes.
+ *
+ * @note This function blocks using the polling method until all bytes have been sent.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @param buffer The data bytes to send.
+ * @param size The number of data bytes to send.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_WriteBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ const uint8_t *buffer,
+ size_t size);
+
+/*!
+ * @brief Receives a buffer of bytes.
+ *
+ * @note This function blocks using the polling method until all bytes have been received.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @param buffer The buffer to store the received bytes.
+ * @param size The number of data bytes to be received.
+ * @param direction Shift direction of MSB first or LSB first.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_ReadBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ uint8_t *buffer,
+ size_t size);
+
+/*!
+ * @brief Receives a buffer of bytes.
+ *
+ * @note This function blocks via polling until all bytes have been received.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure
+ * @param xfer FlexIO SPI transfer structure, see #flexio_spi_transfer_t.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Flush tx/rx shifters.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ */
+void FLEXIO_SPI_FlushShifters(FLEXIO_SPI_Type *base);
+/*@}*/
+
+/*Transactional APIs*/
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO SPI Master handle, which is used in transactional functions.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_master_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Master transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * @param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the master data transfer, which used IRQ.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferAbort(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
+
+/*!
+ * @brief Gets the data transfer status which used IRQ.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCount(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle, size_t *count);
+
+/*!
+ * @brief FlexIO SPI master IRQ handler function.
+ *
+ * @param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * @param spiHandle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferHandleIRQ(void *spiType, void *spiHandle);
+
+/*!
+ * @brief Initializes the FlexIO SPI Slave handle, which is used in transactional functions.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_SlaveTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_slave_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Slave transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ * @param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy SPI is not idle; it is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the slave data transfer which used IRQ, share same API with master.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ */
+static inline void FLEXIO_SPI_SlaveTransferAbort(FLEXIO_SPI_Type *base, flexio_spi_slave_handle_t *handle)
+{
+ FLEXIO_SPI_MasterTransferAbort(base, handle);
+}
+/*!
+ * @brief Gets the data transfer status which used IRQ, share same API with master.
+ *
+ * @param base Pointer to the FLEXIO_SPI_Type structure.
+ * @param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+static inline status_t FLEXIO_SPI_SlaveTransferGetCount(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ size_t *count)
+{
+ return FLEXIO_SPI_MasterTransferGetCount(base, handle, count);
+}
+
+/*!
+ * @brief FlexIO SPI slave IRQ handler function.
+ *
+ * @param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * @param spiHandle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_SlaveTransferHandleIRQ(void *spiType, void *spiHandle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /*_FSL_FLEXIO_SPI_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_dma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_dma.h
new file mode 100644
index 0000000000..a8087a5210
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_dma.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_SPI_DMA_H_
+#define _FSL_FLEXIO_SPI_DMA_H_
+
+#include "fsl_flexio_spi.h"
+#include "fsl_dma.h"
+
+/*!
+ * @addtogroup flexio_dma_spi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO SPI DMA driver version 2.3.0. */
+#define FSL_FLEXIO_SPI_DMA_DRIVER_VERSION (MAKE_VERSION(2, 3, 0))
+/*@}*/
+
+/*! @brief typedef for flexio_spi_master_dma_handle_t in advance. */
+typedef struct _flexio_spi_master_dma_handle flexio_spi_master_dma_handle_t;
+
+/*! @brief Slave handle is the same with master handle. */
+typedef flexio_spi_master_dma_handle_t flexio_spi_slave_dma_handle_t;
+
+/*! @brief FlexIO SPI master callback for finished transmit */
+typedef void (*flexio_spi_master_dma_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_master_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO SPI slave callback for finished transmit */
+typedef void (*flexio_spi_slave_dma_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO SPI DMA transfer handle, users should not touch the content of the handle.*/
+struct _flexio_spi_master_dma_handle
+{
+ size_t transferSize; /*!< Total bytes to be transferred. */
+ bool txInProgress; /*!< Send transfer in progress */
+ bool rxInProgress; /*!< Receive transfer in progress */
+ dma_handle_t *txHandle; /*!< DMA handler for SPI send */
+ dma_handle_t *rxHandle; /*!< DMA handler for SPI receive */
+ flexio_spi_master_dma_transfer_callback_t callback; /*!< Callback for SPI DMA transfer */
+ void *userData; /*!< User Data for SPI DMA callback */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name DMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXO SPI master DMA handle.
+ *
+ * This function initializes the FLEXO SPI master DMA handle which can be used for other FLEXO SPI master transactional
+ * APIs.
+ * Usually, for a specified FLEXO SPI instance, call this API once to get the initialized handle.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_master_dma_handle_t structure to store the transfer state.
+ * @param callback SPI callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @param txHandle User requested DMA handle for FlexIO SPI RX DMA transfer.
+ * @param rxHandle User requested DMA handle for FlexIO SPI TX DMA transfer.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO SPI DMA type/handle table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandleDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_dma_handle_t *handle,
+ flexio_spi_master_dma_transfer_callback_t callback,
+ void *userData,
+ dma_handle_t *txHandle,
+ dma_handle_t *rxHandle);
+
+/*!
+ * @brief Performs a non-blocking FlexIO SPI transfer using DMA.
+ *
+ * @note This interface returned immediately after transfer initiates. Call
+ * FLEXIO_SPI_MasterGetTransferCountDMA to poll the transfer status to check
+ * whether the FlexIO SPI transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_master_dma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to FlexIO SPI transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_dma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO SPI transfer using DMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI DMA handle pointer.
+ */
+void FLEXIO_SPI_MasterTransferAbortDMA(FLEXIO_SPI_Type *base, flexio_spi_master_dma_handle_t *handle);
+
+/*!
+ * @brief Gets the remaining bytes for FlexIO SPI DMA transfer.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI DMA handle pointer.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCountDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_dma_handle_t *handle,
+ size_t *count);
+
+/*!
+ * @brief Initializes the FlexIO SPI slave DMA handle.
+ *
+ * This function initializes the FlexIO SPI slave DMA handle.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_dma_handle_t structure to store the transfer state.
+ * @param callback SPI callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @param txHandle User requested DMA handle for FlexIO SPI TX DMA transfer.
+ * @param rxHandle User requested DMA handle for FlexIO SPI RX DMA transfer.
+ */
+static inline void FLEXIO_SPI_SlaveTransferCreateHandleDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_dma_handle_t *handle,
+ flexio_spi_slave_dma_transfer_callback_t callback,
+ void *userData,
+ dma_handle_t *txHandle,
+ dma_handle_t *rxHandle)
+{
+ (void)FLEXIO_SPI_MasterTransferCreateHandleDMA(base, handle, callback, userData, txHandle, rxHandle);
+}
+
+/*!
+ * @brief Performs a non-blocking FlexIO SPI transfer using DMA.
+ *
+ * @note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_SlaveGetTransferCountDMA to poll the transfer status and
+ * check whether the FlexIO SPI transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_dma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to FlexIO SPI transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_dma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO SPI transfer using DMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_dma_handle_t structure to store the transfer state.
+ */
+static inline void FLEXIO_SPI_SlaveTransferAbortDMA(FLEXIO_SPI_Type *base, flexio_spi_slave_dma_handle_t *handle)
+{
+ FLEXIO_SPI_MasterTransferAbortDMA(base, handle);
+}
+
+/*!
+ * @brief Gets the remaining bytes to be transferred for FlexIO SPI DMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI DMA handle pointer.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+static inline status_t FLEXIO_SPI_SlaveTransferGetCountDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_dma_handle_t *handle,
+ size_t *count)
+{
+ return FLEXIO_SPI_MasterTransferGetCountDMA(base, handle, count);
+}
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.c
new file mode 100644
index 0000000000..c1feba0f00
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_spi_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_spi_edma"
+#endif
+
+/*<! Structure definition for spi_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_spi_master_edma_private_handle
+{
+ FLEXIO_SPI_Type *base;
+ flexio_spi_master_edma_handle_t *handle;
+} flexio_spi_master_edma_private_handle_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief EDMA callback function for FLEXIO SPI send transfer.
+ *
+ * @param handle EDMA handle pointer.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief EDMA callback function for FLEXIO SPI receive transfer.
+ *
+ * @param handle EDMA handle pointer.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief EDMA config for FLEXIO SPI transfer.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure.
+ * @param handle pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to flexio spi transfer structure.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_InvalidArgument The transfer size is not supported.
+ */
+static status_t FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Dummy data used to send */
+static const uint32_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
+
+/*< @brief user configurable flexio spi handle count. */
+#define FLEXIO_SPI_HANDLE_COUNT 2
+
+/*<! Private handle only used for internally. */
+static flexio_spi_master_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
+
+ /* Disable Tx DMA */
+ if (transferDone)
+ {
+ FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, false);
+
+ /* change the state */
+ spiPrivateHandle->handle->txInProgress = false;
+
+ /* All finished, call the callback */
+ if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
+ {
+ if (spiPrivateHandle->handle->callback != NULL)
+ {
+ (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
+ spiPrivateHandle->handle->userData);
+ }
+ }
+ }
+}
+
+static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
+
+ if (transferDone)
+ {
+ /* Disable Rx dma */
+ FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, false);
+
+ /* change the state */
+ spiPrivateHandle->handle->rxInProgress = false;
+
+ /* All finished, call the callback */
+ if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
+ {
+ if (spiPrivateHandle->handle->callback != NULL)
+ {
+ (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
+ spiPrivateHandle->handle->userData);
+ }
+ }
+ }
+}
+
+static status_t FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ edma_transfer_config_t xferConfig = {0};
+ flexio_spi_shift_direction_t direction = kFLEXIO_SPI_MsbFirst;
+ uint8_t bytesPerFrame;
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+
+ /* Configure the values in handle. */
+ switch (dataFormat)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitMsb:
+ bytesPerFrame = 4U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_32bitLsb:
+ bytesPerFrame = 4U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ /* Transfer size should be bytesPerFrame divisible. */
+ if ((xfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Configure tx transfer EDMA. */
+ xferConfig.destAddr = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
+ xferConfig.destOffset = 0;
+ if (bytesPerFrame == 1U)
+ {
+ xferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ xferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ xferConfig.minorLoopBytes = 1U;
+ }
+ else if (bytesPerFrame == 2U)
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ xferConfig.destAddr -= 1U;
+ }
+ xferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
+ xferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
+ xferConfig.minorLoopBytes = 2U;
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ xferConfig.destAddr -= 3U;
+ }
+ xferConfig.srcTransferSize = kEDMA_TransferSize4Bytes;
+ xferConfig.destTransferSize = kEDMA_TransferSize4Bytes;
+ xferConfig.minorLoopBytes = 4U;
+ }
+
+ /* Configure DMA channel. */
+ if (xfer->txData != NULL)
+ {
+ xferConfig.srcOffset = (int16_t)bytesPerFrame;
+ xferConfig.srcAddr = (uint32_t)(xfer->txData);
+ }
+ else
+ {
+ /* Disable the source increasement and source set to dummyData. */
+ xferConfig.srcOffset = 0;
+ xferConfig.srcAddr = (uint32_t)(&s_dummyData);
+ }
+
+ xferConfig.majorLoopCounts = (xfer->dataSize / xferConfig.minorLoopBytes);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO SPI handle */
+ handle->nbytes = (uint8_t)xferConfig.minorLoopBytes;
+
+ if (handle->txHandle != NULL)
+ {
+ (void)EDMA_SubmitTransfer(handle->txHandle, &xferConfig);
+ }
+
+ /* Configure rx transfer EDMA. */
+ if (xfer->rxData != NULL)
+ {
+ xferConfig.srcAddr = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
+ if (bytesPerFrame == 2U)
+ {
+ if (direction == kFLEXIO_SPI_LsbFirst)
+ {
+ xferConfig.srcAddr -= 1U;
+ }
+ }
+ else if (bytesPerFrame == 4U)
+ {
+ if (direction == kFLEXIO_SPI_LsbFirst)
+ {
+ xferConfig.srcAddr -= 3U;
+ }
+ }
+ else
+ {
+ }
+ xferConfig.srcOffset = 0;
+ xferConfig.destAddr = (uint32_t)(xfer->rxData);
+ xferConfig.destOffset = (int16_t)bytesPerFrame;
+ (void)EDMA_SubmitTransfer(handle->rxHandle, &xferConfig);
+ handle->rxInProgress = true;
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, true);
+ EDMA_StartTransfer(handle->rxHandle);
+ }
+
+ /* Always start tx transfer. */
+ if (handle->txHandle != NULL)
+ {
+ handle->txInProgress = true;
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, true);
+ EDMA_StartTransfer(handle->txHandle);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the FlexIO SPI master eDMA handle.
+ *
+ * This function initializes the FlexIO SPI master eDMA handle which can be used for other FlexIO SPI master
+ * transactional
+ * APIs.
+ * For a specified FlexIO SPI instance, call this API once to get the initialized handle.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * param callback SPI callback, NULL means no callback.
+ * param userData callback function parameter.
+ * param txHandle User requested eDMA handle for FlexIO SPI RX eDMA transfer.
+ * param rxHandle User requested eDMA handle for FlexIO SPI TX eDMA transfer.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txHandle,
+ edma_handle_t *rxHandle)
+{
+ assert(handle != NULL);
+
+ uint8_t index = 0;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_SPI_HANDLE_COUNT; index++)
+ {
+ if (s_edmaPrivateHandle[index].base == NULL)
+ {
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+ break;
+ }
+ }
+
+ if (index == (uint16_t)FLEXIO_SPI_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ /* Set spi base to handle. */
+ handle->txHandle = txHandle;
+ handle->rxHandle = rxHandle;
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SPI state to idle. */
+ handle->txInProgress = false;
+ handle->rxInProgress = false;
+
+ /* Install callback for Tx/Rx dma channel. */
+ if (handle->txHandle != NULL)
+ {
+ EDMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxEDMACallback, &s_edmaPrivateHandle[index]);
+ }
+ if (handle->rxHandle != NULL)
+ {
+ EDMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxEDMACallback, &s_edmaPrivateHandle[index]);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_MasterGetTransferCountEDMA to poll the transfer status and check
+ * whether the FlexIO SPI transfer is finished.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * param xfer Pointer to FlexIO SPI transfer structure.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+
+ timerCmp &= 0x00FFU;
+
+ /* Check if the device is busy. */
+ if ((handle->txInProgress) || (handle->rxInProgress))
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if input parameter invalid. */
+ if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Timer1 controls the CS signal which enables/disables(asserts/deasserts) when timer0 enable/disable. Timer0
+ enables when tx shifter is written and disables when timer compare. The timer compare event causes the
+ transmit shift registers to load which generates a tx register empty event. Since when timer stop bit is
+ disabled, a timer enable condition can be detected in the same cycle as a timer disable condition, so if
+ software writes the tx register upon the detection of tx register empty event, the timer enable condition
+ is triggered again, then the CS signal can remain low until software no longer writes the tx register. */
+ if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
+ }
+ else
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
+ }
+
+ /* configure data mode. */
+ if ((dataFormat == (uint8_t)kFLEXIO_SPI_8bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_8bitLsb))
+ {
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ }
+ else if ((dataFormat == (uint8_t)kFLEXIO_SPI_16bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_16bitLsb))
+ {
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ }
+ else if ((dataFormat == (uint8_t)kFLEXIO_SPI_32bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_32bitLsb))
+ {
+ dataMode = (32UL * 2UL - 1UL) << 8U;
+ }
+ else
+ {
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ }
+
+ dataMode |= timerCmp;
+
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ return FLEXIO_SPI_EDMAConfig(base, handle, xfer);
+}
+
+/*!
+ * brief Gets the remaining bytes for FlexIO SPI eDMA transfer.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle FlexIO SPI eDMA handle pointer.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->rxInProgress)
+ {
+ *count =
+ (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
+ handle->rxHandle->base, handle->rxHandle->channel));
+ }
+ else
+ {
+ *count =
+ (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
+ handle->txHandle->base, handle->txHandle->channel));
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a FlexIO SPI transfer using eDMA.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle FlexIO SPI eDMA handle pointer.
+ */
+void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma. */
+ EDMA_AbortTransfer(handle->txHandle);
+ EDMA_AbortTransfer(handle->rxHandle);
+
+ /* Disable DMA enable bit. */
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_DmaAllEnable, false);
+
+ /* Set the handle state. */
+ handle->txInProgress = false;
+ handle->rxInProgress = false;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_SlaveGetTransferCountEDMA to poll the transfer status and
+ * check whether the FlexIO SPI transfer is finished.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
+ * param xfer Pointer to FlexIO SPI transfer structure.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0U;
+ uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
+
+ /* Check if the device is busy. */
+ if ((handle->txInProgress) || (handle->rxInProgress))
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* SCK timer use CS pin as inverted trigger so timer should be disbaled on trigger falling edge(CS re-asserts). */
+ /* However if CPHA is first edge mode, timer will restart each time right after timer compare event occur and
+ before CS pin re-asserts, which triggers another shifter load. To avoid this, when in CS dis-continuous mode,
+ timer should disable in timer compare rather than trigger falling edge(CS re-asserts), and in CS continuous mode,
+ tx/rx shifters should be flushed after transfer finishes and before next transfer starts. */
+ FLEXIO_SPI_FlushShifters(base);
+ if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
+ }
+ else
+ {
+ if ((base->flexioBase->SHIFTCTL[base->shifterIndex[0]] & FLEXIO_SHIFTCTL_TIMPOL_MASK) ==
+ FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive))
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
+ FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare);
+ }
+ else
+ {
+ base->flexioBase->TIMCFG[base->timerIndex[0]] =
+ (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
+ FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
+ }
+ }
+
+ /* Check if input parameter invalid. */
+ if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* configure data mode. */
+ if ((dataFormat == (uint8_t)kFLEXIO_SPI_8bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_8bitLsb))
+ {
+ dataMode = 8U * 2U - 1U;
+ }
+ else if ((dataFormat == (uint8_t)kFLEXIO_SPI_16bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_16bitLsb))
+ {
+ dataMode = 16U * 2U - 1U;
+ }
+ else if ((dataFormat == (uint8_t)kFLEXIO_SPI_32bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_32bitLsb))
+ {
+ dataMode = 32UL * 2UL - 1UL;
+ }
+ else
+ {
+ dataMode = 8U * 2U - 1U;
+ }
+
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ return FLEXIO_SPI_EDMAConfig(base, handle, xfer);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.h
new file mode 100644
index 0000000000..c71a1b1fda
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_spi_edma.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_SPI_EDMA_H_
+#define _FSL_FLEXIO_SPI_EDMA_H_
+
+#include "fsl_flexio_spi.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexio_edma_spi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO SPI EDMA driver version. */
+#define FSL_FLEXIO_SPI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 3, 0))
+/*@}*/
+
+/*! @brief typedef for flexio_spi_master_edma_handle_t in advance. */
+typedef struct _flexio_spi_master_edma_handle flexio_spi_master_edma_handle_t;
+
+/*! @brief Slave handle is the same with master handle. */
+typedef flexio_spi_master_edma_handle_t flexio_spi_slave_edma_handle_t;
+
+/*! @brief FlexIO SPI master callback for finished transmit */
+typedef void (*flexio_spi_master_edma_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO SPI slave callback for finished transmit */
+typedef void (*flexio_spi_slave_edma_transfer_callback_t)(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief FlexIO SPI eDMA transfer handle, users should not touch the content of the handle.*/
+struct _flexio_spi_master_edma_handle
+{
+ size_t transferSize; /*!< Total bytes to be transferred. */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ bool txInProgress; /*!< Send transfer in progress */
+ bool rxInProgress; /*!< Receive transfer in progress */
+ edma_handle_t *txHandle; /*!< DMA handler for SPI send */
+ edma_handle_t *rxHandle; /*!< DMA handler for SPI receive */
+ flexio_spi_master_edma_transfer_callback_t callback; /*!< Callback for SPI DMA transfer */
+ void *userData; /*!< User Data for SPI DMA callback */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FlexIO SPI master eDMA handle.
+ *
+ * This function initializes the FlexIO SPI master eDMA handle which can be used for other FlexIO SPI master
+ * transactional
+ * APIs.
+ * For a specified FlexIO SPI instance, call this API once to get the initialized handle.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * @param callback SPI callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @param txHandle User requested eDMA handle for FlexIO SPI RX eDMA transfer.
+ * @param rxHandle User requested eDMA handle for FlexIO SPI TX eDMA transfer.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txHandle,
+ edma_handle_t *rxHandle);
+
+/*!
+ * @brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * @note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_MasterGetTransferCountEDMA to poll the transfer status and check
+ * whether the FlexIO SPI transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to FlexIO SPI transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO SPI transfer using eDMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI eDMA handle pointer.
+ */
+void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes transferred so far using FlexIO SPI master eDMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI eDMA handle pointer.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ size_t *count);
+
+/*!
+ * @brief Initializes the FlexIO SPI slave eDMA handle.
+ *
+ * This function initializes the FlexIO SPI slave eDMA handle.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
+ * @param callback SPI callback, NULL means no callback.
+ * @param userData callback function parameter.
+ * @param txHandle User requested eDMA handle for FlexIO SPI TX eDMA transfer.
+ * @param rxHandle User requested eDMA handle for FlexIO SPI RX eDMA transfer.
+ */
+static inline void FLEXIO_SPI_SlaveTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ flexio_spi_slave_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txHandle,
+ edma_handle_t *rxHandle)
+{
+ (void)FLEXIO_SPI_MasterTransferCreateHandleEDMA(base, handle, callback, userData, txHandle, rxHandle);
+}
+
+/*!
+ * @brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * @note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_SlaveGetTransferCountEDMA to poll the transfer status and
+ * check whether the FlexIO SPI transfer is finished.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to FlexIO SPI transfer structure.
+ * @retval kStatus_Success Successfully start a transfer.
+ * @retval kStatus_InvalidArgument Input argument is invalid.
+ * @retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a FlexIO SPI transfer using eDMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
+ */
+static inline void FLEXIO_SPI_SlaveTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_slave_edma_handle_t *handle)
+{
+ FLEXIO_SPI_MasterTransferAbortEDMA(base, handle);
+}
+
+/*!
+ * @brief Gets the number of bytes transferred so far using FlexIO SPI slave eDMA.
+ *
+ * @param base Pointer to FLEXIO_SPI_Type structure.
+ * @param handle FlexIO SPI eDMA handle pointer.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+static inline status_t FLEXIO_SPI_SlaveTransferGetCountEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ size_t *count)
+{
+ return FLEXIO_SPI_MasterTransferGetCountEDMA(base, handle, count);
+}
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.c
new file mode 100644
index 0000000000..0d308b16a7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_uart.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_uart"
+#endif
+
+/*<! @brief uart transfer state. */
+enum _flexio_uart_transfer_states
+{
+ kFLEXIO_UART_TxIdle, /* TX idle. */
+ kFLEXIO_UART_TxBusy, /* TX busy. */
+ kFLEXIO_UART_RxIdle, /* RX idle. */
+ kFLEXIO_UART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the length of received data in RX ring buffer.
+ *
+ * @param handle FLEXIO UART handle pointer.
+ * @return Length of received data in RX ring buffer.
+ */
+static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle);
+
+/*!
+ * @brief Check whether the RX ring buffer is full.
+ *
+ * @param handle FLEXIO UART handle pointer.
+ * @retval true RX ring buffer is full.
+ * @retval false RX ring buffer is not full.
+ */
+static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle);
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_UART_GetInstance(FLEXIO_UART_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle)
+{
+ size_t size;
+ uint16_t rxRingBufferHead = handle->rxRingBufferHead;
+ uint16_t rxRingBufferTail = handle->rxRingBufferTail;
+
+ if (rxRingBufferTail > rxRingBufferHead)
+ {
+ size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
+ }
+ else
+ {
+ size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
+ }
+
+ return size;
+}
+
+static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle)
+{
+ bool full;
+
+ if (FLEXIO_UART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
+ {
+ full = true;
+ }
+ else
+ {
+ full = false;
+ }
+
+ return full;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures FlexIO UART
+ * hardware, and configures the FlexIO UART with FlexIO UART configuration.
+ * The configuration structure can be filled by the user or be set with
+ * default values by FLEXIO_UART_GetDefaultConfig().
+ *
+ * Example
+ code
+ FLEXIO_UART_Type base = {
+ .flexioBase = FLEXIO,
+ .TxPinIndex = 0,
+ .RxPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_uart_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 115200U,
+ .bitCountPerChar = 8
+ };
+ FLEXIO_UART_Init(base, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param userConfig Pointer to the flexio_uart_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+ * retval kStatus_Success Configuration success.
+ * retval kStatus_FLEXIO_UART_BaudrateNotSupport Baudrate is not supported for current clock source frequency.
+*/
+status_t FLEXIO_UART_Init(FLEXIO_UART_Type *base, const flexio_uart_config_t *userConfig, uint32_t srcClock_Hz)
+{
+ assert((base != NULL) && (userConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+ uint32_t calculatedBaud;
+ uint32_t diff;
+ status_t result = kStatus_Success;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_UART_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO UART */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(userConfig->enableUart));
+ if (!userConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->TxPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /*2. Configure the timer 0 for tx. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->TxPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ timerDiv = (uint16_t)(srcClock_Hz / userConfig->baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+
+ if (timerDiv > 0xFFU)
+ {
+ /* Check whether the calculated timerDiv is within allowed range. */
+ return kStatus_FLEXIO_UART_BaudrateNotSupport;
+ }
+ else
+ {
+ /* Check to see if actual baud rate is within 3% of desired baud rate
+ * based on the best calculated timerDiv value */
+ calculatedBaud = srcClock_Hz / (((uint32_t)timerDiv + 1U) * 2U);
+ /* timerDiv cannot be larger than the ideal divider, so calculatedBaud is definitely larger
+ than configured baud */
+ diff = calculatedBaud - userConfig->baudRate_Bps;
+ if (diff > ((userConfig->baudRate_Bps / 100U) * 3U))
+ {
+ return kStatus_FLEXIO_UART_BaudrateNotSupport;
+ }
+ }
+
+ timerCmp = ((uint16_t)userConfig->bitCountPerChar * 2U - 1U) << 8U;
+ timerCmp |= timerDiv;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 3. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[1];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->RxPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /* 4. Configure the timer 1 for rx. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->RxPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->RxPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinRisingEdge;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdge;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+
+ return result;
+}
+
+/*!
+ * brief Resets the FlexIO UART shifter and timer config.
+ *
+ * note After calling this API, call the FLEXO_UART_Init to use the FlexIO UART module.
+ *
+ * param base Pointer to FLEXIO_UART_Type structure
+ */
+void FLEXIO_UART_Deinit(FLEXIO_UART_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[0]);
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[1]);
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[0]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[1]);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO UART. The configuration
+ * can be used directly for calling the FLEXIO_UART_Init().
+ * Example:
+ code
+ flexio_uart_config_t config;
+ FLEXIO_UART_GetDefaultConfig(&userConfig);
+ endcode
+ * param userConfig Pointer to the flexio_uart_config_t structure.
+*/
+void FLEXIO_UART_GetDefaultConfig(flexio_uart_config_t *userConfig)
+{
+ assert(userConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(userConfig, 0, sizeof(*userConfig));
+
+ userConfig->enableUart = true;
+ userConfig->enableInDoze = false;
+ userConfig->enableInDebug = true;
+ userConfig->enableFastAccess = false;
+ /* Default baud rate 115200. */
+ userConfig->baudRate_Bps = 115200U;
+ /* Default bit count at 8. */
+ userConfig->bitCountPerChar = kFLEXIO_UART_8BitsPerChar;
+}
+
+/*!
+ * brief Enables the FlexIO UART interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_UART_EnableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO UART interrupt.
+ *
+ * This function disables the FlexIO UART interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_UART_DisableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Gets the FlexIO UART status flags.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * return FlexIO UART status flags.
+ */
+
+uint32_t FLEXIO_UART_GetStatusFlags(FLEXIO_UART_Type *base)
+{
+ uint32_t status = 0U;
+ status =
+ ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 1U);
+ status |=
+ (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 2U);
+ return status;
+}
+
+/*!
+ * brief Gets the FlexIO UART status flags.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_UART_TxDataRegEmptyFlag
+ * arg kFLEXIO_UART_RxEmptyFlag
+ * arg kFLEXIO_UART_RxOverRunFlag
+ */
+
+void FLEXIO_UART_ClearStatusFlags(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxOverRunFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sends a buffer of data bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been sent.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param txData The data bytes to send.
+ * param txSize The number of data bytes to send.
+ * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully wrote all data.
+ */
+status_t FLEXIO_UART_WriteBlocking(FLEXIO_UART_Type *base, const uint8_t *txData, size_t txSize)
+{
+ assert(txData != NULL);
+ assert(txSize != 0U);
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != txSize--)
+ {
+ /* Wait until data transfer complete. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_UART_Timeout;
+ }
+#endif
+
+ base->flexioBase->SHIFTBUF[base->shifterIndex[0]] = *txData++;
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been received.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param rxData The buffer to store the received bytes.
+ * param rxSize The number of data bytes to be received.
+ * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully received all data.
+ */
+status_t FLEXIO_UART_ReadBlocking(FLEXIO_UART_Type *base, uint8_t *rxData, size_t rxSize)
+{
+ assert(rxData != NULL);
+ assert(rxSize != 0U);
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != rxSize--)
+ {
+ /* Wait until data transfer complete. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_UART_Timeout;
+ }
+#endif
+
+ *rxData++ = (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the UART handle.
+ *
+ * This function initializes the FlexIO UART handle, which can be used for other FlexIO
+ * UART transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * The UART driver supports the "background" receiving, which means that users can set up
+ * a RX ring buffer optionally. Data received is stored into the ring buffer even when
+ * the user doesn't call the FLEXIO_UART_TransferReceiveNonBlocking() API. If there is already data
+ * received in the ring buffer, users can get the received data from the ring buffer
+ * directly. The ring buffer is disabled if passing NULL as p ringBuffer.
+ *
+ * param base to FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandle(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the TX/RX state. */
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Clear pending NVIC IRQ before enable NVIC IRQ. */
+ NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_UART_GetInstance(base)]);
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_UART_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_UART_TransferHandleIRQ);
+}
+
+/*!
+ * brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_ReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, users can get the received data from the ring buffer directly.
+ *
+ * note When using the RX ring buffer, one byte is reserved for internal use. In other
+ * words, if p ringBufferSize is 32, only 31 bytes are used for saving data.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * param ringBufferSize Size of the ring buffer.
+ */
+void FLEXIO_UART_TransferStartRingBuffer(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize)
+{
+ assert(handle != NULL);
+
+ /* Setup the ringbuffer address */
+ if (ringBuffer != NULL)
+ {
+ handle->rxRingBuffer = ringBuffer;
+ handle->rxRingBufferSize = ringBufferSize;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+
+ /* Enable the interrupt to accept the data when user need the ring buffer. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+}
+
+/*!
+ * brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferStopRingBuffer(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ if (handle->rxState == (uint8_t)kFLEXIO_UART_RxIdle)
+ {
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ handle->rxRingBuffer = NULL;
+ handle->rxRingBufferSize = 0U;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+}
+
+/*!
+ * brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function sends data using an interrupt method. This is a non-blocking function,
+ * which returns directly without waiting for all data to be written to the TX register. When
+ * all data is written to the TX register in ISR, the FlexIO UART driver calls the callback
+ * function and passes the ref kStatus_FLEXIO_UART_TxIdle as status parameter.
+ *
+ * note The kStatus_FLEXIO_UART_TxIdle is passed to the upper layer when all data is written
+ * to the TX register. However, it does not ensure that all data is sent out.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param xfer FlexIO UART transfer structure. See #flexio_uart_transfer_t.
+ * retval kStatus_Success Successfully starts the data transmission.
+ * retval kStatus_UART_TxBusy Previous transmission still not finished, data not written to the TX register.
+ */
+status_t FLEXIO_UART_TransferSendNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->txData))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return error if current TX busy. */
+ if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
+ {
+ status = kStatus_FLEXIO_UART_TxBusy;
+ }
+ else
+ {
+ handle->txData = xfer->txData;
+ handle->txDataSize = xfer->dataSize;
+ handle->txDataSizeAll = xfer->dataSize;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
+
+ /* Enable transmiter interrupt. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt-driven data sending. Get the remainBytes to find out
+ * how many bytes are still not sent out.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortSend(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ /* Disable the transmitter and disable the interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ handle->txDataSize = 0U;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes sent.
+ *
+ * This function gets the number of bytes sent driven by interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param count Number of bytes sent so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll - handle->txDataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using the interrupt method. This is a non-blocking function,
+ * which returns without waiting for all data to be received.
+ * If the RX ring buffer is used and not empty, the data in ring buffer is copied and
+ * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in ring buffer is not enough to read, the receive
+ * request is saved by the UART driver. When new data arrives, the receive request
+ * is serviced first. When all data is received, the UART driver notifies the upper layer
+ * through a callback function and passes the status parameter ref kStatus_UART_RxIdle.
+ * For example, if the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer,
+ * the 5 bytes are copied to xfer->data. This function returns with the
+ * parameter p receivedBytes set to 5. For the last 5 bytes, newly arrived data is
+ * saved from the xfer->data[5]. When 5 bytes are received, the UART driver notifies upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param xfer UART transfer structure. See #flexio_uart_transfer_t.
+ * param receivedBytes Bytes received from the ring buffer directly.
+ * retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * retval kStatus_FLEXIO_UART_RxBusy Previous receive request is not finished.
+ */
+status_t FLEXIO_UART_TransferReceiveNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer,
+ size_t *receivedBytes)
+{
+ uint32_t i;
+ status_t status;
+ /* How many bytes to copy from ring buffer to user memory. */
+ size_t bytesToCopy = 0U;
+ /* How many bytes to receive. */
+ size_t bytesToReceive;
+ /* How many bytes currently have received. */
+ size_t bytesCurrentReceived;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->rxData))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* How to get data:
+ 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
+ to uart handle, enable interrupt to store received data to xfer->data. When
+ all data received, trigger callback.
+ 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
+ If there are enough data in ring buffer, copy them to xfer->data and return.
+ If there are not enough data in ring buffer, copy all of them to xfer->data,
+ save the xfer->data remained empty space to uart handle, receive data
+ to this empty space and trigger callback when finished. */
+
+ if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
+ {
+ status = kStatus_FLEXIO_UART_RxBusy;
+ }
+ else
+ {
+ bytesToReceive = xfer->dataSize;
+ bytesCurrentReceived = 0U;
+
+ /* If RX ring buffer is used. */
+ if (handle->rxRingBuffer != NULL)
+ {
+ /* Disable FLEXIO_UART RX IRQ, protect ring buffer. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+
+ /* How many bytes in RX ring buffer currently. */
+ bytesToCopy = FLEXIO_UART_TransferGetRxRingBufferLength(handle);
+
+ if (bytesToCopy != 0U)
+ {
+ bytesToCopy = MIN(bytesToReceive, bytesToCopy);
+
+ bytesToReceive -= bytesToCopy;
+
+ /* Copy data from ring buffer to user memory. */
+ for (i = 0U; i < bytesToCopy; i++)
+ {
+ xfer->rxData[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
+
+ /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
+ if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+ }
+
+ /* If ring buffer does not have enough data, still need to read more data. */
+ if (bytesToReceive != 0U)
+ {
+ /* No data in ring buffer, save the request to UART handle. */
+ handle->rxData = xfer->rxData + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = xfer->dataSize;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+ }
+
+ /* Enable FLEXIO_UART RX IRQ if previously enabled. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+
+ /* Call user callback since all data are received. */
+ if (0U == bytesToReceive)
+ {
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+ /* Ring buffer not used. */
+ else
+ {
+ handle->rxData = xfer->rxData + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+
+ /* Enable RX interrupt. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ /* Return the how many bytes have read. */
+ if (receivedBytes != NULL)
+ {
+ *receivedBytes = bytesCurrentReceived;
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the receive data which was using IRQ.
+ *
+ * This function aborts the receive data which was using IRQ.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortReceive(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
+ if (NULL == handle->rxRingBuffer)
+ {
+ /* Disable RX interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ handle->rxDataSize = 0U;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received driven by interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param count Number of bytes received so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll - handle->rxDataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief FlexIO UART IRQ handler function.
+ *
+ * This function processes the FlexIO UART transmit and receives the IRQ request.
+ *
+ * param uartType Pointer to the FLEXIO_UART_Type structure.
+ * param uartHandle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferHandleIRQ(void *uartType, void *uartHandle)
+{
+ uint8_t count = 1;
+ FLEXIO_UART_Type *base = (FLEXIO_UART_Type *)uartType;
+ flexio_uart_handle_t *handle = (flexio_uart_handle_t *)uartHandle;
+ uint16_t rxRingBufferHead;
+
+ /* Read the status back. */
+ uint32_t status = FLEXIO_UART_GetStatusFlags(base);
+
+ /* If RX overrun. */
+ if (((uint32_t)kFLEXIO_UART_RxOverRunFlag & status) != 0U)
+ {
+ /* Clear Overrun flag. */
+ FLEXIO_UART_ClearStatusFlags(base, (uint32_t)kFLEXIO_UART_RxOverRunFlag);
+
+ /* Trigger callback. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxHardwareOverrun, handle->userData);
+ }
+ }
+
+ /* Receive data register full */
+ if ((((uint32_t)kFLEXIO_UART_RxDataRegFullFlag & status) != 0U) &&
+ ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[1])) != 0U))
+ {
+ /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
+ if (handle->rxDataSize != 0U)
+ {
+ /* Using non block API to read the data from the registers. */
+ FLEXIO_UART_ReadByte(base, handle->rxData);
+ handle->rxDataSize--;
+ handle->rxData++;
+ count--;
+
+ /* If all the data required for upper layer is ready, trigger callback. */
+ if (0U == handle->rxDataSize)
+ {
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+
+ if (handle->rxRingBuffer != NULL)
+ {
+ if (count != 0U)
+ {
+ /* If RX ring buffer is full, trigger callback to notify over run. */
+ if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
+ {
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxRingBufferOverrun, handle->userData);
+ }
+ }
+
+ /* If ring buffer is still full after callback function, the oldest data is overridden. */
+ if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
+ {
+ /* Increase handle->rxRingBufferTail to make room for new data. */
+ if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+
+ /* Read data. */
+ rxRingBufferHead = handle->rxRingBufferHead;
+ handle->rxRingBuffer[rxRingBufferHead] =
+ (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+
+ /* Increase handle->rxRingBufferHead. */
+ if ((uint32_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferHead = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferHead++;
+ }
+ }
+ }
+ /* If no receive requst pending, stop RX interrupt. */
+ else if (0U == handle->rxDataSize)
+ {
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+ else
+ {
+ }
+ }
+
+ /* Send data register empty and the interrupt is enabled. */
+ if ((((uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag & status) != 0U) &&
+ ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[0])) != 0U))
+ {
+ if (handle->txDataSize != 0U)
+ {
+ /* Using non block API to write the data to the registers. */
+ FLEXIO_UART_WriteByte(base, handle->txData);
+ handle->txData++;
+ handle->txDataSize--;
+
+ /* If all the data are written to data register, TX finished. */
+ if (0U == handle->txDataSize)
+ {
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ /* Disable TX register empty interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ /* Trigger callback. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_TxIdle, handle->userData);
+ }
+ }
+ }
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.h
new file mode 100644
index 0000000000..783c31885e
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart.h
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXIO_UART_H_
+#define _FSL_FLEXIO_UART_H_
+
+#include "fsl_common.h"
+#include "fsl_flexio.h"
+
+/*!
+ * @addtogroup flexio_uart
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO UART driver version. */
+#define FSL_FLEXIO_UART_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef UART_RETRY_TIMES
+#define UART_RETRY_TIMES 0U /* Defining to zero means to keep waiting for the flag until it is assert/deassert. */
+#endif
+
+/*! @brief Error codes for the UART driver. */
+enum
+{
+ kStatus_FLEXIO_UART_TxBusy = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 0), /*!< Transmitter is busy. */
+ kStatus_FLEXIO_UART_RxBusy = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 1), /*!< Receiver is busy. */
+ kStatus_FLEXIO_UART_TxIdle = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 2), /*!< UART transmitter is idle. */
+ kStatus_FLEXIO_UART_RxIdle = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 3), /*!< UART receiver is idle. */
+ kStatus_FLEXIO_UART_ERROR = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 4), /*!< ERROR happens on UART. */
+ kStatus_FLEXIO_UART_RxRingBufferOverrun =
+ MAKE_STATUS(kStatusGroup_FLEXIO_UART, 5), /*!< UART RX software ring buffer overrun. */
+ kStatus_FLEXIO_UART_RxHardwareOverrun = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 6), /*!< UART RX receiver overrun. */
+ kStatus_FLEXIO_UART_Timeout = MAKE_STATUS(kStatusGroup_FLEXIO_UART, 7), /*!< UART times out. */
+ kStatus_FLEXIO_UART_BaudrateNotSupport =
+ MAKE_STATUS(kStatusGroup_FLEXIO_UART, 8) /*!< Baudrate is not supported in current clock source */
+};
+
+/*! @brief FlexIO UART bit count per char. */
+typedef enum _flexio_uart_bit_count_per_char
+{
+ kFLEXIO_UART_7BitsPerChar = 7U, /*!< 7-bit data characters */
+ kFLEXIO_UART_8BitsPerChar = 8U, /*!< 8-bit data characters */
+ kFLEXIO_UART_9BitsPerChar = 9U, /*!< 9-bit data characters */
+} flexio_uart_bit_count_per_char_t;
+
+/*! @brief Define FlexIO UART interrupt mask. */
+enum _flexio_uart_interrupt_enable
+{
+ kFLEXIO_UART_TxDataRegEmptyInterruptEnable = 0x1U, /*!< Transmit buffer empty interrupt enable. */
+ kFLEXIO_UART_RxDataRegFullInterruptEnable = 0x2U, /*!< Receive buffer full interrupt enable. */
+};
+
+/*! @brief Define FlexIO UART status mask. */
+enum _flexio_uart_status_flags
+{
+ kFLEXIO_UART_TxDataRegEmptyFlag = 0x1U, /*!< Transmit buffer empty flag. */
+ kFLEXIO_UART_RxDataRegFullFlag = 0x2U, /*!< Receive buffer full flag. */
+ kFLEXIO_UART_RxOverRunFlag = 0x4U, /*!< Receive buffer over run flag. */
+};
+
+/*! @brief Define FlexIO UART access structure typedef. */
+typedef struct _flexio_uart_type
+{
+ FLEXIO_Type *flexioBase; /*!< FlexIO base pointer. */
+ uint8_t TxPinIndex; /*!< Pin select for UART_Tx. */
+ uint8_t RxPinIndex; /*!< Pin select for UART_Rx. */
+ uint8_t shifterIndex[2]; /*!< Shifter index used in FlexIO UART. */
+ uint8_t timerIndex[2]; /*!< Timer index used in FlexIO UART. */
+} FLEXIO_UART_Type;
+
+/*! @brief Define FlexIO UART user configuration structure. */
+typedef struct _flexio_uart_config
+{
+ bool enableUart; /*!< Enable/disable FlexIO UART TX & RX. */
+ bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode*/
+ bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode*/
+ bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers,
+ fast access requires the FlexIO clock to be at least
+ twice the frequency of the bus clock. */
+ uint32_t baudRate_Bps; /*!< Baud rate in Bps. */
+ flexio_uart_bit_count_per_char_t bitCountPerChar; /*!< number of bits, 7/8/9 -bit */
+} flexio_uart_config_t;
+
+/*! @brief Define FlexIO UART transfer structure. */
+typedef struct _flexio_uart_transfer
+{
+ /*
+ * Use separate TX and RX data pointer, because TX data is const data.
+ * The member data is kept for backward compatibility.
+ */
+ union
+ {
+ uint8_t *data; /*!< The buffer of data to be transfer.*/
+ uint8_t *rxData; /*!< The buffer to receive data. */
+ const uint8_t *txData; /*!< The buffer of data to be sent. */
+ };
+ size_t dataSize; /*!< Transfer size*/
+} flexio_uart_transfer_t;
+
+/* Forward declaration of the handle typedef. */
+typedef struct _flexio_uart_handle flexio_uart_handle_t;
+
+/*! @brief FlexIO UART transfer callback function. */
+typedef void (*flexio_uart_transfer_callback_t)(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Define FLEXIO UART handle structure*/
+struct _flexio_uart_handle
+{
+ const uint8_t *volatile txData; /*!< Address of remaining data to send. */
+ volatile size_t txDataSize; /*!< Size of the remaining data to send. */
+ uint8_t *volatile rxData; /*!< Address of remaining data to receive. */
+ volatile size_t rxDataSize; /*!< Size of the remaining data to receive. */
+ size_t txDataSizeAll; /*!< Total bytes to be sent. */
+ size_t rxDataSizeAll; /*!< Total bytes to be received. */
+
+ uint8_t *rxRingBuffer; /*!< Start address of the receiver ring buffer. */
+ size_t rxRingBufferSize; /*!< Size of the ring buffer. */
+ volatile uint16_t rxRingBufferHead; /*!< Index for the driver to store received data into ring buffer. */
+ volatile uint16_t rxRingBufferTail; /*!< Index for the user to get data from the ring buffer. */
+
+ flexio_uart_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< UART callback function parameter.*/
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Ungates the FlexIO clock, resets the FlexIO module, configures FlexIO UART
+ * hardware, and configures the FlexIO UART with FlexIO UART configuration.
+ * The configuration structure can be filled by the user or be set with
+ * default values by FLEXIO_UART_GetDefaultConfig().
+ *
+ * Example
+ @code
+ FLEXIO_UART_Type base = {
+ .flexioBase = FLEXIO,
+ .TxPinIndex = 0,
+ .RxPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_uart_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 115200U,
+ .bitCountPerChar = 8
+ };
+ FLEXIO_UART_Init(base, &config, srcClock_Hz);
+ @endcode
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param userConfig Pointer to the flexio_uart_config_t structure.
+ * @param srcClock_Hz FlexIO source clock in Hz.
+ * @retval kStatus_Success Configuration success.
+ * @retval kStatus_FLEXIO_UART_BaudrateNotSupport Baudrate is not supported for current clock source frequency.
+*/
+status_t FLEXIO_UART_Init(FLEXIO_UART_Type *base, const flexio_uart_config_t *userConfig, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Resets the FlexIO UART shifter and timer config.
+ *
+ * @note After calling this API, call the FLEXO_UART_Init to use the FlexIO UART module.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ */
+void FLEXIO_UART_Deinit(FLEXIO_UART_Type *base);
+
+/*!
+ * @brief Gets the default configuration to configure the FlexIO UART. The configuration
+ * can be used directly for calling the FLEXIO_UART_Init().
+ * Example:
+ @code
+ flexio_uart_config_t config;
+ FLEXIO_UART_GetDefaultConfig(&userConfig);
+ @endcode
+ * @param userConfig Pointer to the flexio_uart_config_t structure.
+*/
+void FLEXIO_UART_GetDefaultConfig(flexio_uart_config_t *userConfig);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexIO UART status flags.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @return FlexIO UART status flags.
+ */
+
+uint32_t FLEXIO_UART_GetStatusFlags(FLEXIO_UART_Type *base);
+
+/*!
+ * @brief Gets the FlexIO UART status flags.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * @arg kFLEXIO_UART_TxDataRegEmptyFlag
+ * @arg kFLEXIO_UART_RxEmptyFlag
+ * @arg kFLEXIO_UART_RxOverRunFlag
+ */
+
+void FLEXIO_UART_ClearStatusFlags(FLEXIO_UART_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the FlexIO UART interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param mask Interrupt source.
+ */
+void FLEXIO_UART_EnableInterrupts(FLEXIO_UART_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the FlexIO UART interrupt.
+ *
+ * This function disables the FlexIO UART interrupt.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param mask Interrupt source.
+ */
+void FLEXIO_UART_DisableInterrupts(FLEXIO_UART_Type *base, uint32_t mask);
+
+/* @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Gets the FlexIO UARt transmit data register address.
+ *
+ * This function returns the UART data register address, which is mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @return FlexIO UART transmit data register address.
+ */
+static inline uint32_t FLEXIO_UART_GetTxDataRegisterAddress(FLEXIO_UART_Type *base)
+{
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBuffer, base->shifterIndex[0]);
+}
+
+/*!
+ * @brief Gets the FlexIO UART receive data register address.
+ *
+ * This function returns the UART data register address, which is mainly used by DMA/eDMA.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @return FlexIO UART receive data register address.
+ */
+static inline uint32_t FLEXIO_UART_GetRxDataRegisterAddress(FLEXIO_UART_Type *base)
+{
+ return FLEXIO_GetShifterBufferAddress(base->flexioBase, kFLEXIO_ShifterBufferByteSwapped, base->shifterIndex[1]);
+}
+
+/*!
+ * @brief Enables/disables the FlexIO UART transmit DMA.
+ * This function enables/disables the FlexIO UART Tx DMA,
+ * which means asserting the kFLEXIO_UART_TxDataRegEmptyFlag does/doesn't trigger the DMA request.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param enable True to enable, false to disable.
+ */
+static inline void FLEXIO_UART_EnableTxDMA(FLEXIO_UART_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[0], enable);
+}
+
+/*!
+ * @brief Enables/disables the FlexIO UART receive DMA.
+ * This function enables/disables the FlexIO UART Rx DMA,
+ * which means asserting kFLEXIO_UART_RxDataRegFullFlag does/doesn't trigger the DMA request.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param enable True to enable, false to disable.
+ */
+static inline void FLEXIO_UART_EnableRxDMA(FLEXIO_UART_Type *base, bool enable)
+{
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[1], enable);
+}
+
+/* @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the FlexIO UART module operation.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type.
+ * @param enable True to enable, false does not have any effect.
+ */
+static inline void FLEXIO_UART_Enable(FLEXIO_UART_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*!
+ * @brief Writes one byte of data.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is put into the
+ * data register. Ensure that the TxEmptyFlag is asserted before calling
+ * this API.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param buffer The data bytes to send.
+ */
+static inline void FLEXIO_UART_WriteByte(FLEXIO_UART_Type *base, const uint8_t *buffer)
+{
+ base->flexioBase->SHIFTBUF[base->shifterIndex[0]] = *buffer;
+}
+
+/*!
+ * @brief Reads one byte of data.
+ *
+ * @note This is a non-blocking API, which returns directly after the data is read from the
+ * data register. Ensure that the RxFullFlag is asserted before calling this API.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param buffer The buffer to store the received bytes.
+ */
+static inline void FLEXIO_UART_ReadByte(FLEXIO_UART_Type *base, uint8_t *buffer)
+{
+ *buffer = (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+}
+
+/*!
+ * @brief Sends a buffer of data bytes.
+ *
+ * @note This function blocks using the polling method until all bytes have been sent.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param txData The data bytes to send.
+ * @param txSize The number of data bytes to send.
+ * @retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * @retval kStatus_Success Successfully wrote all data.
+ */
+status_t FLEXIO_UART_WriteBlocking(FLEXIO_UART_Type *base, const uint8_t *txData, size_t txSize);
+
+/*!
+ * @brief Receives a buffer of bytes.
+ *
+ * @note This function blocks using the polling method until all bytes have been received.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param rxData The buffer to store the received bytes.
+ * @param rxSize The number of data bytes to be received.
+ * @retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * @retval kStatus_Success Successfully received all data.
+ */
+status_t FLEXIO_UART_ReadBlocking(FLEXIO_UART_Type *base, uint8_t *rxData, size_t rxSize);
+
+/* @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the UART handle.
+ *
+ * This function initializes the FlexIO UART handle, which can be used for other FlexIO
+ * UART transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * The UART driver supports the "background" receiving, which means that users can set up
+ * a RX ring buffer optionally. Data received is stored into the ring buffer even when
+ * the user doesn't call the FLEXIO_UART_TransferReceiveNonBlocking() API. If there is already data
+ * received in the ring buffer, users can get the received data from the ring buffer
+ * directly. The ring buffer is disabled if passing NULL as @p ringBuffer.
+ *
+ * @param base to FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandle(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_ReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, users can get the received data from the ring buffer directly.
+ *
+ * @note When using the RX ring buffer, one byte is reserved for internal use. In other
+ * words, if @p ringBufferSize is 32, only 31 bytes are used for saving data.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * @param ringBufferSize Size of the ring buffer.
+ */
+void FLEXIO_UART_TransferStartRingBuffer(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize);
+
+/*!
+ * @brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferStopRingBuffer(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle);
+
+/*!
+ * @brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function sends data using an interrupt method. This is a non-blocking function,
+ * which returns directly without waiting for all data to be written to the TX register. When
+ * all data is written to the TX register in ISR, the FlexIO UART driver calls the callback
+ * function and passes the @ref kStatus_FLEXIO_UART_TxIdle as status parameter.
+ *
+ * @note The kStatus_FLEXIO_UART_TxIdle is passed to the upper layer when all data is written
+ * to the TX register. However, it does not ensure that all data is sent out.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param xfer FlexIO UART transfer structure. See #flexio_uart_transfer_t.
+ * @retval kStatus_Success Successfully starts the data transmission.
+ * @retval kStatus_UART_TxBusy Previous transmission still not finished, data not written to the TX register.
+ */
+status_t FLEXIO_UART_TransferSendNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt-driven data sending. Get the remainBytes to find out
+ * how many bytes are still not sent out.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortSend(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes sent.
+ *
+ * This function gets the number of bytes sent driven by interrupt.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param count Number of bytes sent so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using the interrupt method. This is a non-blocking function,
+ * which returns without waiting for all data to be received.
+ * If the RX ring buffer is used and not empty, the data in ring buffer is copied and
+ * the parameter @p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in ring buffer is not enough to read, the receive
+ * request is saved by the UART driver. When new data arrives, the receive request
+ * is serviced first. When all data is received, the UART driver notifies the upper layer
+ * through a callback function and passes the status parameter kStatus_UART_RxIdle.
+ * For example, if the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer,
+ * the 5 bytes are copied to xfer->data. This function returns with the
+ * parameter @p receivedBytes set to 5. For the last 5 bytes, newly arrived data is
+ * saved from the xfer->data[5]. When 5 bytes are received, the UART driver notifies upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param xfer UART transfer structure. See #flexio_uart_transfer_t.
+ * @param receivedBytes Bytes received from the ring buffer directly.
+ * @retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * @retval kStatus_FLEXIO_UART_RxBusy Previous receive request is not finished.
+ */
+status_t FLEXIO_UART_TransferReceiveNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer,
+ size_t *receivedBytes);
+
+/*!
+ * @brief Aborts the receive data which was using IRQ.
+ *
+ * This function aborts the receive data which was using IRQ.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortReceive(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received driven by interrupt.
+ *
+ * @param base Pointer to the FLEXIO_UART_Type structure.
+ * @param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * @param count Number of bytes received so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count);
+
+/*!
+ * @brief FlexIO UART IRQ handler function.
+ *
+ * This function processes the FlexIO UART transmit and receives the IRQ request.
+ *
+ * @param uartType Pointer to the FLEXIO_UART_Type structure.
+ * @param uartHandle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferHandleIRQ(void *uartType, void *uartHandle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /*_FSL_FLEXIO_UART_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_dma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_dma.h
new file mode 100644
index 0000000000..5d8444fec8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_dma.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_UART_DMA_H_
+#define _FSL_FLEXIO_UART_DMA_H_
+
+#include "fsl_flexio_uart.h"
+#include "fsl_dma.h"
+
+/*!
+ * @addtogroup flexio_dma_uart
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO UART DMA driver version. */
+#define FSL_FLEXIO_UART_DMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
+/*@}*/
+
+/* Forward declaration of the handle typedef. */
+typedef struct _flexio_uart_dma_handle flexio_uart_dma_handle_t;
+
+/*! @brief UART transfer callback function. */
+typedef void (*flexio_uart_dma_transfer_callback_t)(FLEXIO_UART_Type *base,
+ flexio_uart_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief UART DMA handle
+ */
+struct _flexio_uart_dma_handle
+{
+ flexio_uart_dma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< UART callback function parameter.*/
+
+ size_t txDataSizeAll; /*!< Total bytes to be sent. */
+ size_t rxDataSizeAll; /*!< Total bytes to be received. */
+
+ dma_handle_t *txDmaHandle; /*!< The DMA TX channel used. */
+ dma_handle_t *rxDmaHandle; /*!< The DMA RX channel used. */
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXIO_UART handle which is used in transactional functions.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure.
+ * @param handle Pointer to flexio_uart_dma_handle_t structure.
+ * @param callback FlexIO UART callback, NULL means no callback.
+ * @param userData User callback function data.
+ * @param txDmaHandle User requested DMA handle for TX DMA transfer.
+ * @param rxDmaHandle User requested DMA handle for RX DMA transfer.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO UART DMA type/handle table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandleDMA(FLEXIO_UART_Type *base,
+ flexio_uart_dma_handle_t *handle,
+ flexio_uart_dma_transfer_callback_t callback,
+ void *userData,
+ dma_handle_t *txDmaHandle,
+ dma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Sends data using DMA.
+ *
+ * This function send data using DMA. This is non-blocking function, which returns
+ * right away. When all data is sent out, the send callback function is called.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ * @param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferSendDMA(FLEXIO_UART_Type *base,
+ flexio_uart_dma_handle_t *handle,
+ flexio_uart_transfer_t *xfer);
+
+/*!
+ * @brief Receives data using DMA.
+ *
+ * This function receives data using DMA. This is non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ * @param xfer FLEXIO_UART DMA transfer structure, see #flexio_uart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXIO_UART_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferReceiveDMA(FLEXIO_UART_Type *base,
+ flexio_uart_dma_handle_t *handle,
+ flexio_uart_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the sent data which using DMA.
+ *
+ * This function aborts the sent data which using DMA.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortSendDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle);
+
+/*!
+ * @brief Aborts the receive data which using DMA.
+ *
+ * This function aborts the receive data which using DMA.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortReceiveDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes sent out.
+ *
+ * This function gets the number of bytes sent out.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ * @param count Number of bytes sent so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCountDMA(FLEXIO_UART_Type *base, flexio_uart_dma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received.
+ *
+ * @param base Pointer to FLEXIO_UART_Type structure
+ * @param handle Pointer to flexio_uart_dma_handle_t structure
+ * @param count Number of bytes received so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCountDMA(FLEXIO_UART_Type *base,
+ flexio_uart_dma_handle_t *handle,
+ size_t *count);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_UART_DMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.c
new file mode 100644
index 0000000000..f2502c9df2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_uart_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_uart_edma"
+#endif
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_uart_edma_private_handle
+{
+ FLEXIO_UART_Type *base;
+ flexio_uart_edma_handle_t *handle;
+} flexio_uart_edma_private_handle_t;
+
+/* UART EDMA transfer handle. */
+enum _flexio_uart_edma_tansfer_states
+{
+ kFLEXIO_UART_TxIdle, /* TX idle. */
+ kFLEXIO_UART_TxBusy, /* TX busy. */
+ kFLEXIO_UART_RxIdle, /* RX idle. */
+ kFLEXIO_UART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*< @brief user configurable flexio uart handle count. */
+#define FLEXIO_UART_HANDLE_COUNT 2
+
+/*<! Private handle only used for internally. */
+static flexio_uart_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief FLEXIO UART EDMA send finished callback function.
+ *
+ * This function is called when FLEXIO UART EDMA send finished. It disables the UART
+ * TX EDMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief FLEXIO UART EDMA receive finished callback function.
+ *
+ * This function is called when FLEXIO UART EDMA receive finished. It disables the UART
+ * RX EDMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
+
+ assert(uartPrivateHandle->handle != NULL);
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ FLEXIO_UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback != NULL)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
+ kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds)
+{
+ flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
+
+ assert(uartPrivateHandle->handle != NULL);
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable transfer. */
+ FLEXIO_UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback != NULL)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
+ kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the UART handle which is used in transactional functions.
+ *
+ * param base Pointer to FLEXIO_UART_Type.
+ * param handle Pointer to flexio_uart_edma_handle_t structure.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ * param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(handle != NULL);
+
+ uint8_t index = 0U;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_UART_HANDLE_COUNT; index++)
+ {
+ if (s_edmaPrivateHandle[index].base == NULL)
+ {
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_UART_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ handle->rxEdmaHandle = rxEdmaHandle;
+ handle->txEdmaHandle = txEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Configure TX. */
+ if (txEdmaHandle != NULL)
+ {
+ EDMA_SetCallback(handle->txEdmaHandle, FLEXIO_UART_TransferSendEDMACallback, &s_edmaPrivateHandle);
+ }
+
+ /* Configure RX. */
+ if (rxEdmaHandle != NULL)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_UART_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent out, the send callback function is called.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle UART handle pointer.
+ * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ assert(handle->txEdmaHandle != NULL);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If previous TX not finished. */
+ if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
+ {
+ status = kStatus_FLEXIO_UART_TxBusy;
+ }
+ else
+ {
+ handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
+ handle->txDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
+ (uint32_t *)FLEXIO_UART_GetTxDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
+ xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
+ handle->nbytes = 1U;
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->txEdmaHandle);
+
+ /* Enable UART TX EDMA. */
+ FLEXIO_UART_EnableTxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_UART_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If previous RX not finished. */
+ if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
+ {
+ status = kStatus_FLEXIO_UART_RxBusy;
+ }
+ else
+ {
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+ handle->rxDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (uint32_t *)FLEXIO_UART_GetRxDataRegisterAddress(base), sizeof(uint8_t),
+ xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
+ handle->nbytes = (uint8_t)sizeof(uint8_t);
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+
+ /* Enable UART RX EDMA. */
+ FLEXIO_UART_EnableRxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the sent data which using eDMA.
+ *
+ * This function aborts sent data which using eDMA.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
+{
+ assert(handle->txEdmaHandle != NULL);
+
+ /* Disable UART TX EDMA. */
+ FLEXIO_UART_EnableTxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_StopTransfer(handle->txEdmaHandle);
+
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+}
+
+/*!
+ * brief Aborts the receive data which using eDMA.
+ *
+ * This function aborts the receive data which using eDMA.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ /* Disable UART RX EDMA. */
+ FLEXIO_UART_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_StopTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param count Number of bytes received so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(handle != NULL);
+ assert(handle->rxEdmaHandle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the number of bytes sent out.
+ *
+ * This function gets the number of bytes sent out.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param count Number of bytes sent so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(handle->txEdmaHandle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.h
new file mode 100644
index 0000000000..3f145ea6a4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexio/fsl_flexio_uart_edma.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_FLEXIO_UART_EDMA_H_
+#define _FSL_FLEXIO_UART_EDMA_H_
+
+#include "fsl_flexio_uart.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexio_edma_uart
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FlexIO UART EDMA driver version. */
+#define FSL_FLEXIO_UART_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/* Forward declaration of the handle typedef. */
+typedef struct _flexio_uart_edma_handle flexio_uart_edma_handle_t;
+
+/*! @brief UART transfer callback function. */
+typedef void (*flexio_uart_edma_transfer_callback_t)(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief UART eDMA handle
+ */
+struct _flexio_uart_edma_handle
+{
+ flexio_uart_edma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< UART callback function parameter.*/
+
+ size_t txDataSizeAll; /*!< Total bytes to be sent. */
+ size_t rxDataSizeAll; /*!< Total bytes to be received. */
+
+ edma_handle_t *txEdmaHandle; /*!< The eDMA TX channel used. */
+ edma_handle_t *rxEdmaHandle; /*!< The eDMA RX channel used. */
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the UART handle which is used in transactional functions.
+ *
+ * @param base Pointer to FLEXIO_UART_Type.
+ * @param handle Pointer to flexio_uart_edma_handle_t structure.
+ * @param callback The callback function.
+ * @param userData The parameter of the callback function.
+ * @param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ * @param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * @retval kStatus_Success Successfully create the handle.
+ * @retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle);
+
+/*!
+ * @brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent out, the send callback function is called.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle UART handle pointer.
+ * @param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer);
+
+/*!
+ * @brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle Pointer to flexio_uart_edma_handle_t structure
+ * @param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_UART_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the sent data which using eDMA.
+ *
+ * This function aborts sent data which using eDMA.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts the receive data which using eDMA.
+ *
+ * This function aborts the receive data which using eDMA.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes sent out.
+ *
+ * This function gets the number of bytes sent out.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle Pointer to flexio_uart_edma_handle_t structure
+ * @param count Number of bytes sent so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received.
+ *
+ * @param base Pointer to FLEXIO_UART_Type
+ * @param handle Pointer to flexio_uart_edma_handle_t structure
+ * @param count Number of bytes received so far by the non-blocking transaction.
+ * @retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ size_t *count);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_UART_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.c
new file mode 100644
index 0000000000..65e7318301
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexram.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexram"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base FLEXRAM base address
+ *
+ * @return The FLEXRAM instance
+ */
+static uint32_t FLEXRAM_GetInstance(FLEXRAM_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to FLEXRAM bases for each instance. */
+static FLEXRAM_Type *const s_flexramBases[] = FLEXRAM_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to FLEXRAM clocks for each instance. */
+static const clock_ip_name_t s_flexramClocks[] = FLEXRAM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+/*! Look-up table to calculate single-bit error bit position for ITCM. */
+static const uint8_t ItcmLookUpTable[64] = {
+ 0xC1, 0x43, 0x9E, 0x83, 0x15, 0x4C, 0x4A, 0x8C, 0x31, 0x1C, 0xA2, 0xE0, 0x51, 0x2C, 0xC2, 0xD0,
+ 0x19, 0x1A, 0x26, 0xEA, 0x29, 0x94, 0x16, 0x64, 0x37, 0xA4, 0x0D, 0xC4, 0x75, 0x38, 0x4F, 0x58,
+ 0x46, 0x91, 0x86, 0x61, 0x49, 0x98, 0x89, 0x68, 0x32, 0x34, 0x07, 0xC8, 0x92, 0xA8, 0xA7, 0x54,
+ 0xA1, 0xD9, 0x25, 0xF8, 0x0E, 0x0B, 0x8A, 0x2A, 0x52, 0x45, 0x13, 0x85, 0x62, 0x70, 0x23, 0xB0};
+/*! Look-up table to calculate single-bit error bit position for DTCM. */
+static const uint8_t DtcmLookUpTable[32] = {0x61, 0x51, 0x19, 0x45, 0x43, 0x31, 0x29, 0x13, 0x62, 0x52, 0x4A,
+ 0x46, 0x32, 0x2A, 0x23, 0x1A, 0x2C, 0x64, 0x26, 0x25, 0x34, 0x16,
+ 0x15, 0x54, 0x0B, 0x58, 0x1C, 0x4C, 0x38, 0x0E, 0x0D, 0x49};
+#endif /* FLEXRAM_ECC_ERROR_DETAILED_INFO */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t FLEXRAM_GetInstance(FLEXRAM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexramBases); instance++)
+ {
+ if (s_flexramBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexramBases));
+
+ return instance;
+}
+
+/*!
+ * brief FLEXRAM module initialization function.
+ *
+ * param base FLEXRAM base address.
+ */
+void FLEXRAM_Init(FLEXRAM_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate ENET clock. */
+ CLOCK_EnableClock(s_flexramClocks[FLEXRAM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* enable all the interrupt status */
+ base->INT_STAT_EN |= (uint32_t)kFLEXRAM_InterruptStatusAll;
+ /* clear all the interrupt status */
+ base->INT_STATUS |= (uint32_t)kFLEXRAM_InterruptStatusAll;
+ /* disable all the interrpt */
+ base->INT_SIG_EN = 0U;
+}
+
+/*!
+ * brief Deinitializes the FLEXRAM.
+ *
+ */
+void FLEXRAM_Deinit(FLEXRAM_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate ENET clock. */
+ CLOCK_DisableClock(s_flexramClocks[FLEXRAM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if (defined(FSL_FEATURE_FLEXRAM_HAS_ECC) && FSL_FEATURE_FLEXRAM_HAS_ECC)
+void FLEXRAM_EnableECC(FLEXRAM_Type *base, bool OcramECCEnable, bool TcmECCEnable)
+{
+ if (true == OcramECCEnable)
+ {
+ base->FLEXRAM_CTRL |= FLEXRAM_FLEXRAM_CTRL_OCRAM_ECC_EN_MASK;
+ }
+ else
+ {
+ base->FLEXRAM_CTRL &= ~FLEXRAM_FLEXRAM_CTRL_OCRAM_ECC_EN_MASK;
+ }
+
+ if (true == TcmECCEnable)
+ {
+ base->FLEXRAM_CTRL |= FLEXRAM_FLEXRAM_CTRL_TCM_ECC_EN_MASK;
+ }
+ else
+ {
+ base->FLEXRAM_CTRL &= ~FLEXRAM_FLEXRAM_CTRL_TCM_ECC_EN_MASK;
+ }
+}
+
+void FLEXRAM_ErrorInjection(FLEXRAM_Type *base, flexram_memory_type_t memory, flexram_ecc_error_type_t *error)
+{
+ assert(error != NULL);
+
+ switch (memory)
+ {
+ case kFLEXRAM_OCRAM:
+ base->OCRAM_ECC_ERROR_INJEC =
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_ERR1BIT(error->SingleBitPos) |
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_ERR2BIT(error->SecondBitPos) |
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_FR11BI(error->Fource1BitDataInversion) |
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_FR1NCI(error->FourceOneNCDataInversion) |
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_FRC1BI(error->FourceConti1BitDataInversion) |
+ FLEXRAM_OCRAM_ECC_ERROR_INJEC_OCRAM_FRCNCI(error->FourceContiNCDataInversion);
+ break;
+ case kFLEXRAM_ITCM:
+ base->ITCM_ECC_ERROR_INJEC = FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_ERR1BIT(error->SingleBitPos) |
+ FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_ERR2BIT(error->SecondBitPos) |
+ FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_FR11BI(error->Fource1BitDataInversion) |
+ FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_FR1NCI(error->FourceOneNCDataInversion) |
+ FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_FRC1BI(error->FourceConti1BitDataInversion) |
+ FLEXRAM_ITCM_ECC_ERROR_INJEC_ITCM_FRCNCI(error->FourceContiNCDataInversion);
+ break;
+ case kFLEXRAM_D0TCM:
+ base->D0TCM_ECC_ERROR_INJEC =
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_ERR1BIT(error->SingleBitPos) |
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_ERR2BIT(error->SecondBitPos) |
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_FR11BI(error->Fource1BitDataInversion) |
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_FR1NCI(error->FourceOneNCDataInversion) |
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_FRC1BI(error->FourceConti1BitDataInversion) |
+ FLEXRAM_D0TCM_ECC_ERROR_INJEC_D0TCM_FRCNCI(error->FourceContiNCDataInversion);
+ break;
+ case kFLEXRAM_D1TCM:
+ base->D1TCM_ECC_ERROR_INJEC =
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_ERR1BIT(error->SingleBitPos) |
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_ERR2BIT(error->SecondBitPos) |
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_FR11BI(error->Fource1BitDataInversion) |
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_FR1NCI(error->FourceOneNCDataInversion) |
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_FRC1BI(error->FourceConti1BitDataInversion) |
+ FLEXRAM_D1TCM_ECC_ERROR_INJEC_D1TCM_FRCNCI(error->FourceContiNCDataInversion);
+ break;
+ default:
+ assert(NULL);
+ break;
+ }
+
+ __DSB();
+}
+
+void FLEXRAM_GetOcramSingleErroInfo(FLEXRAM_Type *base, flexram_ocram_ecc_single_error_info_t *info)
+{
+ assert(NULL != info);
+
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ info->OcramSingleErrorECCCipher =
+ (uint8_t)((base->OCRAM_ECC_SINGLE_ERROR_INFO & FLEXRAM_OCRAM_ECC_SINGLE_ERROR_INFO_OCRAM_ECCS_ERRED_ECC_MASK) >>
+ FLEXRAM_OCRAM_ECC_SINGLE_ERROR_INFO_OCRAM_ECCS_ERRED_ECC_SHIFT);
+ info->OcramSingleErrorECCSyndrome =
+ (uint8_t)((base->OCRAM_ECC_SINGLE_ERROR_INFO & FLEXRAM_OCRAM_ECC_SINGLE_ERROR_INFO_OCRAM_ECCS_ERRED_SYN_MASK) >>
+ FLEXRAM_OCRAM_ECC_SINGLE_ERROR_INFO_OCRAM_ECCS_ERRED_SYN_SHIFT);
+#else
+ info->OcramSingleErrorInfo = base->OCRAM_ECC_SINGLE_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->OcramSingleErrorAddr = base->OCRAM_ECC_SINGLE_ERROR_ADDR;
+ info->OcramSingleErrorDataLSB = base->OCRAM_ECC_SINGLE_ERROR_DATA_LSB;
+ info->OcramSingleErrorDataMSB = base->OCRAM_ECC_SINGLE_ERROR_DATA_MSB;
+}
+
+void FLEXRAM_GetOcramMultiErroInfo(FLEXRAM_Type *base, flexram_ocram_ecc_multi_error_info_t *info)
+{
+ assert(NULL != info);
+
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ info->OcramMultiErrorECCCipher =
+ (uint8_t)((base->OCRAM_ECC_MULTI_ERROR_INFO & FLEXRAM_OCRAM_ECC_MULTI_ERROR_INFO_OCRAM_ECCM_ERRED_ECC_MASK) >>
+ FLEXRAM_OCRAM_ECC_MULTI_ERROR_INFO_OCRAM_ECCM_ERRED_ECC_SHIFT);
+#else
+ info->OcramMultiErrorInfo = base->OCRAM_ECC_MULTI_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ info->OcramMultiErrorAddr = base->OCRAM_ECC_MULTI_ERROR_ADDR;
+ info->OcramMultiErrorDataLSB = base->OCRAM_ECC_MULTI_ERROR_DATA_LSB;
+ info->OcramMultiErrorDataMSB = base->OCRAM_ECC_MULTI_ERROR_DATA_MSB;
+}
+
+void FLEXRAM_GetItcmSingleErroInfo(FLEXRAM_Type *base, flexram_itcm_ecc_single_error_info_t *info)
+{
+ assert(NULL != info);
+
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ /* ECC error corresponding syndrome, which can be used to locate the Error bit using a look-up table. */
+ uint8_t singleErrorECCSyndrome = 0x00U;
+
+ info->ItcmSingleErrorTCMWriteRead =
+ (uint8_t)((base->ITCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFW_MASK) >>
+ FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFW_SHIFT);
+ info->ItcmSingleErrorTCMAccessSize =
+ (uint8_t)((base->ITCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFSIZ_SHIFT);
+ info->ItcmSingleErrorTCMMaster =
+ (uint8_t)((base->ITCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFMST_SHIFT);
+ info->ItcmSingleErrorTCMPrivilege =
+ (uint8_t)((base->ITCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFPRT_SHIFT);
+ singleErrorECCSyndrome =
+ (uint8_t)((base->ITCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_ITCM_ECC_SINGLE_ERROR_INFO_ITCM_ECCS_EFSYN_SHIFT);
+
+ for (uint8_t i = 0x00U; i < sizeof(ItcmLookUpTable) / sizeof(ItcmLookUpTable[0]); i++)
+ {
+ if (singleErrorECCSyndrome == ItcmLookUpTable[i])
+ {
+ info->ItcmSingleErrorBitPostion = i;
+ break;
+ }
+ }
+#else
+ info->ItcmSingleErrorInfo = base->ITCM_ECC_SINGLE_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->ItcmSingleErrorAddr = base->ITCM_ECC_SINGLE_ERROR_ADDR;
+ info->ItcmSingleErrorDataLSB = base->ITCM_ECC_SINGLE_ERROR_DATA_LSB;
+ info->ItcmSingleErrorDataMSB = base->ITCM_ECC_SINGLE_ERROR_DATA_MSB;
+}
+
+void FLEXRAM_GetItcmMultiErroInfo(FLEXRAM_Type *base, flexram_itcm_ecc_multi_error_info_t *info)
+{
+ assert(NULL != info);
+
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ info->ItcmMultiErrorTCMWriteRead =
+ (uint8_t)((base->ITCM_ECC_MULTI_ERROR_INFO & FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFW_MASK) >>
+ FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFW_SHIFT);
+ info->ItcmMultiErrorTCMAccessSize =
+ (uint8_t)((base->ITCM_ECC_MULTI_ERROR_INFO & FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSIZ_SHIFT);
+ info->ItcmMultiErrorTCMMaster =
+ (uint8_t)((base->ITCM_ECC_MULTI_ERROR_INFO & FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFMST_SHIFT);
+ info->ItcmMultiErrorTCMPrivilege =
+ (uint8_t)((base->ITCM_ECC_MULTI_ERROR_INFO & FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFPRT_SHIFT);
+ info->ItcmMultiErrorECCSyndrome =
+ (uint8_t)((base->ITCM_ECC_MULTI_ERROR_INFO & FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_ITCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSYN_SHIFT);
+#else
+ info->ItcmMultiErrorInfo = base->ITCM_ECC_MULTI_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->ItcmMultiErrorAddr = base->ITCM_ECC_MULTI_ERROR_ADDR;
+ info->ItcmMultiErrorDataLSB = base->ITCM_ECC_MULTI_ERROR_DATA_LSB;
+ info->ItcmMultiErrorDataMSB = base->ITCM_ECC_MULTI_ERROR_DATA_MSB;
+}
+
+void FLEXRAM_GetDtcmSingleErroInfo(FLEXRAM_Type *base, flexram_dtcm_ecc_single_error_info_t *info, uint8_t bank)
+{
+ assert(NULL != info);
+ assert((0x00U == bank) || (0x01U == bank));
+
+ if (0x00U == bank)
+ {
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ /* ECC error corresponding syndrome, which can be used to locate the Error bit using a look-up table. */
+ uint8_t singleErrorECCSyndrome = 0x00U;
+
+ info->DtcmSingleErrorTCMWriteRead =
+ (uint8_t)((base->D0TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFW_MASK) >>
+ FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFW_SHIFT);
+ info->DtcmSingleErrorTCMAccessSize =
+ (uint8_t)((base->D0TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFSIZ_SHIFT);
+ info->DtcmSingleErrorTCMMaster =
+ (uint8_t)((base->D0TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFMST_SHIFT);
+ info->DtcmSingleErrorTCMPrivilege =
+ (uint8_t)((base->D0TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFPRT_SHIFT);
+ singleErrorECCSyndrome =
+ (uint8_t)((base->D0TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_D0TCM_ECC_SINGLE_ERROR_INFO_D0TCM_ECCS_EFSYN_SHIFT);
+
+ for (uint8_t i = 0x00U; i < sizeof(ItcmLookUpTable) / sizeof(ItcmLookUpTable[0]); i++)
+ {
+ if (singleErrorECCSyndrome == ItcmLookUpTable[i])
+ {
+ info->DtcmSingleErrorBitPostion = i;
+ break;
+ }
+ }
+#else
+ info->DtcmSingleErrorInfo = base->D0TCM_ECC_SINGLE_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->DtcmSingleErrorAddr = base->D0TCM_ECC_SINGLE_ERROR_ADDR;
+ info->DtcmSingleErrorData = base->D0TCM_ECC_SINGLE_ERROR_DATA;
+ }
+ else
+ {
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ /* ECC error corresponding syndrome, which can be used to locate the Error bit using a look-up table. */
+ uint8_t singleErrorECCSyndrome = 0x00U;
+
+ info->DtcmSingleErrorTCMWriteRead =
+ (uint8_t)((base->D1TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFW_MASK) >>
+ FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFW_SHIFT);
+ info->DtcmSingleErrorTCMAccessSize =
+ (uint8_t)((base->D1TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFSIZ_SHIFT);
+ info->DtcmSingleErrorTCMMaster =
+ (uint8_t)((base->D1TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFMST_SHIFT);
+ info->DtcmSingleErrorTCMPrivilege =
+ (uint8_t)((base->D1TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFPRT_SHIFT);
+ singleErrorECCSyndrome =
+ (uint8_t)((base->D1TCM_ECC_SINGLE_ERROR_INFO & FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_D1TCM_ECC_SINGLE_ERROR_INFO_D1TCM_ECCS_EFSYN_SHIFT);
+
+ for (uint8_t i = 0x00U; i < sizeof(DtcmLookUpTable) / sizeof(DtcmLookUpTable[0]); i++)
+ {
+ if (singleErrorECCSyndrome == DtcmLookUpTable[i])
+ {
+ info->DtcmSingleErrorBitPostion = i;
+ break;
+ }
+ }
+#else
+ info->DtcmSingleErrorInfo = base->D1TCM_ECC_SINGLE_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->DtcmSingleErrorAddr = base->D1TCM_ECC_SINGLE_ERROR_ADDR;
+ info->DtcmSingleErrorData = base->D1TCM_ECC_SINGLE_ERROR_DATA;
+ }
+}
+
+void FLEXRAM_GetDtcmMultiErroInfo(FLEXRAM_Type *base, flexram_dtcm_ecc_multi_error_info_t *info, uint8_t bank)
+{
+ assert(NULL != info);
+ assert((0x00U == bank) || (0x01U == bank));
+
+ if (0x00U == bank)
+ {
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ info->DtcmMultiErrorTCMWriteRead =
+ (uint8_t)((base->D0TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFW_MASK) >>
+ FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFW_SHIFT);
+ info->DtcmMultiErrorTCMAccessSize =
+ (uint8_t)((base->D0TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFSIZ_SHIFT);
+ info->DtcmMultiErrorTCMMaster =
+ (uint8_t)((base->D0TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFMST_SHIFT);
+ info->DtcmMultiErrorTCMPrivilege =
+ (uint8_t)((base->D0TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFPRT_SHIFT);
+ info->DtcmMultiErrorECCSyndrome =
+ (uint8_t)((base->D0TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_D0TCM_ECC_MULTI_ERROR_INFO_D0TCM_ECCS_EFSYN_SHIFT);
+#else
+ info->DtcmMultiErrorInfo = base->D0TCM_ECC_MULTI_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->DtcmMultiErrorAddr = base->D0TCM_ECC_MULTI_ERROR_ADDR;
+ info->DtcmMultiErrorData = base->D0TCM_ECC_MULTI_ERROR_DATA;
+ }
+ else
+ {
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ info->DtcmMultiErrorTCMWriteRead =
+ (uint8_t)((base->D1TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFW_MASK) >>
+ FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_D1TCM_ECCS_EFW_SHIFT);
+ info->DtcmMultiErrorTCMAccessSize =
+ (uint8_t)((base->D1TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSIZ_MASK) >>
+ FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_D1TCM_ECCS_EFSIZ_SHIFT);
+ info->DtcmMultiErrorTCMMaster =
+ (uint8_t)((base->D1TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFMST_MASK) >>
+ FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_D1TCM_ECCS_EFMST_SHIFT);
+ info->DtcmMultiErrorTCMPrivilege =
+ (uint8_t)((base->D1TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFPRT_MASK) >>
+ FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_D1TCM_ECCS_EFPRT_SHIFT);
+ info->DtcmMultiErrorECCSyndrome =
+ (uint8_t)((base->D1TCM_ECC_MULTI_ERROR_INFO & FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_ITCM_ECCS_EFSYN_MASK) >>
+ FLEXRAM_D1TCM_ECC_MULTI_ERROR_INFO_D1TCM_ECCS_EFSYN_SHIFT);
+#else
+ info->DtcmMultiErrorInfo = base->D1TCM_ECC_MULTI_ERROR_INFO;
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+
+ info->DtcmMultiErrorAddr = base->D1TCM_ECC_MULTI_ERROR_ADDR;
+ info->DtcmMultiErrorData = base->D1TCM_ECC_MULTI_ERROR_DATA;
+ }
+}
+#endif /* FSL_FEATURE_FLEXRAM_HAS_ECC */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.h
new file mode 100644
index 0000000000..3c9a9c2db3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexram/fsl_flexram.h
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXRAM_H_
+#define _FSL_FLEXRAM_H_
+
+#include "fsl_common.h"
+#include "fsl_flexram_allocate.h"
+
+/*!
+ * @addtogroup flexram
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions.
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Driver version. */
+#define FSL_FLEXRAM_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 0U))
+/*@}*/
+
+/*! @brief Get ECC error detailed information. */
+#ifndef FLEXRAM_ECC_ERROR_DETAILED_INFO
+#define FLEXRAM_ECC_ERROR_DETAILED_INFO \
+ 0U /* Define to zero means get raw ECC error information, which needs parse it by user. */
+#endif
+
+/*! @brief Flexram write/read selection. */
+enum
+{
+ kFLEXRAM_Read = 0U, /*!< read */
+ kFLEXRAM_Write = 1U, /*!< write */
+};
+
+/*! @brief Interrupt status flag mask */
+enum
+{
+ kFLEXRAM_OCRAMAccessError = FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK, /*!< OCRAM accesses unallocated address */
+ kFLEXRAM_DTCMAccessError = FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK, /*!< DTCM accesses unallocated address */
+ kFLEXRAM_ITCMAccessError = FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK, /*!< ITCM accesses unallocated address */
+
+#if defined(FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR) && FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR
+ kFLEXRAM_OCRAMMagicAddrMatch = FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK, /*!< OCRAM magic address match */
+ kFLEXRAM_DTCMMagicAddrMatch = FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK, /*!< DTCM magic address match */
+ kFLEXRAM_ITCMMagicAddrMatch = FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK, /*!< ITCM magic address match */
+
+#if defined(FSL_FEATURE_FLEXRAM_HAS_ECC) && FSL_FEATURE_FLEXRAM_HAS_ECC
+ kFLEXRAM_OCRAMECCMultiError = FLEXRAM_INT_STATUS_OCRAM_ECC_ERRM_INT_MASK,
+ kFLEXRAM_OCRAMECCSingleError = FLEXRAM_INT_STATUS_OCRAM_ECC_ERRS_INT_MASK,
+ kFLEXRAM_ITCMECCMultiError = FLEXRAM_INT_STATUS_ITCM_ECC_ERRM_INT_MASK,
+ kFLEXRAM_ITCMECCSingleError = FLEXRAM_INT_STATUS_ITCM_ECC_ERRS_INT_MASK,
+ kFLEXRAM_D0TCMECCMultiError = FLEXRAM_INT_STATUS_D0TCM_ECC_ERRM_INT_MASK,
+ kFLEXRAM_D0TCMECCSingleError = FLEXRAM_INT_STATUS_D0TCM_ECC_ERRS_INT_MASK,
+ kFLEXRAM_D1TCMECCMultiError = FLEXRAM_INT_STATUS_D1TCM_ECC_ERRM_INT_MASK,
+ kFLEXRAM_D1TCMECCSingleError = FLEXRAM_INT_STATUS_D1TCM_ECC_ERRS_INT_MASK,
+
+ kFLEXRAM_InterruptStatusAll =
+ FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK | FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK |
+ FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK | FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK |
+ FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK | FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK |
+ FLEXRAM_INT_STATUS_OCRAM_ECC_ERRM_INT_MASK | FLEXRAM_INT_STATUS_OCRAM_ECC_ERRS_INT_MASK |
+ FLEXRAM_INT_STATUS_ITCM_ECC_ERRM_INT_MASK | FLEXRAM_INT_STATUS_ITCM_ECC_ERRS_INT_MASK |
+ FLEXRAM_INT_STATUS_D0TCM_ECC_ERRM_INT_MASK | FLEXRAM_INT_STATUS_D0TCM_ECC_ERRS_INT_MASK |
+ FLEXRAM_INT_STATUS_D1TCM_ECC_ERRM_INT_MASK | FLEXRAM_INT_STATUS_D1TCM_ECC_ERRS_INT_MASK,
+#else
+ kFLEXRAM_InterruptStatusAll = FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK | FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK |
+ FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK | FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK |
+ FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK | FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK,
+#endif /* FSL_FEATURE_FLEXRAM_HAS_ECC */
+
+/*!< all the interrupt status mask */
+#else
+ kFLEXRAM_InterruptStatusAll = FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK | FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK |
+ FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK, /*!< all the interrupt status mask */
+#endif /* FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR */
+
+};
+
+/*! @brief FLEXRAM TCM access mode.
+ * Fast access mode expected to be finished in 1-cycle;
+ * Wait access mode expected to be finished in 2-cycle.
+ * Wait access mode is a feature of the flexram and it should be used when
+ * the CPU clock is too fast to finish TCM access in 1-cycle.
+ * Normally, fast mode is the default mode, the efficiency of the TCM access will better.
+ */
+typedef enum _flexram_tcm_access_mode
+{
+ kFLEXRAM_TCMAccessFastMode = 0U, /*!< fast access mode */
+ kFLEXRAM_TCMAccessWaitMode = 1U, /*!< wait access mode */
+} flexram_tcm_access_mode_t;
+
+/*! @brief FLEXRAM TCM support size */
+enum
+{
+ kFLEXRAM_TCMSize32KB = 32 * 1024U, /*!< TCM total size be 32KB */
+ kFLEXRAM_TCMSize64KB = 64 * 1024U, /*!< TCM total size be 64KB */
+ kFLEXRAM_TCMSize128KB = 128 * 1024U, /*!< TCM total size be 128KB */
+ kFLEXRAM_TCMSize256KB = 256 * 1024U, /*!< TCM total size be 256KB */
+ kFLEXRAM_TCMSize512KB = 512 * 1024U, /*!< TCM total size be 512KB */
+};
+
+#if (defined(FSL_FEATURE_FLEXRAM_HAS_ECC) && FSL_FEATURE_FLEXRAM_HAS_ECC)
+/*! @brief FLEXRAM memory type, such as OCRAM/ITCM/D0TCM/D1TCM */
+typedef enum _flexram_memory_type
+{
+ kFLEXRAM_OCRAM = 0U, /*!< Memory type OCRAM */
+ kFLEXRAM_ITCM = 1U, /*!< Memory type ITCM */
+ kFLEXRAM_D0TCM = 2U, /*!< Memory type D0TCM */
+ kFLEXRAM_D1TCM = 3U, /*!< Memory type D1TCM */
+} flexram_memory_type_t;
+
+/*! @brief FLEXRAM error type, such as single bit error position, multi-bit error position */
+typedef struct _flexram_ecc_error_type
+{
+ uint8_t SingleBitPos; /*!< Bit position of the bit to inject ECC Error. */
+ uint8_t SecondBitPos; /*!< Bit position of the second bit to inject multi-bit ECC Error */
+ bool Fource1BitDataInversion; /*!< Force One 1-Bit Data Inversion (single-bit ECC error) on memory write access */
+ bool FourceOneNCDataInversion; /*!< Force One Non-correctable Data Inversion(multi-bit ECC error) on memory write
+ access */
+ bool FourceConti1BitDataInversion; /*!< Force Continuous 1-Bit Data Inversions (single-bit ECC error) on memory
+ write access */
+ bool FourceContiNCDataInversion; /*!< Force Continuous Non-correctable Data Inversions (multi-bit ECC error) on
+ memory write access */
+} flexram_ecc_error_type_t;
+
+/*! @brief FLEXRAM ocram ecc single error information, including single error information, error address, error data */
+typedef struct _flexram_ocram_ecc_single_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t OcramSingleErrorECCCipher; /*!< OCRAM corresponding ECC cipher of OCRAM single-bit ECC error. */
+ uint8_t OcramSingleErrorECCSyndrome; /*!< OCRAM corresponding ECC syndrome of OCRAM single-bit ECC error,
+ which can be used to locate the Error bit using a look-up table. */
+#else
+ uint32_t OcramSingleErrorInfo; /*!< Ocram single error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t OcramSingleErrorAddr; /*!< Ocram single error address */
+ uint32_t OcramSingleErrorDataLSB; /*!< Ocram single error data LSB */
+ uint32_t OcramSingleErrorDataMSB; /*!< Ocram single error data MSB */
+} flexram_ocram_ecc_single_error_info_t;
+
+/*! @brief FLEXRAM ocram ecc multiple error information, including multiple error information, error address, error data
+ */
+typedef struct _flexram_ocram_ecc_multi_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t OcramMultiErrorECCCipher; /*!< OCRAM corresponding ECC cipher of OCRAM multi-bit ECC error. */
+#else
+ uint32_t OcramMultiErrorInfo; /*!< Ocram single error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t OcramMultiErrorAddr; /*!< Ocram multiple error address */
+ uint32_t OcramMultiErrorDataLSB; /*!< Ocram multiple error data LSB */
+ uint32_t OcramMultiErrorDataMSB; /*!< Ocram multiple error data MSB */
+} flexram_ocram_ecc_multi_error_info_t;
+
+/*! @brief FLEXRAM itcm ecc single error information, including single error information, error address, error data */
+typedef struct _flexram_itcm_ecc_single_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t ItcmSingleErrorTCMWriteRead; /*!< itcm single-bit ECC error corresponding tcm_wr value, which is to tell
+ whether it is a write access(0x01) or a read access(0x00). */
+ uint8_t ItcmSingleErrorTCMAccessSize; /*!< itcm single-bit ECC error corresponding tcm access size,
+ which should be 3 (64bit). */
+ uint8_t ItcmSingleErrorTCMMaster; /*!< itcm single-bit ECC error corresponding tcm_master,
+ which is to tell the requester of the current access. */
+ uint8_t ItcmSingleErrorTCMPrivilege; /*!< itcm single-bit ECC error corresponding tcm_priv,
+ which is to tell the privilege level of access. */
+ uint8_t ItcmSingleErrorBitPostion; /*!< itcm single-bit ECC error corresponding bit postion. */
+#else
+ uint32_t ItcmSingleErrorInfo; /*!< itcm single error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t ItcmSingleErrorAddr; /*!< itcm single error address */
+ uint32_t ItcmSingleErrorDataLSB; /*!< itcm single error data LSB */
+ uint32_t ItcmSingleErrorDataMSB; /*!< itcm single error data MSB */
+} flexram_itcm_ecc_single_error_info_t;
+
+/*! @brief FLEXRAM itcm ecc multiple error information, including multiple error information, error address, error data
+ */
+typedef struct _flexram_itcm_ecc_multi_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t ItcmMultiErrorTCMWriteRead; /*!< itcm multiple-bit ECC error corresponding tcm_wr value, which is to tell
+ whether it is a write access(0x01) or a read access(0x00). */
+ uint8_t ItcmMultiErrorTCMAccessSize; /*!< itcm multiple-bit ECC error corresponding tcm access size,
+ which should be 3 (64bit). */
+ uint8_t ItcmMultiErrorTCMMaster; /*!< itcm multiple-bit ECC error corresponding tcm_master,
+ which is to tell the requester of the current access. */
+ uint8_t ItcmMultiErrorTCMPrivilege; /*!< itcm multiple-bit ECC error corresponding tcm_priv,
+ which is to tell the privilege level of access. */
+ uint8_t ItcmMultiErrorECCSyndrome; /*!< itcm multiple-bit ECC error corresponding syndrome,
+ which can not be used to locate the Error bit using a look-up table. */
+#else
+ uint32_t ItcmMultiErrorInfo; /*!< itcm multiple error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t ItcmMultiErrorAddr; /*!< itcm multiple error address */
+ uint32_t ItcmMultiErrorDataLSB; /*!< itcm multiple error data LSB */
+ uint32_t ItcmMultiErrorDataMSB; /*!< itcm multiple error data MSB */
+} flexram_itcm_ecc_multi_error_info_t;
+
+/*! @brief FLEXRAM dtcm ecc single error information, including single error information, error address, error data */
+typedef struct _flexram_dtcm_ecc_single_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t DtcmSingleErrorTCMWriteRead; /*!< dtcm single-bit ECC error corresponding tcm_wr value, which is to tell
+ whether it is a write access(0x01) or a read access(0x00). */
+ uint8_t DtcmSingleErrorTCMAccessSize; /*!< dtcm single-bit ECC error corresponding tcm access size,
+ which should be 2 (32bit). */
+ uint8_t DtcmSingleErrorTCMMaster; /*!< dtcm single-bit ECC error corresponding tcm_master,
+ which is to tell the requester of the current access. */
+ uint8_t DtcmSingleErrorTCMPrivilege; /*!< dtcm single-bit ECC error corresponding tcm_priv,
+ which is to tell the privilege level of access. */
+ uint8_t DtcmSingleErrorBitPostion; /*!< dtcm single-bit ECC error corresponding bit postion. */
+#else
+ uint32_t DtcmSingleErrorInfo; /*!< dtcm single error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t DtcmSingleErrorAddr; /*!< dtcm single error address */
+ uint32_t DtcmSingleErrorData; /*!< dtcm single error data */
+} flexram_dtcm_ecc_single_error_info_t;
+
+/*! @brief FLEXRAM dtcm ecc multiple error information, including multiple error information, error address, error data
+ */
+typedef struct _flexram_dtcm_ecc_multi_error_info
+{
+#if defined(FLEXRAM_ECC_ERROR_DETAILED_INFO) && FLEXRAM_ECC_ERROR_DETAILED_INFO
+ uint8_t DtcmMultiErrorTCMWriteRead; /*!< dtcm multiple-bit ECC error corresponding tcm_wr value, which is to tell
+ whether it is a write access(0x01) or a read access(0x00). */
+ uint8_t DtcmMultiErrorTCMAccessSize; /*!< dtcm multiple-bit ECC error corresponding tcm access size,
+ which should be 3 (64bit). */
+ uint8_t DtcmMultiErrorTCMMaster; /*!< dtcm multiple-bit ECC error corresponding tcm_master,
+ which is to tell the requester of the current access. */
+ uint8_t DtcmMultiErrorTCMPrivilege; /*!< dtcm multiple-bit ECC error corresponding tcm_priv,
+ which is to tell the privilege level of access. */
+ uint8_t DtcmMultiErrorECCSyndrome; /*!< dtcm multiple-bit ECC error corresponding syndrome,
+ which can not be used to locate the Error bit using a look-up table. */
+#else
+ uint32_t DtcmMultiErrorInfo; /*!< dtcm multiple error information, user should parse it by themself. */
+#endif /*FLEXRAM_ECC_ERROR_DETAILED_INFO*/
+ uint32_t DtcmMultiErrorAddr; /*!< dtcm multiple error address */
+ uint32_t DtcmMultiErrorData; /*!< dtcm multiple error data */
+} flexram_dtcm_ecc_multi_error_info_t;
+
+#endif /* FSL_FEATURE_FLEXRAM_HAS_ECC */
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief FLEXRAM module initialization function.
+ *
+ * @param base FLEXRAM base address.
+ */
+void FLEXRAM_Init(FLEXRAM_Type *base);
+
+/*!
+ * @brief De-initializes the FLEXRAM.
+ *
+ */
+void FLEXRAM_Deinit(FLEXRAM_Type *base);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+/*!
+ * @brief FLEXRAM module gets interrupt status.
+ *
+ * @param base FLEXRAM base address.
+ */
+static inline uint32_t FLEXRAM_GetInterruptStatus(FLEXRAM_Type *base)
+{
+ return base->INT_STATUS & (uint32_t)kFLEXRAM_InterruptStatusAll;
+}
+
+/*!
+ * @brief FLEXRAM module clears interrupt status.
+ *
+ * @param base FLEXRAM base address.
+ * @param status Status to be cleared.
+ */
+static inline void FLEXRAM_ClearInterruptStatus(FLEXRAM_Type *base, uint32_t status)
+{
+ base->INT_STATUS |= status;
+}
+
+/*!
+ * @brief FLEXRAM module enables interrupt status.
+ *
+ * @param base FLEXRAM base address.
+ * @param status Status to be enabled.
+ */
+static inline void FLEXRAM_EnableInterruptStatus(FLEXRAM_Type *base, uint32_t status)
+{
+ base->INT_STAT_EN |= status;
+}
+
+/*!
+ * @brief FLEXRAM module disable interrupt status.
+ *
+ * @param base FLEXRAM base address.
+ * @param status Status to be disabled.
+ */
+static inline void FLEXRAM_DisableInterruptStatus(FLEXRAM_Type *base, uint32_t status)
+{
+ base->INT_STAT_EN &= ~status;
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief FLEXRAM module enables interrupt.
+ *
+ * @param base FLEXRAM base address.
+ * @param status Status interrupt to be enabled.
+ */
+static inline void FLEXRAM_EnableInterruptSignal(FLEXRAM_Type *base, uint32_t status)
+{
+ base->INT_SIG_EN |= status;
+}
+
+/*!
+ * @brief FLEXRAM module disables interrupt.
+ *
+ * @param base FLEXRAM base address.
+ * @param status Status interrupt to be disabled.
+ */
+static inline void FLEXRAM_DisableInterruptSignal(FLEXRAM_Type *base, uint32_t status)
+{
+ base->INT_SIG_EN &= ~status;
+}
+/* @} */
+
+/*!
+ * @brief FLEXRAM module sets TCM read access mode
+ *
+ * @param base FLEXRAM base address.
+ * @param mode Access mode.
+ */
+static inline void FLEXRAM_SetTCMReadAccessMode(FLEXRAM_Type *base, flexram_tcm_access_mode_t mode)
+{
+ base->TCM_CTRL &= ~FLEXRAM_TCM_CTRL_TCM_RWAIT_EN_MASK;
+ base->TCM_CTRL |= (uint32_t)mode;
+}
+
+/*!
+ * @brief FLEXRAM module set TCM write access mode
+ *
+ * @param base FLEXRAM base address.
+ * @param mode Access mode.
+ */
+static inline void FLEXRAM_SetTCMWriteAccessMode(FLEXRAM_Type *base, flexram_tcm_access_mode_t mode)
+{
+ base->TCM_CTRL &= ~FLEXRAM_TCM_CTRL_TCM_WWAIT_EN_MASK;
+ base->TCM_CTRL |= (uint32_t)mode;
+}
+
+/*!
+ * @brief FLEXRAM module force ram clock on
+ *
+ * @param base FLEXRAM base address.
+ * @param enable Enable or disable clock force on.
+ */
+static inline void FLEXRAM_EnableForceRamClockOn(FLEXRAM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->TCM_CTRL |= FLEXRAM_TCM_CTRL_FORCE_CLK_ON_MASK;
+ }
+ else
+ {
+ base->TCM_CTRL &= ~FLEXRAM_TCM_CTRL_FORCE_CLK_ON_MASK;
+ }
+}
+
+#if defined(FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR) && FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR
+/*!
+ * @brief FLEXRAM OCRAM magic addr configuration.
+ * When read/write access hit magic address, it will generate interrupt.
+ * @param base FLEXRAM base address.
+ * @param magicAddr Magic address, the actual address bits [18:3] is corresponding to the register field [16:1].
+ * @param rwSel Read/write selection. 0 for read access while 1 for write access.
+ */
+static inline void FLEXRAM_SetOCRAMMagicAddr(FLEXRAM_Type *base, uint16_t magicAddr, uint32_t rwSel)
+{
+ base->OCRAM_MAGIC_ADDR = FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_WR_RD_SEL(rwSel) |
+ FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR((uint32_t)magicAddr >> 3);
+}
+
+/*!
+ * @brief FLEXRAM DTCM magic addr configuration.
+ * When read/write access hits magic address, it will generate interrupt.
+ * @param base FLEXRAM base address.
+ * @param magicAddr Magic address, the actual address bits [18:3] is corresponding to the register field [16:1].
+ * @param rwSel Read/write selection. 0 for read access while 1 write access.
+ */
+static inline void FLEXRAM_SetDTCMMagicAddr(FLEXRAM_Type *base, uint16_t magicAddr, uint32_t rwSel)
+{
+ base->DTCM_MAGIC_ADDR = FLEXRAM_DTCM_MAGIC_ADDR_DTCM_WR_RD_SEL(rwSel) |
+ FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR((uint32_t)magicAddr >> 3);
+}
+
+/*!
+ * @brief FLEXRAM ITCM magic addr configuration.
+ * When read/write access hits magic address, it will generate interrupt.
+ * @param base FLEXRAM base address.
+ * @param magicAddr Magic address, the actual address bits [18:3] is corresponding to the register field [16:1].
+ * @param rwSel Read/write selection. 0 for read access while 1 for write access.
+ */
+static inline void FLEXRAM_SetITCMMagicAddr(FLEXRAM_Type *base, uint16_t magicAddr, uint32_t rwSel)
+{
+ base->ITCM_MAGIC_ADDR = FLEXRAM_ITCM_MAGIC_ADDR_ITCM_WR_RD_SEL(rwSel) |
+ FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR((uint32_t)magicAddr >> 3);
+}
+#endif /* FSL_FEATURE_FLEXRAM_HAS_MAGIC_ADDR */
+
+#if (defined(FSL_FEATURE_FLEXRAM_HAS_ECC) && FSL_FEATURE_FLEXRAM_HAS_ECC)
+/*!
+ * @brief FLEXRAM get ocram ecc single error information.
+ * @param base FLEXRAM base address.
+ * @param OcramECCEnable ocram ecc enablement.
+ * @param TcmECCEnable tcm(itcm/d0tcm/d1tcm) ecc enablement.
+ */
+void FLEXRAM_EnableECC(FLEXRAM_Type *base, bool OcramECCEnable, bool TcmECCEnable);
+
+/*!
+ * @brief FLEXRAM ECC error injection.
+ * @param base FLEXRAM base address.
+ * @param memory memory type, such as OCRAM/ITCM/DTCM.
+ * @param error ECC error type.
+ */
+void FLEXRAM_ErrorInjection(FLEXRAM_Type *base, flexram_memory_type_t memory, flexram_ecc_error_type_t *error);
+
+/*!
+ * @brief FLEXRAM get ocram ecc single error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ */
+void FLEXRAM_GetOcramSingleErroInfo(FLEXRAM_Type *base, flexram_ocram_ecc_single_error_info_t *info);
+
+/*!
+ * @brief FLEXRAM get ocram ecc multiple error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ */
+void FLEXRAM_GetOcramMultiErroInfo(FLEXRAM_Type *base, flexram_ocram_ecc_multi_error_info_t *info);
+
+/*!
+ * @brief FLEXRAM get itcm ecc single error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ */
+void FLEXRAM_GetItcmSingleErroInfo(FLEXRAM_Type *base, flexram_itcm_ecc_single_error_info_t *info);
+
+/*!
+ * @brief FLEXRAM get itcm ecc multiple error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ */
+void FLEXRAM_GetItcmMultiErroInfo(FLEXRAM_Type *base, flexram_itcm_ecc_multi_error_info_t *info);
+
+/*!
+ * @brief FLEXRAM get d0tcm ecc single error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ * @param bank DTCM bank, 0 is D0TCM, 1 is D1TCM.
+ */
+void FLEXRAM_GetDtcmSingleErroInfo(FLEXRAM_Type *base, flexram_dtcm_ecc_single_error_info_t *info, uint8_t bank);
+
+/*!
+ * @brief FLEXRAM get d0tcm ecc multiple error information.
+ * @param base FLEXRAM base address.
+ * @param info ecc error information.
+ * @param bank DTCM bank, 0 is D0TCM, 1 is D1TCM.
+ */
+void FLEXRAM_GetDtcmMultiErroInfo(FLEXRAM_Type *base, flexram_dtcm_ecc_multi_error_info_t *info, uint8_t bank);
+
+#endif /* FSL_FEATURE_FLEXRAM_HAS_ECC */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.c
new file mode 100644
index 0000000000..71da8f1c92
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.c
@@ -0,0 +1,1271 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexspi.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexspi"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define FREQ_1MHz (1000000UL)
+#define FLEXSPI_DLLCR_DEFAULT (0x100UL)
+#define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0UL)
+
+enum
+{
+ kFLEXSPI_DelayCellUnitMin = 75, /* 75ps. */
+ kFLEXSPI_DelayCellUnitMax = 225, /* 225ps. */
+};
+
+enum
+{
+ kFLEXSPI_FlashASampleClockSlaveDelayLocked =
+ FLEXSPI_STS2_ASLVLOCK_MASK, /* Flash A sample clock slave delay line locked. */
+ kFLEXSPI_FlashASampleClockRefDelayLocked =
+ FLEXSPI_STS2_AREFLOCK_MASK, /* Flash A sample clock reference delay line locked. */
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK))
+ kFLEXSPI_FlashBSampleClockSlaveDelayLocked =
+ FLEXSPI_STS2_BSLVLOCK_MASK, /* Flash B sample clock slave delay line locked. */
+#endif
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BREFLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BREFLOCK))
+ kFLEXSPI_FlashBSampleClockRefDelayLocked =
+ FLEXSPI_STS2_BREFLOCK_MASK, /* Flash B sample clock reference delay line locked. */
+#endif
+};
+
+/*! @brief Common sets of flags used by the driver, _flexspi_flag_constants. */
+enum
+{
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kIrqFlags = kFLEXSPI_IpTxFifoWatermarkEmptyFlag | kFLEXSPI_IpRxFifoWatermarkAvailableFlag |
+ kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |
+ kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExecutionDoneFlag,
+
+ /*! Errors to check for. */
+ kErrorFlags = kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |
+ kFLEXSPI_IpCommandGrantTimeoutFlag,
+};
+
+/* FLEXSPI transfer state, _flexspi_transfer_state. */
+enum
+{
+ kFLEXSPI_Idle = 0x0U, /*!< Transfer is done. */
+ kFLEXSPI_BusyWrite = 0x1U, /*!< FLEXSPI is busy write transfer. */
+ kFLEXSPI_BusyRead = 0x2U, /*!< FLEXSPI is busy write transfer. */
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*flexspi_isr_t)(FLEXSPI_Type *base, flexspi_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static void FLEXSPI_Memset(void *src, uint8_t value, size_t length);
+
+/*!
+ * @brief Calculate flash A/B sample clock DLL.
+ *
+ * @param base FLEXSPI base pointer.
+ * @param config Flash configuration parameters.
+ */
+static uint32_t FLEXSPI_CalculateDll(FLEXSPI_Type *base, flexspi_device_config_t *config);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to flexspi bases for each instance. */
+static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
+
+/*! @brief Pointers to flexspi IRQ number for each instance. */
+static const IRQn_Type s_flexspiIrqs[] = FLEXSPI_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_flexspiClock[] = FLEXSPI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+/*! @brief Pointers to flexspi handles for each instance. */
+static flexspi_handle_t *s_flexspiHandle[ARRAY_SIZE(s_flexspiBases)];
+#endif
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET
+/*! @brief Pointers to FLEXSPI resets for each instance. */
+static const reset_ip_name_t s_flexspiResets[] = FLEXSPI_RSTS;
+#endif
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+/*! @brief Pointer to flexspi IRQ handler. */
+static flexspi_isr_t s_flexspiIsr;
+#endif
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/* To avoid compiler opitimizing this API into memset() in library. */
+#if defined(__ICCARM__)
+#pragma optimize = none
+#endif /* defined(__ICCARM__) */
+static void FLEXSPI_Memset(void *src, uint8_t value, size_t length)
+{
+ assert(src != NULL);
+ uint8_t *p = src;
+
+ for (uint32_t i = 0U; i < length; i++)
+ {
+ *p = value;
+ p++;
+ }
+}
+
+uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexspiBases); instance++)
+ {
+ if (s_flexspiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexspiBases));
+
+ return instance;
+}
+
+static uint32_t FLEXSPI_CalculateDll(FLEXSPI_Type *base, flexspi_device_config_t *config)
+{
+ bool isUnifiedConfig = true;
+ uint32_t flexspiDllValue;
+ uint32_t dllValue;
+ uint32_t temp;
+#if defined(FSL_FEATURE_FLEXSPI_DQS_DELAY_PS) && FSL_FEATURE_FLEXSPI_DQS_DELAY_PS
+ uint32_t internalDqsDelayPs = FSL_FEATURE_FLEXSPI_DQS_DELAY_PS;
+#endif
+ uint32_t rxSampleClock = (base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) >> FLEXSPI_MCR0_RXCLKSRC_SHIFT;
+ switch (rxSampleClock)
+ {
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackInternally:
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromDqsPad:
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromSckPad:
+ isUnifiedConfig = true;
+ break;
+ case (uint32_t)kFLEXSPI_ReadSampleClkExternalInputFromDqsPad:
+ if (config->isSck2Enabled)
+ {
+ isUnifiedConfig = true;
+ }
+ else
+ {
+ isUnifiedConfig = false;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ if (isUnifiedConfig)
+ {
+ flexspiDllValue = FLEXSPI_DLLCR_DEFAULT; /* 1 fixed delay cells in DLL delay chain) */
+ }
+ else
+ {
+ if (config->flexspiRootClk >= 100U * FREQ_1MHz)
+ {
+#if defined(FSL_FEATURE_FLEXSPI_DQS_DELAY_MIN) && FSL_FEATURE_FLEXSPI_DQS_DELAY_MIN
+ /* DLLEN = 1, SLVDLYTARGET = 0x0, */
+ flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x00);
+#else
+ /* DLLEN = 1, SLVDLYTARGET = 0xF, */
+ flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x0F);
+#endif
+ }
+ else
+ {
+ temp = (uint32_t)config->dataValidTime * 1000U; /* Convert data valid time in ns to ps. */
+ dllValue = temp / (uint32_t)kFLEXSPI_DelayCellUnitMin;
+ if (dllValue * (uint32_t)kFLEXSPI_DelayCellUnitMin < temp)
+ {
+ dllValue++;
+ }
+ flexspiDllValue = FLEXSPI_DLLCR_OVRDEN(1) | FLEXSPI_DLLCR_OVRDVAL(dllValue);
+ }
+ }
+ return flexspiDllValue;
+}
+
+status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check for error. */
+ status &= (uint32_t)kErrorFlags;
+ if (0U != status)
+ {
+ /* Select the correct error code.. */
+ if (0U != (status & (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag))
+ {
+ result = kStatus_FLEXSPI_SequenceExecutionTimeout;
+ }
+ else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag))
+ {
+ result = kStatus_FLEXSPI_IpCommandSequenceError;
+ }
+ else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag))
+ {
+ result = kStatus_FLEXSPI_IpCommandGrantTimeout;
+ }
+ else
+ {
+ assert(false);
+ }
+
+ /* Clear the flags. */
+ FLEXSPI_ClearInterruptStatusFlags(base, status);
+
+ /* Reset fifos. These flags clear automatically. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the FLEXSPI module and internal state.
+ *
+ * This function enables the clock for FLEXSPI and also configures the FLEXSPI with the
+ * input configure parameters. Users should call this function before any FLEXSPI operations.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param config FLEXSPI configure structure.
+ */
+void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config)
+{
+ uint32_t configValue = 0;
+ uint8_t i = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the flexspi clock */
+ (void)CLOCK_EnableClock(s_flexspiClock[FLEXSPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET
+ /* Reset the FLEXSPI module */
+ RESET_PeripheralReset(s_flexspiResets[FLEXSPI_GetInstance(base)]);
+#endif
+
+ /* Reset peripheral before configuring it. */
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+ FLEXSPI_SoftwareReset(base);
+
+ /* Configure MCR0 configuration items. */
+ configValue = FLEXSPI_MCR0_RXCLKSRC(config->rxSampleClock) | FLEXSPI_MCR0_DOZEEN(config->enableDoze) |
+ FLEXSPI_MCR0_IPGRANTWAIT(config->ipGrantTimeoutCycle) |
+ FLEXSPI_MCR0_AHBGRANTWAIT(config->ahbConfig.ahbGrantTimeoutCycle) |
+ FLEXSPI_MCR0_SCKFREERUNEN(config->enableSckFreeRunning) |
+ FLEXSPI_MCR0_HSEN(config->enableHalfSpeedAccess) |
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
+ FLEXSPI_MCR0_COMBINATIONEN(config->enableCombination) |
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)
+ FLEXSPI_MCR0_ATDFEN(config->ahbConfig.enableAHBWriteIpTxFifo) |
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)
+ FLEXSPI_MCR0_ARDFEN(config->ahbConfig.enableAHBWriteIpRxFifo) |
+#endif
+ FLEXSPI_MCR0_MDIS_MASK;
+ base->MCR0 = configValue;
+
+ /* Configure MCR1 configurations. */
+ configValue =
+ FLEXSPI_MCR1_SEQWAIT(config->seqTimeoutCycle) | FLEXSPI_MCR1_AHBBUSWAIT(config->ahbConfig.ahbBusTimeoutCycle);
+ base->MCR1 = configValue;
+
+ /* Configure MCR2 configurations. */
+ configValue = base->MCR2;
+ configValue &= ~(FLEXSPI_MCR2_RESUMEWAIT_MASK |
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)
+ FLEXSPI_MCR2_SCKBDIFFOPT_MASK |
+#endif
+ FLEXSPI_MCR2_SAMEDEVICEEN_MASK | FLEXSPI_MCR2_CLRAHBBUFOPT_MASK);
+ configValue |= FLEXSPI_MCR2_RESUMEWAIT(config->ahbConfig.resumeWaitCycle) |
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB
+ FLEXSPI_MCR2_RXCLKSRC_B(config->rxSampleClockPortB) |
+#endif
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF) && FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF
+ FLEXSPI_MCR2_RX_CLK_SRC_DIFF(config->rxSampleClockDiff) |
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)
+ FLEXSPI_MCR2_SCKBDIFFOPT(config->enableSckBDiffOpt) |
+#endif
+ FLEXSPI_MCR2_SAMEDEVICEEN(config->enableSameConfigForAll) |
+ FLEXSPI_MCR2_CLRAHBBUFOPT(config->ahbConfig.enableClearAHBBufferOpt);
+
+ base->MCR2 = configValue;
+
+ /* Configure AHB control items. */
+ configValue = base->AHBCR;
+ configValue &= ~(FLEXSPI_AHBCR_READADDROPT_MASK | FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_BUFFERABLEEN_MASK |
+ FLEXSPI_AHBCR_CACHABLEEN_MASK);
+ configValue |= FLEXSPI_AHBCR_READADDROPT(config->ahbConfig.enableReadAddressOpt) |
+ FLEXSPI_AHBCR_PREFETCHEN(config->ahbConfig.enableAHBPrefetch) |
+ FLEXSPI_AHBCR_BUFFERABLEEN(config->ahbConfig.enableAHBBufferable) |
+ FLEXSPI_AHBCR_CACHABLEEN(config->ahbConfig.enableAHBCachable);
+ base->AHBCR = configValue;
+
+ /* Configure AHB rx buffers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++)
+ {
+ configValue = base->AHBRXBUFCR0[i];
+
+ configValue &= ~(FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK |
+ FLEXSPI_AHBRXBUFCR0_MSTRID_MASK | FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK);
+ configValue |= FLEXSPI_AHBRXBUFCR0_PREFETCHEN(config->ahbConfig.buffer[i].enablePrefetch) |
+ FLEXSPI_AHBRXBUFCR0_PRIORITY(config->ahbConfig.buffer[i].priority) |
+ FLEXSPI_AHBRXBUFCR0_MSTRID(config->ahbConfig.buffer[i].masterIndex) |
+ FLEXSPI_AHBRXBUFCR0_BUFSZ((uint32_t)config->ahbConfig.buffer[i].bufferSize / 8U);
+ base->AHBRXBUFCR0[i] = configValue;
+ }
+
+ /* Configure IP Fifo watermarks. */
+ base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXWMRK_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_RXWMRK((uint32_t)config->rxWatermark / 8U - 1U);
+ base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXWMRK_MASK;
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_TXWMRK((uint32_t)config->txWatermark / 8U - 1U);
+
+ /* Reset flash size on all ports */
+ for (i = 0; i < (uint32_t)kFLEXSPI_PortCount; i++)
+ {
+ base->FLSHCR0[i] = 0;
+ }
+}
+
+/*!
+ * brief Gets default settings for FLEXSPI.
+ *
+ * param config FLEXSPI configuration structure.
+ */
+void FLEXSPI_GetDefaultConfig(flexspi_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ FLEXSPI_Memset(config, 0, sizeof(*config));
+
+ config->rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;
+ config->enableSckFreeRunning = false;
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
+ config->enableCombination = false;
+#endif
+ config->enableDoze = true;
+ config->enableHalfSpeedAccess = false;
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)
+ config->enableSckBDiffOpt = false;
+#endif
+ config->enableSameConfigForAll = false;
+ config->seqTimeoutCycle = 0xFFFFU;
+ config->ipGrantTimeoutCycle = 0xFFU;
+ config->txWatermark = 8;
+ config->rxWatermark = 8;
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)
+ config->ahbConfig.enableAHBWriteIpTxFifo = false;
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)
+ config->ahbConfig.enableAHBWriteIpRxFifo = false;
+#endif
+ config->ahbConfig.ahbGrantTimeoutCycle = 0xFFU;
+ config->ahbConfig.ahbBusTimeoutCycle = 0xFFFFU;
+ config->ahbConfig.resumeWaitCycle = 0x20U;
+ FLEXSPI_Memset(config->ahbConfig.buffer, 0, sizeof(config->ahbConfig.buffer));
+ /* Use invalid master ID 0xF and buffer size 0 for the first several buffers. */
+ for (uint8_t i = 0; i < ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U); i++)
+ {
+ config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */
+ config->ahbConfig.buffer[i].masterIndex = 0xFU; /* Invalid master index which is not used, so will never hit. */
+ config->ahbConfig.buffer[i].bufferSize =
+ 0; /* Default buffer size 0 for buffer0 to buffer(FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 3U)*/
+ }
+
+ for (uint8_t i = ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U);
+ i < (uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++)
+ {
+ config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */
+ config->ahbConfig.buffer[i].bufferSize = 256U; /* Default buffer size 256 bytes. */
+ }
+ config->ahbConfig.enableClearAHBBufferOpt = false;
+ config->ahbConfig.enableReadAddressOpt = false;
+ config->ahbConfig.enableAHBPrefetch = false;
+ config->ahbConfig.enableAHBBufferable = false;
+ config->ahbConfig.enableAHBCachable = false;
+}
+
+/*!
+ * brief Deinitializes the FLEXSPI module.
+ *
+ * Clears the FLEXSPI state and FLEXSPI module registers.
+ * param base FLEXSPI peripheral base address.
+ */
+void FLEXSPI_Deinit(FLEXSPI_Type *base)
+{
+ /* Reset peripheral. */
+ FLEXSPI_SoftwareReset(base);
+}
+
+/*!
+ * brief Update FLEXSPI DLL value depending on currently flexspi root clock.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param config Flash configuration parameters.
+ * param port FLEXSPI Operation port.
+ */
+void FLEXSPI_UpdateDllValue(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port)
+{
+ uint32_t configValue = 0;
+ uint32_t statusValue = 0;
+ uint8_t index = (uint8_t)port >> 1U; /* PortA with index 0, PortB with index 1. */
+
+ /* Wait for bus to be idle before changing flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ /* Configure DLL. */
+ configValue = FLEXSPI_CalculateDll(base, config);
+ base->DLLCR[index] = configValue;
+
+ /* Exit stop mode. */
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+
+ /* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */
+ if (index == 0U)
+ {
+ statusValue =
+ ((uint32_t)kFLEXSPI_FlashASampleClockSlaveDelayLocked | (uint32_t)kFLEXSPI_FlashASampleClockRefDelayLocked);
+ }
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK))
+ else
+ {
+ statusValue =
+ ((uint32_t)kFLEXSPI_FlashBSampleClockSlaveDelayLocked | (uint32_t)kFLEXSPI_FlashBSampleClockRefDelayLocked);
+ }
+#endif
+ if (0U != (configValue & FLEXSPI_DLLCR_DLLEN_MASK))
+ {
+#if defined(FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426) && (FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426)
+ if (config->isFroClockSource == false)
+#endif
+ {
+ /* Wait slave delay line locked and slave reference delay line locked. */
+ while ((base->STS2 & statusValue) != statusValue)
+ {
+ }
+ }
+
+ /* Wait at least 100 NOPs*/
+ for (uint8_t delay = 100U; delay > 0U; delay--)
+ {
+ __NOP();
+ }
+ }
+}
+
+/*!
+ * brief Configures the connected device parameter.
+ *
+ * This function configures the connected device relevant parameters, such as the size, command, and so on.
+ * The flash configuration value cannot have a default value. The user needs to configure it according to the
+ * connected device.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param config Flash configuration parameters.
+ * param port FLEXSPI Operation port.
+ */
+void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port)
+{
+ uint32_t configValue = 0;
+ uint8_t index = (uint8_t)port >> 1U; /* PortA with index 0, PortB with index 1. */
+
+ /* Wait for bus to be idle before changing flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ /* Configure flash size and address shift. */
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT) && (FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT)
+ base->FLSHCR0[port] = config->flashSize | FLEXSPI_FLSHCR0_ADDRSHIFT(config->addressShift);
+#else
+ base->FLSHCR0[port] = config->flashSize;
+#endif /* FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT */
+
+ /* Configure flash parameters. */
+ base->FLSHCR1[port] = FLEXSPI_FLSHCR1_CSINTERVAL(config->CSInterval) |
+ FLEXSPI_FLSHCR1_CSINTERVALUNIT(config->CSIntervalUnit) |
+ FLEXSPI_FLSHCR1_TCSH(config->CSHoldTime) | FLEXSPI_FLSHCR1_TCSS(config->CSSetupTime) |
+ FLEXSPI_FLSHCR1_CAS(config->columnspace) | FLEXSPI_FLSHCR1_WA(config->enableWordAddress);
+
+ /* Configure AHB operation items. */
+ configValue = base->FLSHCR2[port];
+
+ configValue &= ~(FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK | FLEXSPI_FLSHCR2_AWRWAIT_MASK | FLEXSPI_FLSHCR2_AWRSEQNUM_MASK |
+ FLEXSPI_FLSHCR2_AWRSEQID_MASK | FLEXSPI_FLSHCR2_ARDSEQNUM_MASK | FLEXSPI_FLSHCR2_ARDSEQID_MASK);
+
+ configValue |=
+ FLEXSPI_FLSHCR2_AWRWAITUNIT(config->AHBWriteWaitUnit) | FLEXSPI_FLSHCR2_AWRWAIT(config->AHBWriteWaitInterval);
+
+ if (config->AWRSeqNumber > 0U)
+ {
+ configValue |= FLEXSPI_FLSHCR2_AWRSEQID((uint32_t)config->AWRSeqIndex) |
+ FLEXSPI_FLSHCR2_AWRSEQNUM((uint32_t)config->AWRSeqNumber - 1U);
+ }
+
+ if (config->ARDSeqNumber > 0U)
+ {
+ configValue |= FLEXSPI_FLSHCR2_ARDSEQID((uint32_t)config->ARDSeqIndex) |
+ FLEXSPI_FLSHCR2_ARDSEQNUM((uint32_t)config->ARDSeqNumber - 1U);
+ }
+
+ base->FLSHCR2[port] = configValue;
+
+ /* Configure DLL. */
+ FLEXSPI_UpdateDllValue(base, config, port);
+
+ /* Step into stop mode. */
+ base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
+
+ /* Configure write mask. */
+ if (config->enableWriteMask)
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMOPT1_MASK;
+ }
+ else
+ {
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMOPT1_MASK;
+ }
+
+ if (index == 0U) /*PortA*/
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENA_MASK;
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENA(config->enableWriteMask);
+ }
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_FLSHCR4_WMENB)) && (FSL_FEATURE_FLEXSPI_HAS_NO_FLSHCR4_WMENB))
+ else
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENB_MASK;
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENB(config->enableWriteMask);
+ }
+#endif
+
+ /* Exit stop mode. */
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+
+ /* Wait for bus to be idle before use it access to external flash. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+}
+
+/*! brief Updates the LUT table.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param index From which index start to update. It could be any index of the LUT table, which
+ * also allows user to update command content inside a command. Each command consists of up to
+ * 8 instructions and occupy 4*32-bit memory.
+ * param cmd Command sequence array.
+ * param count Number of sequences.
+ */
+void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count)
+{
+ assert(index < 64U);
+
+ uint32_t i = 0;
+ volatile uint32_t *lutBase;
+
+ /* Wait for bus to be idle before changing flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ /* Unlock LUT for update. */
+#if !((defined(FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO)) && (FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO))
+ base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
+#endif
+ base->LUTCR = 0x02;
+
+ lutBase = &base->LUT[index];
+ for (i = 0; i < count; i++)
+ {
+ *lutBase++ = *cmd++;
+ }
+
+ /* Lock LUT. */
+#if !((defined(FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO)) && (FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO))
+ base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
+#endif
+ base->LUTCR = 0x01;
+}
+
+/*! brief Update read sample clock source
+ *
+ * param base FLEXSPI peripheral base address.
+ * param clockSource clockSource of type #flexspi_read_sample_clock_t
+ */
+void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource)
+{
+ uint32_t mcr0Val;
+
+ /* Wait for bus to be idle before changing flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ mcr0Val = base->MCR0;
+ mcr0Val &= ~FLEXSPI_MCR0_RXCLKSRC_MASK;
+ mcr0Val |= FLEXSPI_MCR0_RXCLKSRC(clockSource);
+ base->MCR0 = mcr0Val;
+
+ /* Reset peripheral. */
+ FLEXSPI_SoftwareReset(base);
+}
+
+/*!
+ * brief Sends a buffer of data bytes using blocking method.
+ * note This function blocks via polling until all bytes have been sent.
+ * param base FLEXSPI peripheral base address
+ * param buffer The data bytes to send
+ * param size The number of data bytes to send
+ * retval kStatus_Success write success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size)
+{
+ uint32_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
+ uint32_t status;
+ status_t result = kStatus_Success;
+ uint32_t i = 0;
+
+ /* Send data buffer */
+ while (0U != size)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag))
+ {
+ }
+
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Write watermark level data into tx fifo . */
+ if (size >= 8U * txWatermark)
+ {
+ for (i = 0U; i < 2U * txWatermark; i++)
+ {
+ base->TFDR[i] = *(uint32_t *)(void *)buffer;
+ buffer += 4U;
+ }
+
+ size = size - 8U * txWatermark;
+ }
+ else
+ {
+ /* Write word aligned data into tx fifo. */
+ for (i = 0U; i < (size / 4U); i++)
+ {
+ base->TFDR[i] = *(uint32_t *)(void *)buffer;
+ buffer += 4U;
+ }
+
+ /* Adjust size by the amount processed. */
+ size -= 4U * i;
+
+ /* Write word un-aligned data into tx fifo. */
+ if (0x00U != size)
+ {
+ uint32_t tempVal = 0x00U;
+
+ for (uint32_t j = 0U; j < size; j++)
+ {
+ tempVal |= ((uint32_t)*buffer++ << (8U * j));
+ }
+
+ base->TFDR[i] = tempVal;
+ }
+
+ size = 0U;
+ }
+
+ /* Push a watermark level data into IP TX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Receives a buffer of data bytes using a blocking method.
+ * note This function blocks via polling until all bytes have been sent.
+ * param base FLEXSPI peripheral base address
+ * param buffer The data bytes to send
+ * param size The number of data bytes to receive
+ * retval kStatus_Success read success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size)
+{
+ uint32_t rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
+ uint32_t status;
+ status_t result = kStatus_Success;
+ uint32_t i = 0;
+ bool isReturn = false;
+
+ /* Send data buffer */
+ while (0U != size)
+ {
+ if (size >= 8U * rxWatermark)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag))
+ {
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if (kStatus_Success != result)
+ {
+ isReturn = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Wait fill level. This also checks for errors. */
+ while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U))
+ {
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+
+ if (kStatus_Success != result)
+ {
+ isReturn = true;
+ break;
+ }
+ }
+ }
+
+ if (isReturn)
+ {
+ break;
+ }
+
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Read watermark level data from rx fifo. */
+ if (size >= 8U * rxWatermark)
+ {
+ for (i = 0U; i < 2U * rxWatermark; i++)
+ {
+ *(uint32_t *)(void *)buffer = base->RFDR[i];
+ buffer += 4U;
+ }
+
+ size = size - 8U * rxWatermark;
+ }
+ else
+ {
+ /* Read word aligned data from rx fifo. */
+ for (i = 0U; i < (size / 4U); i++)
+ {
+ *(uint32_t *)(void *)buffer = base->RFDR[i];
+ buffer += 4U;
+ }
+
+ /* Adjust size by the amount processed. */
+ size -= 4U * i;
+
+ /* Read word un-aligned data from rx fifo. */
+ if (0x00U != size)
+ {
+ uint32_t tempVal = base->RFDR[i];
+
+ for (i = 0U; i < size; i++)
+ {
+ *buffer++ = ((uint8_t)(tempVal >> (8U * i)) & 0xFFU);
+ }
+ }
+
+ size = 0;
+ }
+
+ /* Pop out a watermark level datas from IP RX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Execute command to transfer a buffer data bytes using a blocking method.
+ * param base FLEXSPI peripheral base address
+ * param xfer pointer to the transfer structure.
+ * retval kStatus_Success command transfer success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer)
+{
+ uint32_t configValue = 0;
+ status_t result = kStatus_Success;
+
+ /* Clear sequence pointer before sending data to external devices. */
+ base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
+
+ /* Clear former pending status before start this transfer. */
+ base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
+ FLEXSPI_INTR_IPCMDGE_MASK;
+
+ /* Configure base address. */
+ base->IPCR0 = xfer->deviceAddress;
+
+ /* Reset fifos. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+
+ /* Configure data size. */
+ if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
+ {
+ configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
+ }
+
+ /* Configure sequence ID. */
+ configValue |=
+ FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
+ base->IPCR1 = configValue;
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+
+ if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
+ {
+ result = FLEXSPI_WriteBlocking(base, (uint8_t *)xfer->data, xfer->dataSize);
+ }
+ else if (xfer->cmdType == kFLEXSPI_Read)
+ {
+ result = FLEXSPI_ReadBlocking(base, (uint8_t *)xfer->data, xfer->dataSize);
+ }
+ else
+ {
+ /* Empty else. */
+ }
+
+ /* Wait for bus to be idle before changing flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ if (xfer->cmdType == kFLEXSPI_Command)
+ {
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the FLEXSPI handle which is used in transactional functions.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure to store the transfer state.
+ * param callback pointer to user callback function.
+ * param userData user parameter passed to the callback function.
+ */
+void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base,
+ flexspi_handle_t *handle,
+ flexspi_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = FLEXSPI_GetInstance(base);
+
+ /* Zero handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_flexspiHandle[instance] = handle;
+ s_flexspiIsr = FLEXSPI_TransferHandleIRQ;
+#endif
+
+ /* Enable NVIC interrupt. */
+ (void)EnableIRQ(s_flexspiIrqs[instance]);
+}
+
+/*!
+ * brief Performs a interrupt non-blocking transfer on the FLEXSPI bus.
+ *
+ * note Calling the API returns immediately after transfer initiates. The user needs
+ * to call FLEXSPI_GetTransferCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer
+ * is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark level, or
+ * FLEXSPI could not read data properly.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * param xfer pointer to flexspi_transfer_t structure.
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_FLEXSPI_Busy Previous transmission still not finished.
+ */
+status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer)
+{
+ uint32_t configValue = 0;
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+ assert(NULL != xfer);
+
+ /* Check if the I2C bus is idle - if not return busy status. */
+ if (handle->state != (uint32_t)kFLEXSPI_Idle)
+ {
+ result = kStatus_FLEXSPI_Busy;
+ }
+ else
+ {
+ handle->data = (uint8_t *)xfer->data;
+ handle->dataSize = xfer->dataSize;
+ handle->transferTotalSize = xfer->dataSize;
+ handle->state = (xfer->cmdType == kFLEXSPI_Read) ? (uint32_t)kFLEXSPI_BusyRead : (uint32_t)kFLEXSPI_BusyWrite;
+
+ /* Clear sequence pointer before sending data to external devices. */
+ base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
+
+ /* Clear former pending status before start this transfer. */
+ base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
+ FLEXSPI_INTR_IPCMDGE_MASK;
+
+ /* Configure base address. */
+ base->IPCR0 = xfer->deviceAddress;
+
+ /* Reset fifos. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+
+ /* Configure data size. */
+ if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
+ {
+ configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
+ }
+
+ /* Configure sequence ID. */
+ configValue |=
+ FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
+ base->IPCR1 = configValue;
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+
+ if (handle->state == (uint32_t)kFLEXSPI_BusyRead)
+ {
+ FLEXSPI_EnableInterrupts(base, (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag |
+ (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag |
+ (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);
+ }
+ else
+ {
+ FLEXSPI_EnableInterrupts(
+ base, (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag | (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag | (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count)
+{
+ assert(NULL != handle);
+
+ status_t result = kStatus_Success;
+
+ if (handle->state == (uint32_t)kFLEXSPI_Idle)
+ {
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferTotalSize - handle->dataSize;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Aborts an interrupt non-blocking transfer early.
+ *
+ * note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state
+ */
+void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ FLEXSPI_DisableInterrupts(base, (uint32_t)kIrqFlags);
+ handle->state = (uint32_t)kFLEXSPI_Idle;
+}
+
+/*!
+ * brief Master interrupt handler.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure.
+ */
+void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle)
+{
+ uint32_t status;
+ status_t result;
+ uint32_t intEnableStatus;
+ uint32_t txWatermark;
+ uint32_t rxWatermark;
+ uint32_t i = 0;
+
+ status = base->INTR;
+ intEnableStatus = base->INTEN;
+
+ /* Check if interrupt is enabled and status is alerted. */
+ if ((status & intEnableStatus) != 0U)
+ {
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if ((result != kStatus_Success) && (handle->completionCallback != NULL))
+ {
+ FLEXSPI_TransferAbort(base, handle);
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+ else
+ {
+ if ((0U != (status & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag)) &&
+ (handle->state == (uint32_t)kFLEXSPI_BusyRead))
+ {
+ rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
+
+ /* Read watermark level data from rx fifo . */
+ if (handle->dataSize >= 8U * rxWatermark)
+ {
+ /* Read watermark level data from rx fifo . */
+ for (i = 0U; i < 2U * rxWatermark; i++)
+ {
+ *(uint32_t *)(void *)handle->data = base->RFDR[i];
+ handle->data += 4U;
+ }
+
+ handle->dataSize = handle->dataSize - 8U * rxWatermark;
+ }
+ else
+ {
+ /* Read word aligned data from rx fifo. */
+ for (i = 0U; i < (handle->dataSize / 4U); i++)
+ {
+ *(uint32_t *)(void *)handle->data = base->RFDR[i];
+ handle->data += 4U;
+ }
+
+ /* Adjust size by the amount processed. */
+ handle->dataSize -= 4U * i;
+
+ /* Read word un-aligned data from rx fifo. */
+ if (0x00U != handle->dataSize)
+ {
+ uint32_t tempVal = base->RFDR[i];
+
+ for (i = 0U; i < handle->dataSize; i++)
+ {
+ *handle->data++ = ((uint8_t)(tempVal >> (8U * i)) & 0xFFU);
+ }
+ }
+
+ handle->dataSize = 0;
+ }
+ /* Pop out a watermark level data from IP RX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;
+ }
+
+ if (0U != (status & (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag))
+ {
+ base->INTR |= (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag;
+
+ FLEXSPI_TransferAbort(base, handle);
+
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* TX FIFO empty interrupt, push watermark level data into tx FIFO. */
+ if ((0U != (status & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag)) &&
+ (handle->state == (uint32_t)kFLEXSPI_BusyWrite))
+ {
+ if (0U != handle->dataSize)
+ {
+ txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
+ /* Write watermark level data into tx fifo . */
+ if (handle->dataSize >= 8U * txWatermark)
+ {
+ for (i = 0; i < 2U * txWatermark; i++)
+ {
+ base->TFDR[i] = *(uint32_t *)(void *)handle->data;
+ handle->data += 4U;
+ }
+
+ handle->dataSize = handle->dataSize - 8U * txWatermark;
+ }
+ else
+ {
+ /* Write word aligned data into tx fifo. */
+ for (i = 0U; i < (handle->dataSize / 4U); i++)
+ {
+ base->TFDR[i] = *(uint32_t *)(void *)handle->data;
+ handle->data += 4U;
+ }
+
+ /* Adjust size by the amount processed. */
+ handle->dataSize -= 4U * i;
+
+ /* Write word un-aligned data into tx fifo. */
+ if (0x00U != handle->dataSize)
+ {
+ uint32_t tempVal = 0x00U;
+
+ for (uint32_t j = 0U; j < handle->dataSize; j++)
+ {
+ tempVal |= ((uint32_t)*handle->data++ << (8U * j));
+ }
+
+ base->TFDR[i] = tempVal;
+ }
+
+ handle->dataSize = 0;
+ }
+
+ /* Push a watermark level data into IP TX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;
+ }
+ }
+ else
+ {
+ /* Empty else */
+ }
+ }
+ }
+ else
+ {
+ /* Empty else */
+ }
+}
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+#if defined(FLEXSPI)
+void FLEXSPI_DriverIRQHandler(void);
+void FLEXSPI_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FLEXSPI0)
+void FLEXSPI0_DriverIRQHandler(void);
+void FLEXSPI0_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#if defined(FLEXSPI1)
+void FLEXSPI1_DriverIRQHandler(void);
+void FLEXSPI1_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(LSIO__FLEXSPI0)
+void LSIO_OCTASPI0_INT_DriverIRQHandler(void);
+void LSIO_OCTASPI0_INT_DriverIRQHandler(void)
+{
+ s_flexspiIsr(LSIO__FLEXSPI0, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#if defined(LSIO__FLEXSPI1)
+void LSIO_OCTASPI1_INT_DriverIRQHandler(void);
+void LSIO_OCTASPI1_INT_DriverIRQHandler(void)
+{
+ s_flexspiIsr(LSIO__FLEXSPI1, s_flexspiHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1
+
+void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void);
+void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void)
+{
+ /* If handle is registered, treat the transfer function is enabled. */
+ if (NULL != s_flexspiHandle[0])
+ {
+ s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);
+ }
+ if (NULL != s_flexspiHandle[1])
+ {
+ s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);
+ }
+}
+#endif
+
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.h
new file mode 100644
index 0000000000..935d92dd71
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi.h
@@ -0,0 +1,886 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __FSL_FLEXSPI_H_
+#define __FSL_FLEXSPI_H_
+
+#include <stddef.h>
+#include "fsl_device_registers.h"
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup flexspi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FLEXSPI driver version. */
+#define FSL_FLEXSPI_DRIVER_VERSION (MAKE_VERSION(2, 5, 0))
+/*@}*/
+
+#define FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNTn(0)
+
+/*! @brief Formula to form FLEXSPI instructions in LUT table. */
+#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 Status structure of FLEXSPI.*/
+enum
+{
+ kStatus_FLEXSPI_Busy = MAKE_STATUS(kStatusGroup_FLEXSPI, 0), /*!< FLEXSPI is busy */
+ kStatus_FLEXSPI_SequenceExecutionTimeout = MAKE_STATUS(kStatusGroup_FLEXSPI, 1), /*!< Sequence execution timeout
+ error occurred during FLEXSPI transfer. */
+ kStatus_FLEXSPI_IpCommandSequenceError = MAKE_STATUS(kStatusGroup_FLEXSPI, 2), /*!< IP command Sequence execution
+ timeout error occurred during FLEXSPI transfer. */
+ kStatus_FLEXSPI_IpCommandGrantTimeout = MAKE_STATUS(kStatusGroup_FLEXSPI, 3), /*!< IP command grant timeout error
+ occurred during FLEXSPI transfer. */
+};
+
+/*! @brief CMD definition of FLEXSPI, use to form LUT instruction, _flexspi_command. */
+enum
+{
+ kFLEXSPI_Command_STOP = 0x00U, /*!< Stop execution, deassert CS. */
+ kFLEXSPI_Command_SDR = 0x01U, /*!< Transmit Command code to Flash, using SDR mode. */
+ kFLEXSPI_Command_RADDR_SDR = 0x02U, /*!< Transmit Row Address to Flash, using SDR mode. */
+ kFLEXSPI_Command_CADDR_SDR = 0x03U, /*!< Transmit Column Address to Flash, using SDR mode. */
+ kFLEXSPI_Command_MODE1_SDR = 0x04U, /*!< Transmit 1-bit Mode bits to Flash, using SDR mode. */
+ kFLEXSPI_Command_MODE2_SDR = 0x05U, /*!< Transmit 2-bit Mode bits to Flash, using SDR mode. */
+ kFLEXSPI_Command_MODE4_SDR = 0x06U, /*!< Transmit 4-bit Mode bits to Flash, using SDR mode. */
+ kFLEXSPI_Command_MODE8_SDR = 0x07U, /*!< Transmit 8-bit Mode bits to Flash, using SDR mode. */
+ kFLEXSPI_Command_WRITE_SDR = 0x08U, /*!< Transmit Programming Data to Flash, using SDR mode. */
+ kFLEXSPI_Command_READ_SDR = 0x09U, /*!< Receive Read Data from Flash, using SDR mode. */
+ kFLEXSPI_Command_LEARN_SDR = 0x0AU, /*!< Receive Read Data or Preamble bit from Flash, SDR mode. */
+ kFLEXSPI_Command_DATSZ_SDR = 0x0BU, /*!< Transmit Read/Program Data size (byte) to Flash, SDR mode. */
+ kFLEXSPI_Command_DUMMY_SDR = 0x0CU, /*!< Leave data lines undriven by FlexSPI controller.*/
+ kFLEXSPI_Command_DUMMY_RWDS_SDR = 0x0DU, /*!< Leave data lines undriven by FlexSPI controller,
+ dummy cycles decided by RWDS. */
+ kFLEXSPI_Command_DDR = 0x21U, /*!< Transmit Command code to Flash, using DDR mode. */
+ kFLEXSPI_Command_RADDR_DDR = 0x22U, /*!< Transmit Row Address to Flash, using DDR mode. */
+ kFLEXSPI_Command_CADDR_DDR = 0x23U, /*!< Transmit Column Address to Flash, using DDR mode. */
+ kFLEXSPI_Command_MODE1_DDR = 0x24U, /*!< Transmit 1-bit Mode bits to Flash, using DDR mode. */
+ kFLEXSPI_Command_MODE2_DDR = 0x25U, /*!< Transmit 2-bit Mode bits to Flash, using DDR mode. */
+ kFLEXSPI_Command_MODE4_DDR = 0x26U, /*!< Transmit 4-bit Mode bits to Flash, using DDR mode. */
+ kFLEXSPI_Command_MODE8_DDR = 0x27U, /*!< Transmit 8-bit Mode bits to Flash, using DDR mode. */
+ kFLEXSPI_Command_WRITE_DDR = 0x28U, /*!< Transmit Programming Data to Flash, using DDR mode. */
+ kFLEXSPI_Command_READ_DDR = 0x29U, /*!< Receive Read Data from Flash, using DDR mode. */
+ kFLEXSPI_Command_LEARN_DDR = 0x2AU, /*!< Receive Read Data or Preamble bit from Flash, DDR mode. */
+ kFLEXSPI_Command_DATSZ_DDR = 0x2BU, /*!< Transmit Read/Program Data size (byte) to Flash, DDR mode. */
+ kFLEXSPI_Command_DUMMY_DDR = 0x2CU, /*!< Leave data lines undriven by FlexSPI controller.*/
+ kFLEXSPI_Command_DUMMY_RWDS_DDR = 0x2DU, /*!< Leave data lines undriven by FlexSPI controller,
+ dummy cycles decided by RWDS. */
+ kFLEXSPI_Command_JUMP_ON_CS = 0x1FU, /*!< Stop execution, deassert CS and save operand[7:0] as the
+ instruction start pointer for next sequence */
+};
+
+/*! @brief pad definition of FLEXSPI, use to form LUT instruction. */
+typedef enum _flexspi_pad
+{
+ kFLEXSPI_1PAD = 0x00U, /*!< Transmit command/address and transmit/receive data only through DATA0/DATA1. */
+ kFLEXSPI_2PAD = 0x01U, /*!< Transmit command/address and transmit/receive data only through DATA[1:0]. */
+ kFLEXSPI_4PAD = 0x02U, /*!< Transmit command/address and transmit/receive data only through DATA[3:0]. */
+ kFLEXSPI_8PAD = 0x03U, /*!< Transmit command/address and transmit/receive data only through DATA[7:0]. */
+} flexspi_pad_t;
+
+/*! @brief FLEXSPI interrupt status flags.*/
+typedef enum _flexspi_flags
+{
+ kFLEXSPI_SequenceExecutionTimeoutFlag = FLEXSPI_INTEN_SEQTIMEOUTEN_MASK, /*!< Sequence execution timeout. */
+#if defined(FSL_FEATURE_FLEXSPI_HAS_INTEN_AHBBUSERROREN) && FSL_FEATURE_FLEXSPI_HAS_INTEN_AHBBUSERROREN
+ kFLEXSPI_AhbBusErrorFlag = FLEXSPI_INTEN_AHBBUSERROREN_MASK, /*!< AHB Bus error flag. */
+#else
+ kFLEXSPI_AhbBusTimeoutFlag = FLEXSPI_INTEN_AHBBUSTIMEOUTEN_MASK, /*!< AHB Bus timeout. */
+#endif
+ kFLEXSPI_SckStoppedBecauseTxEmptyFlag =
+ FLEXSPI_INTEN_SCKSTOPBYWREN_MASK, /*!< SCK is stopped during command
+ sequence because Async TX FIFO empty. */
+ kFLEXSPI_SckStoppedBecauseRxFullFlag =
+ FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK, /*!< SCK is stopped during command
+ sequence because Async RX FIFO full. */
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) && (FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN))
+ kFLEXSPI_DataLearningFailedFlag = FLEXSPI_INTEN_DATALEARNFAILEN_MASK, /*!< Data learning failed. */
+#endif
+ kFLEXSPI_IpTxFifoWatermarkEmptyFlag = FLEXSPI_INTEN_IPTXWEEN_MASK, /*!< IP TX FIFO WaterMark empty. */
+ kFLEXSPI_IpRxFifoWatermarkAvailableFlag = FLEXSPI_INTEN_IPRXWAEN_MASK, /*!< IP RX FIFO WaterMark available. */
+ kFLEXSPI_AhbCommandSequenceErrorFlag =
+ FLEXSPI_INTEN_AHBCMDERREN_MASK, /*!< AHB triggered Command Sequences Error. */
+ kFLEXSPI_IpCommandSequenceErrorFlag = FLEXSPI_INTEN_IPCMDERREN_MASK, /*!< IP triggered Command Sequences Error. */
+ kFLEXSPI_AhbCommandGrantTimeoutFlag =
+ FLEXSPI_INTEN_AHBCMDGEEN_MASK, /*!< AHB triggered Command Sequences Grant Timeout. */
+ kFLEXSPI_IpCommandGrantTimeoutFlag =
+ FLEXSPI_INTEN_IPCMDGEEN_MASK, /*!< IP triggered Command Sequences Grant Timeout. */
+ kFLEXSPI_IpCommandExecutionDoneFlag =
+ FLEXSPI_INTEN_IPCMDDONEEN_MASK, /*!< IP triggered Command Sequences Execution finished. */
+ kFLEXSPI_AllInterruptFlags = 0xFFFU, /*!< All flags. */
+} flexspi_flags_t;
+
+/*! @brief FLEXSPI sample clock source selection for Flash Reading.*/
+typedef enum _flexspi_read_sample_clock
+{
+ kFLEXSPI_ReadSampleClkLoopbackInternally = 0x0U, /*!< Dummy Read strobe generated by FlexSPI Controller
+ and loopback internally. */
+ kFLEXSPI_ReadSampleClkLoopbackFromDqsPad = 0x1U, /*!< Dummy Read strobe generated by FlexSPI Controller
+ and loopback from DQS pad. */
+ kFLEXSPI_ReadSampleClkLoopbackFromSckPad = 0x2U, /*!< SCK output clock and loopback from SCK pad. */
+ kFLEXSPI_ReadSampleClkExternalInputFromDqsPad = 0x3U, /*!< Flash provided Read strobe and input from DQS pad. */
+} flexspi_read_sample_clock_t;
+
+/*! @brief FLEXSPI interval unit for flash device select.*/
+typedef enum _flexspi_cs_interval_cycle_unit
+{
+ kFLEXSPI_CsIntervalUnit1SckCycle = 0x0U, /*!< Chip selection interval: CSINTERVAL * 1 serial clock cycle. */
+ kFLEXSPI_CsIntervalUnit256SckCycle = 0x1U, /*!< Chip selection interval: CSINTERVAL * 256 serial clock cycle. */
+} flexspi_cs_interval_cycle_unit_t;
+
+/*! @brief FLEXSPI AHB wait interval unit for writing.*/
+typedef enum _flexspi_ahb_write_wait_unit
+{
+ kFLEXSPI_AhbWriteWaitUnit2AhbCycle = 0x0U, /*!< AWRWAIT unit is 2 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit8AhbCycle = 0x1U, /*!< AWRWAIT unit is 8 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit32AhbCycle = 0x2U, /*!< AWRWAIT unit is 32 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit128AhbCycle = 0x3U, /*!< AWRWAIT unit is 128 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit512AhbCycle = 0x4U, /*!< AWRWAIT unit is 512 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit2048AhbCycle = 0x5U, /*!< AWRWAIT unit is 2048 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit8192AhbCycle = 0x6U, /*!< AWRWAIT unit is 8192 ahb clock cycle. */
+ kFLEXSPI_AhbWriteWaitUnit32768AhbCycle = 0x7U, /*!< AWRWAIT unit is 32768 ahb clock cycle. */
+} flexspi_ahb_write_wait_unit_t;
+
+/*! @brief Error Code when IP command Error detected.*/
+typedef enum _flexspi_ip_error_code
+{
+ kFLEXSPI_IpCmdErrorNoError = 0x0U, /*!< No error. */
+ kFLEXSPI_IpCmdErrorJumpOnCsInIpCmd = 0x2U, /*!< IP command with JMP_ON_CS instruction used. */
+ kFLEXSPI_IpCmdErrorUnknownOpCode = 0x3U, /*!< Unknown instruction opcode in the sequence. */
+ kFLEXSPI_IpCmdErrorSdrDummyInDdrSequence = 0x4U, /*!< Instruction DUMMY_SDR/DUMMY_RWDS_SDR
+ used in DDR sequence. */
+ kFLEXSPI_IpCmdErrorDdrDummyInSdrSequence = 0x5U, /*!< Instruction DUMMY_DDR/DUMMY_RWDS_DDR
+ used in SDR sequence. */
+ kFLEXSPI_IpCmdErrorInvalidAddress = 0x6U, /*!< Flash access start address exceed the whole
+ flash address range (A1/A2/B1/B2). */
+ kFLEXSPI_IpCmdErrorSequenceExecutionTimeout = 0xEU, /*!< Sequence execution timeout. */
+ kFLEXSPI_IpCmdErrorFlashBoundaryAcrosss = 0xFU, /*!< Flash boundary crossed. */
+} flexspi_ip_error_code_t;
+
+/*! @brief Error Code when AHB command Error detected.*/
+typedef enum _flexspi_ahb_error_code
+{
+ kFLEXSPI_AhbCmdErrorNoError = 0x0U, /*!< No error. */
+ kFLEXSPI_AhbCmdErrorJumpOnCsInWriteCmd = 0x2U, /*!< AHB Write command with JMP_ON_CS instruction
+ used in the sequence. */
+ kFLEXSPI_AhbCmdErrorUnknownOpCode = 0x3U, /*!< Unknown instruction opcode in the sequence. */
+ kFLEXSPI_AhbCmdErrorSdrDummyInDdrSequence = 0x4U, /*!< Instruction DUMMY_SDR/DUMMY_RWDS_SDR used
+ in DDR sequence. */
+ kFLEXSPI_AhbCmdErrorDdrDummyInSdrSequence = 0x5U, /*!< Instruction DUMMY_DDR/DUMMY_RWDS_DDR
+ used in SDR sequence. */
+ kFLEXSPI_AhbCmdSequenceExecutionTimeout = 0x6U, /*!< Sequence execution timeout. */
+} flexspi_ahb_error_code_t;
+
+/*! @brief FLEXSPI operation port select.*/
+typedef enum _flexspi_port
+{
+ kFLEXSPI_PortA1 = 0x0U, /*!< Access flash on A1 port. */
+ kFLEXSPI_PortA2, /*!< Access flash on A2 port. */
+#if !((defined(FSL_FEATURE_FLEXSPI_NO_SUPPORT_PORTB)) && (FSL_FEATURE_FLEXSPI_NO_SUPPORT_PORTB))
+ kFLEXSPI_PortB1, /*!< Access flash on B1 port. */
+ kFLEXSPI_PortB2, /*!< Access flash on B2 port. */
+#endif
+ kFLEXSPI_PortCount
+} flexspi_port_t;
+
+/*! @brief Trigger source of current command sequence granted by arbitrator.*/
+typedef enum _flexspi_arb_command_source
+{
+ kFLEXSPI_AhbReadCommand = 0x0U,
+ kFLEXSPI_AhbWriteCommand = 0x1U,
+ kFLEXSPI_IpCommand = 0x2U,
+ kFLEXSPI_SuspendedCommand = 0x3U,
+} flexspi_arb_command_source_t;
+
+/*! @brief Command type. */
+typedef enum _flexspi_command_type
+{
+ kFLEXSPI_Command, /*!< FlexSPI operation: Only command, both TX and Rx buffer are ignored. */
+ kFLEXSPI_Config, /*!< FlexSPI operation: Configure device mode, the TX fifo size is fixed in LUT. */
+ kFLEXSPI_Read, /* /!< FlexSPI operation: Read, only Rx Buffer is effective. */
+ kFLEXSPI_Write, /* /!< FlexSPI operation: Read, only Tx Buffer is effective. */
+} flexspi_command_type_t;
+
+typedef struct _flexspi_ahbBuffer_config
+{
+ uint8_t priority; /*!< This priority for AHB Master Read which this AHB RX Buffer is assigned. */
+ uint8_t masterIndex; /*!< AHB Master ID the AHB RX Buffer is assigned. */
+ uint16_t bufferSize; /*!< AHB buffer size in byte. */
+ bool enablePrefetch; /*!< AHB Read Prefetch Enable for current AHB RX Buffer corresponding Master, allows
+ prefetch disable/enable separately for each master. */
+} flexspi_ahbBuffer_config_t;
+
+/*! @brief FLEXSPI configuration structure. */
+typedef struct _flexspi_config
+{
+ flexspi_read_sample_clock_t rxSampleClock; /*!< Sample Clock source selection for Flash Reading. */
+ bool enableSckFreeRunning; /*!< Enable/disable SCK output free-running. */
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
+ bool enableCombination; /*!< Enable/disable combining PORT A and B Data Pins
+ (SIOA[3:0] and SIOB[3:0]) to support Flash Octal mode. */
+#endif
+ bool enableDoze; /*!< Enable/disable doze mode support. */
+ bool enableHalfSpeedAccess; /*!< Enable/disable divide by 2 of the clock for half
+ speed commands. */
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB
+ flexspi_read_sample_clock_t rxSampleClockPortB; /*!< Sample Clock source_b selection for Flash Reading. */
+#endif
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF) && FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF
+ bool rxSampleClockDiff; /*!< Sample Clock source or source_b selection for Flash Reading. */
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)
+ bool enableSckBDiffOpt; /*!< Enable/disable SCKB pad use as SCKA differential clock
+ output, when enable, Port B flash access is not available. */
+#endif
+ bool enableSameConfigForAll; /*!< Enable/disable same configuration for all connected devices
+ when enabled, same configuration in FLASHA1CRx is applied to all. */
+ uint16_t seqTimeoutCycle; /*!< Timeout wait cycle for command sequence execution,
+ timeout after ahbGrantTimeoutCyle*1024 serial root clock cycles. */
+ uint8_t ipGrantTimeoutCycle; /*!< Timeout wait cycle for IP command grant, timeout after
+ ipGrantTimeoutCycle*1024 AHB clock cycles. */
+ uint8_t txWatermark; /*!< FLEXSPI IP transmit watermark value. */
+ uint8_t rxWatermark; /*!< FLEXSPI receive watermark value. */
+ struct
+ {
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)
+ bool enableAHBWriteIpTxFifo; /*!< Enable AHB bus write access to IP TX FIFO. */
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)
+ bool enableAHBWriteIpRxFifo; /*!< Enable AHB bus write access to IP RX FIFO. */
+#endif
+ uint8_t ahbGrantTimeoutCycle; /*!< Timeout wait cycle for AHB command grant,
+ timeout after ahbGrantTimeoutCyle*1024 AHB clock cycles. */
+ uint16_t ahbBusTimeoutCycle; /*!< Timeout wait cycle for AHB read/write access,
+ timeout after ahbBusTimeoutCycle*1024 AHB clock cycles. */
+ uint8_t resumeWaitCycle; /*!< Wait cycle for idle state before suspended command sequence
+ resume, timeout after ahbBusTimeoutCycle AHB clock cycles. */
+ flexspi_ahbBuffer_config_t buffer[FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT]; /*!< AHB buffer size. */
+ bool enableClearAHBBufferOpt; /*!< Enable/disable automatically clean AHB RX Buffer and TX Buffer
+ when FLEXSPI returns STOP mode ACK. */
+ bool enableReadAddressOpt; /*!< Enable/disable remove AHB read burst start address alignment limitation.
+ when enable, there is no AHB read burst start address alignment limitation. */
+ bool enableAHBPrefetch; /*!< Enable/disable AHB read prefetch feature, when enabled, FLEXSPI
+ will fetch more data than current AHB burst. */
+ bool enableAHBBufferable; /*!< Enable/disable AHB bufferable write access support, when enabled,
+ FLEXSPI return before waiting for command execution finished. */
+ bool enableAHBCachable; /*!< Enable AHB bus cachable read access support. */
+ } ahbConfig;
+} flexspi_config_t;
+
+/*! @brief External device configuration items. */
+typedef struct _flexspi_device_config
+{
+ uint32_t flexspiRootClk; /*!< FLEXSPI serial root clock. */
+ bool isSck2Enabled; /*!< FLEXSPI use SCK2. */
+ uint32_t flashSize; /*!< Flash size in KByte. */
+#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT) && (FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT)
+ bool addressShift; /*!< Address shift. */
+#endif /* FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT */
+ flexspi_cs_interval_cycle_unit_t CSIntervalUnit; /*!< CS interval unit, 1 or 256 cycle. */
+ uint16_t CSInterval; /*!< CS line assert interval, multiply CS interval unit to
+ get the CS line assert interval cycles. */
+ uint8_t CSHoldTime; /*!< CS line hold time. */
+ uint8_t CSSetupTime; /*!< CS line setup time. */
+ uint8_t dataValidTime; /*!< Data valid time for external device. */
+ uint8_t columnspace; /*!< Column space size. */
+ bool enableWordAddress; /*!< If enable word address.*/
+ uint8_t AWRSeqIndex; /*!< Sequence ID for AHB write command. */
+ uint8_t AWRSeqNumber; /*!< Sequence number for AHB write command. */
+ uint8_t ARDSeqIndex; /*!< Sequence ID for AHB read command. */
+ uint8_t ARDSeqNumber; /*!< Sequence number for AHB read command. */
+ flexspi_ahb_write_wait_unit_t AHBWriteWaitUnit; /*!< AHB write wait unit. */
+ uint16_t AHBWriteWaitInterval; /*!< AHB write wait interval, multiply AHB write interval
+ unit to get the AHB write wait cycles. */
+ bool enableWriteMask; /*!< Enable/Disable FLEXSPI drive DQS pin as write mask
+ when writing to external device. */
+#if defined(FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426) && (FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426)
+ bool isFroClockSource; /*!< Is FRO clock source or not. */
+#endif
+} flexspi_device_config_t;
+
+/*! @brief Transfer structure for FLEXSPI. */
+typedef struct _flexspi_transfer
+{
+ uint32_t deviceAddress; /*!< Operation device address. */
+ flexspi_port_t port; /*!< Operation port. */
+ flexspi_command_type_t cmdType; /*!< Execution command type. */
+ uint8_t seqIndex; /*!< Sequence ID for command. */
+ uint8_t SeqNumber; /*!< Sequence number for command. */
+ uint32_t *data; /*!< Data buffer. */
+ size_t dataSize; /*!< Data size in bytes. */
+} flexspi_transfer_t;
+
+/* Forward declaration of the handle typedef. */
+typedef struct _flexspi_handle flexspi_handle_t;
+
+/*! @brief FLEXSPI transfer callback function. */
+typedef void (*flexspi_transfer_callback_t)(FLEXSPI_Type *base,
+ flexspi_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief Transfer handle structure for FLEXSPI. */
+struct _flexspi_handle
+{
+ uint32_t state; /*!< Internal state for FLEXSPI transfer */
+ uint8_t *data; /*!< Data buffer. */
+ size_t dataSize; /*!< Remaining Data size in bytes. */
+ size_t transferTotalSize; /*!< Total Data size in bytes. */
+ flexspi_transfer_callback_t completionCallback; /*!< Callback for users while transfer finish or error occurred */
+ void *userData; /*!< FLEXSPI callback function parameter.*/
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus. */
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Get the instance number for FLEXSPI.
+ *
+ * @param base FLEXSPI base pointer.
+ */
+uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base);
+
+/*!
+ * @brief Check and clear IP command execution errors.
+ *
+ * @param base FLEXSPI base pointer.
+ * @param status interrupt status.
+ */
+status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status);
+
+/*!
+ * @brief Initializes the FLEXSPI module and internal state.
+ *
+ * This function enables the clock for FLEXSPI and also configures the FLEXSPI with the
+ * input configure parameters. Users should call this function before any FLEXSPI operations.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param config FLEXSPI configure structure.
+ */
+void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config);
+
+/*!
+ * @brief Gets default settings for FLEXSPI.
+ *
+ * @param config FLEXSPI configuration structure.
+ */
+void FLEXSPI_GetDefaultConfig(flexspi_config_t *config);
+
+/*!
+ * @brief Deinitializes the FLEXSPI module.
+ *
+ * Clears the FLEXSPI state and FLEXSPI module registers.
+ * @param base FLEXSPI peripheral base address.
+ */
+void FLEXSPI_Deinit(FLEXSPI_Type *base);
+
+/*!
+ * @brief Update FLEXSPI DLL value depending on currently flexspi root clock.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param config Flash configuration parameters.
+ * @param port FLEXSPI Operation port.
+ */
+void FLEXSPI_UpdateDllValue(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port);
+
+/*!
+ * @brief Configures the connected device parameter.
+ *
+ * This function configures the connected device relevant parameters, such as the size, command, and so on.
+ * The flash configuration value cannot have a default value. The user needs to configure it according to the
+ * connected device.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param config Flash configuration parameters.
+ * @param port FLEXSPI Operation port.
+ */
+void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port);
+
+/*!
+ * @brief Software reset for the FLEXSPI logic.
+ *
+ * This function sets the software reset flags for both AHB and buffer domain and
+ * resets both AHB buffer and also IP FIFOs.
+ *
+ * @param base FLEXSPI peripheral base address.
+ */
+static inline void FLEXSPI_SoftwareReset(FLEXSPI_Type *base)
+{
+ base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
+ while (0U != (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK))
+ {
+ }
+}
+
+/*!
+ * @brief Enables or disables the FLEXSPI module.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param enable True means enable FLEXSPI, false means disable.
+ */
+static inline void FLEXSPI_Enable(FLEXSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+ }
+ else
+ {
+ base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+/*!
+ * @brief Enables the FLEXSPI interrupts.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param mask FLEXSPI interrupt source.
+ */
+static inline void FLEXSPI_EnableInterrupts(FLEXSPI_Type *base, uint32_t mask)
+{
+ base->INTEN |= mask;
+}
+
+/*!
+ * @brief Disable the FLEXSPI interrupts.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param mask FLEXSPI interrupt source.
+ */
+static inline void FLEXSPI_DisableInterrupts(FLEXSPI_Type *base, uint32_t mask)
+{
+ base->INTEN &= ~mask;
+}
+
+/* @} */
+
+/*! @name DMA control */
+/*@{*/
+
+/*!
+ * @brief Enables or disables FLEXSPI IP Tx FIFO DMA requests.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param enable Enable flag for transmit DMA request. Pass true for enable, false for disable.
+ */
+static inline void FLEXSPI_EnableTxDMA(FLEXSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_TXDMAEN_MASK;
+ }
+ else
+ {
+ base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXDMAEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables or disables FLEXSPI IP Rx FIFO DMA requests.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param enable Enable flag for receive DMA request. Pass true for enable, false for disable.
+ */
+static inline void FLEXSPI_EnableRxDMA(FLEXSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_RXDMAEN_MASK;
+ }
+ else
+ {
+ base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXDMAEN_MASK;
+ }
+}
+
+/*!
+ * @brief Gets FLEXSPI IP tx fifo address for DMA transfer.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @retval The tx fifo address.
+ */
+static inline uint32_t FLEXSPI_GetTxFifoAddress(FLEXSPI_Type *base)
+{
+ return (uint32_t)&base->TFDR[0];
+}
+
+/*!
+ * @brief Gets FLEXSPI IP rx fifo address for DMA transfer.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @retval The rx fifo address.
+ */
+static inline uint32_t FLEXSPI_GetRxFifoAddress(FLEXSPI_Type *base)
+{
+ return (uint32_t)&base->RFDR[0];
+}
+
+/*@}*/
+
+/*! @name FIFO control */
+/*@{*/
+
+/*! @brief Clears the FLEXSPI IP FIFO logic.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param txFifo Pass true to reset TX FIFO.
+ * @param rxFifo Pass true to reset RX FIFO.
+ */
+static inline void FLEXSPI_ResetFifos(FLEXSPI_Type *base, bool txFifo, bool rxFifo)
+{
+ if (txFifo)
+ {
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ }
+ if (rxFifo)
+ {
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+ }
+}
+
+/*!
+ * @brief Gets the valid data entries in the FLEXSPI FIFOs.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param[out] txCount Pointer through which the current number of bytes in the transmit FIFO is returned.
+ * Pass NULL if this value is not required.
+ * @param[out] rxCount Pointer through which the current number of bytes in the receive FIFO is returned.
+ * Pass NULL if this value is not required.
+ */
+static inline void FLEXSPI_GetFifoCounts(FLEXSPI_Type *base, size_t *txCount, size_t *rxCount)
+{
+ if (NULL != txCount)
+ {
+ *txCount = (((base->IPTXFSTS) & FLEXSPI_IPTXFSTS_FILL_MASK) >> FLEXSPI_IPTXFSTS_FILL_SHIFT) * 8U;
+ }
+ if (NULL != rxCount)
+ {
+ *rxCount = (((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U;
+ }
+}
+
+/*@}*/
+
+/*!
+ * @name Status
+ * @{
+ */
+/*!
+ * @brief Get the FLEXSPI interrupt status flags.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @retval interrupt status flag, use status flag to AND #flexspi_flags_t could get the related status.
+ */
+static inline uint32_t FLEXSPI_GetInterruptStatusFlags(FLEXSPI_Type *base)
+{
+ return base->INTR;
+}
+
+/*!
+ * @brief Get the FLEXSPI interrupt status flags.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param mask FLEXSPI interrupt source.
+ */
+static inline void FLEXSPI_ClearInterruptStatusFlags(FLEXSPI_Type *base, uint32_t mask)
+{
+ base->INTR |= mask;
+}
+
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) && (FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN))
+/*! @brief Gets the sampling clock phase selection after Data Learning.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param portAPhase Pointer to a uint8_t type variable to receive the selected clock phase on PORTA.
+ * @param portBPhase Pointer to a uint8_t type variable to receive the selected clock phase on PORTB.
+ */
+static inline void FLEXSPI_GetDataLearningPhase(FLEXSPI_Type *base, uint8_t *portAPhase, uint8_t *portBPhase)
+{
+ if (portAPhase != NULL)
+ {
+ *portAPhase = (uint8_t)((base->STS0 & FLEXSPI_STS0_DATALEARNPHASEA_MASK) >> FLEXSPI_STS0_DATALEARNPHASEA_SHIFT);
+ }
+
+#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS0_DATALEARNPHASEB)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS0_DATALEARNPHASEB))
+ if (portBPhase != NULL)
+ {
+ *portBPhase = (uint8_t)((base->STS0 & FLEXSPI_STS0_DATALEARNPHASEB_MASK) >> FLEXSPI_STS0_DATALEARNPHASEB_SHIFT);
+ }
+#endif
+}
+#endif
+
+/*! @brief Gets the trigger source of current command sequence granted by arbitrator.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @retval trigger source of current command sequence.
+ */
+static inline flexspi_arb_command_source_t FLEXSPI_GetArbitratorCommandSource(FLEXSPI_Type *base)
+{
+ return (flexspi_arb_command_source_t)(
+ (uint32_t)((base->STS0 & FLEXSPI_STS0_ARBCMDSRC_MASK) >> FLEXSPI_STS0_ARBCMDSRC_SHIFT));
+}
+
+/*! @brief Gets the error code when IP command error detected.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param index Pointer to a uint8_t type variable to receive the sequence index when error detected.
+ * @retval error code when IP command error detected.
+ */
+static inline flexspi_ip_error_code_t FLEXSPI_GetIPCommandErrorCode(FLEXSPI_Type *base, uint8_t *index)
+{
+ *index = (uint8_t)((base->STS1 & FLEXSPI_STS1_IPCMDERRID_MASK) >> FLEXSPI_STS1_IPCMDERRID_SHIFT);
+ return (flexspi_ip_error_code_t)(
+ (uint32_t)((base->STS1 & FLEXSPI_STS1_IPCMDERRCODE_MASK) >> FLEXSPI_STS1_IPCMDERRCODE_SHIFT));
+}
+
+/*! @brief Gets the error code when AHB command error detected.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param index Pointer to a uint8_t type variable to receive the sequence index when error detected.
+ * @retval error code when AHB command error detected.
+ */
+static inline flexspi_ahb_error_code_t FLEXSPI_GetAHBCommandErrorCode(FLEXSPI_Type *base, uint8_t *index)
+{
+ *index = (uint8_t)(base->STS1 & FLEXSPI_STS1_AHBCMDERRID_MASK) >> FLEXSPI_STS1_AHBCMDERRID_SHIFT;
+ return (flexspi_ahb_error_code_t)(
+ (uint32_t)((base->STS1 & FLEXSPI_STS1_AHBCMDERRCODE_MASK) >> FLEXSPI_STS1_AHBCMDERRCODE_SHIFT));
+}
+
+/*! @brief Returns whether the bus is idle.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @retval true Bus is idle.
+ * @retval false Bus is busy.
+ */
+static inline bool FLEXSPI_GetBusIdleStatus(FLEXSPI_Type *base)
+{
+ return (0U != (base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK)) && (0U != (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK));
+}
+/*@}*/
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*! @brief Update read sample clock source
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param clockSource clockSource of type #flexspi_read_sample_clock_t
+ */
+void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource);
+
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_IP_PARALLEL_MODE) && FSL_FEATURE_FLEXSPI_HAS_NO_IP_PARALLEL_MODE)
+/*! @brief Enables/disables the FLEXSPI IP command parallel mode.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param enable True means enable parallel mode, false means disable parallel mode.
+ */
+static inline void FLEXSPI_EnableIPParallelMode(FLEXSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->IPCR1 |= FLEXSPI_IPCR1_IPAREN_MASK;
+ }
+ else
+ {
+ base->IPCR1 &= ~FLEXSPI_IPCR1_IPAREN_MASK;
+ }
+}
+#endif
+
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_AHB_PARALLEL_MODE) && FSL_FEATURE_FLEXSPI_HAS_NO_AHB_PARALLEL_MODE)
+/*! @brief Enables/disables the FLEXSPI AHB command parallel mode.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param enable True means enable parallel mode, false means disable parallel mode.
+ */
+static inline void FLEXSPI_EnableAHBParallelMode(FLEXSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->AHBCR |= FLEXSPI_AHBCR_APAREN_MASK;
+ }
+ else
+ {
+ base->AHBCR &= ~FLEXSPI_AHBCR_APAREN_MASK;
+ }
+}
+#endif
+
+/*! @brief Updates the LUT table.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param index From which index start to update. It could be any index of the LUT table, which
+ * also allows user to update command content inside a command. Each command consists of up to
+ * 8 instructions and occupy 4*32-bit memory.
+ * @param cmd Command sequence array.
+ * @param count Number of sequences.
+ */
+void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count);
+
+/*!
+ * @brief Writes data into FIFO.
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param data The data bytes to send
+ * @param fifoIndex Destination fifo index.
+ */
+static inline void FLEXSPI_WriteData(FLEXSPI_Type *base, uint32_t data, uint8_t fifoIndex)
+{
+ base->TFDR[fifoIndex] = data;
+}
+
+/*!
+ * @brief Receives data from data FIFO.
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param fifoIndex Source fifo index.
+ * @return The data in the FIFO.
+ */
+static inline uint32_t FLEXSPI_ReadData(FLEXSPI_Type *base, uint8_t fifoIndex)
+{
+ return base->RFDR[fifoIndex];
+}
+
+/*!
+ * @brief Sends a buffer of data bytes using blocking method.
+ * @note This function blocks via polling until all bytes have been sent.
+ * @param base FLEXSPI peripheral base address
+ * @param buffer The data bytes to send
+ * @param size The number of data bytes to send
+ * @retval kStatus_Success write success without error
+ * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size);
+
+/*!
+ * @brief Receives a buffer of data bytes using a blocking method.
+ * @note This function blocks via polling until all bytes have been sent.
+ * @param base FLEXSPI peripheral base address
+ * @param buffer The data bytes to send
+ * @param size The number of data bytes to receive
+ * @retval kStatus_Success read success without error
+ * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected
+ * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size);
+
+/*!
+ * @brief Execute command to transfer a buffer data bytes using a blocking method.
+ * @param base FLEXSPI peripheral base address
+ * @param xfer pointer to the transfer structure.
+ * @retval kStatus_Success command transfer success without error
+ * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer);
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXSPI handle which is used in transactional functions.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle pointer to flexspi_handle_t structure to store the transfer state.
+ * @param callback pointer to user callback function.
+ * @param userData user parameter passed to the callback function.
+ */
+void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base,
+ flexspi_handle_t *handle,
+ flexspi_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a interrupt non-blocking transfer on the FLEXSPI bus.
+ *
+ * @note Calling the API returns immediately after transfer initiates. The user needs
+ * to call FLEXSPI_GetTransferCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer
+ * is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark level, or
+ * FLEXSPI could not read data properly.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * @param xfer pointer to flexspi_transfer_t structure.
+ * @retval kStatus_Success Successfully start the data transmission.
+ * @retval kStatus_FLEXSPI_Busy Previous transmission still not finished.
+ */
+status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer);
+
+/*!
+ * @brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_InvalidArgument count is Invalid.
+ * @retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts an interrupt non-blocking transfer early.
+ *
+ * @note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle pointer to flexspi_handle_t structure which stores the transfer state
+ */
+void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle);
+
+/*!
+ * @brief Master interrupt handler.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle pointer to flexspi_handle_t structure.
+ */
+void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle);
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus. */
+/*@}*/
+
+#endif /* __FSL_FLEXSPI_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_dma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_dma.h
new file mode 100644
index 0000000000..101af6d913
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_dma.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2019-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXSPI_DMA_H_
+#define _FSL_FLEXSPI_DMA_H_
+
+#include "fsl_flexspi.h"
+#include "fsl_dma.h"
+
+/*!
+ * @addtogroup flexspi_dma
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FLEXSPI DMA driver version 2.2.1. */
+#define FSL_FLEXSPI_DMA_DRIVER_VERSION (MAKE_VERSION(2, 2, 1))
+/*@}*/
+
+typedef struct _flexspi_dma_handle flexspi_dma_handle_t;
+
+/*! @brief FLEXSPI dma transfer callback function for finish and error */
+typedef void (*flexspi_dma_callback_t)(FLEXSPI_Type *base,
+ flexspi_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief dma transfer configuration */
+typedef enum _flexspi_dma_ntransfer_size
+{
+ kFLEXPSI_DMAnSize1Bytes = 0x1U, /*!< Source/Destination data transfer size is 1 byte every time */
+ kFLEXPSI_DMAnSize2Bytes = 0x2U, /*!< Source/Destination data transfer size is 2 bytes every time */
+ kFLEXPSI_DMAnSize4Bytes = 0x4U, /*!< Source/Destination data transfer size is 4 bytes every time */
+} flexspi_dma_transfer_nsize_t;
+
+/*! @brief FLEXSPI DMA transfer handle, users should not touch the content of the handle.*/
+struct _flexspi_dma_handle
+{
+ dma_handle_t *txDmaHandle; /*!< dma handler for FLEXSPI Tx. */
+ dma_handle_t *rxDmaHandle; /*!< dma handler for FLEXSPI Rx. */
+ size_t transferSize; /*!< Bytes need to transfer. */
+ flexspi_dma_transfer_nsize_t nsize; /*!< dma SSIZE/DSIZE in each transfer. */
+ uint8_t nbytes; /*!< dma minor byte transfer count initially configured. */
+ uint8_t count; /*!< The transfer data count in a DMA request. */
+ uint32_t state; /*!< Internal state for FLEXSPI dma transfer. */
+ flexspi_dma_callback_t completionCallback; /*!< A callback function called after the dma transfer is finished. */
+ void *userData; /*!< User callback parameter */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name FLEXSPI dma Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param handle Pointer to flexspi_dma_handle_t structure
+ * @param callback FLEXSPI callback, NULL means no callback.
+ * @param userData User callback function data.
+ * @param txDmaHandle User requested DMA handle for TX DMA transfer.
+ * @param rxDmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void FLEXSPI_TransferCreateHandleDMA(FLEXSPI_Type *base,
+ flexspi_dma_handle_t *handle,
+ flexspi_dma_callback_t callback,
+ void *userData,
+ dma_handle_t *txDmaHandle,
+ dma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Update FLEXSPI DMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param handle Pointer to flexspi_dma_handle_t structure
+ * @param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
+ * kFLEXPSI_DMAnSize1Bytes(one byte).
+ * @see flexspi_dma_transfer_nsize_t .
+ */
+void FLEXSPI_TransferUpdateSizeDMA(FLEXSPI_Type *base,
+ flexspi_dma_handle_t *handle,
+ flexspi_dma_transfer_nsize_t nsize);
+
+/*!
+ * @brief Transfers FLEXSPI data using an dma non-blocking method.
+ *
+ * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_dma_handle_t structure
+ * @param xfer FLEXSPI transfer structure.
+ * @retval kStatus_FLEXSPI_Busy FLEXSPI is busy transfer.
+ * @retval kStatus_InvalidArgument The watermark configuration is invalid, the watermark should be power of
+ 2 to do successfully DMA transfer.
+ * @retval kStatus_Success FLEXSPI successfully start dma transfer.
+ */
+status_t FLEXSPI_TransferDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, flexspi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the transfer data using dma.
+ *
+ * This function aborts the transfer data using dma.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_dma_handle_t structure
+ */
+void FLEXSPI_TransferAbortDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle);
+
+/*!
+ * @brief Gets the transferred counts of transfer.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_dma_handle_t structure.
+ * @param count Bytes transfer.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXSPI_TransferGetTransferCountDMA(FLEXSPI_Type *base, flexspi_dma_handle_t *handle, size_t *count);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* @} */
+
+#endif /* _FSL_FLEXSPI_DMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.c
new file mode 100644
index 0000000000..80c19f8ccd
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexspi_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexspi_edma"
+#endif
+
+/*<! Structure definition for flexspi_edma_private_handle_t. The structure is private. */
+typedef struct _flexspi_edma_private_handle
+{
+ FLEXSPI_Type *base;
+ flexspi_edma_handle_t *handle;
+} flexspi_edma_private_handle_t;
+
+/* FLEXSPI EDMA transfer handle, _flexspi_edma_tansfer_states. */
+enum
+{
+ kFLEXSPI_Idle, /* FLEXSPI Bus idle. */
+ kFLEXSPI_Busy /* FLEXSPI Bus busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to flexspi bases for each instance. */
+static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
+
+/*<! Private handle only used for internally. */
+static flexspi_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_flexspiBases)];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief FLEXSPI EDMA transfer finished callback function.
+ *
+ * This function is called when FLEXSPI EDMA transfer finished. It disables the FLEXSPI
+ * TX/RX EDMA request and sends status to FLEXSPI callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint8_t FLEXSPI_CalculatePower(uint8_t value)
+{
+ uint8_t power = 0;
+ while (value >> 1 != 0U)
+ {
+ power++;
+ value = value >> 1;
+ }
+
+ return power;
+}
+static void FLEXSPI_TransferEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ flexspi_edma_private_handle_t *flexspiPrivateHandle = (flexspi_edma_private_handle_t *)param;
+
+ /* Avoid warning for unused parameters. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Wait for bus idle. */
+ while (!FLEXSPI_GetBusIdleStatus(flexspiPrivateHandle->base))
+ {
+ }
+ /* Disable transfer. */
+ FLEXSPI_TransferAbortEDMA(flexspiPrivateHandle->base, flexspiPrivateHandle->handle);
+
+ if (flexspiPrivateHandle->handle->completionCallback != NULL)
+ {
+ flexspiPrivateHandle->handle->completionCallback(flexspiPrivateHandle->base, flexspiPrivateHandle->handle,
+ kStatus_Success, flexspiPrivateHandle->handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
+ *
+ * param base FLEXSPI peripheral base address
+ * param handle Pointer to flexspi_edma_handle_t structure
+ * param callback FLEXSPI callback, NULL means no callback.
+ * param userData User callback function data.
+ * param txDmaHandle User requested DMA handle for TX DMA transfer.
+ * param rxDmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type *base,
+ flexspi_edma_handle_t *handle,
+ flexspi_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *txDmaHandle,
+ edma_handle_t *rxDmaHandle)
+{
+ assert(handle);
+
+ uint32_t instance = FLEXSPI_GetInstance(base);
+
+ s_edmaPrivateHandle[instance].base = base;
+ s_edmaPrivateHandle[instance].handle = handle;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->state = kFLEXSPI_Idle;
+ handle->txDmaHandle = txDmaHandle;
+ handle->rxDmaHandle = rxDmaHandle;
+ handle->nsize = kFLEXPSI_EDMAnSize1Bytes;
+
+ handle->completionCallback = callback;
+ handle->userData = userData;
+}
+
+/*!
+ * brief Update FLEXSPI EDMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
+ *
+ * param base FLEXSPI peripheral base address
+ * param handle Pointer to flexspi_edma_handle_t structure
+ * param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
+ * kFLEXPSI_EDMAnSize1Bytes(one byte).
+ * see flexspi_edma_transfer_nsize_t .
+ */
+void FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type *base,
+ flexspi_edma_handle_t *handle,
+ flexspi_edma_transfer_nsize_t nsize)
+{
+ handle->nsize = nsize;
+}
+
+/*!
+ * brief Transfers FLEXSPI data using an eDMA non-blocking method.
+ *
+ * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
+ * param base FLEXSPI peripheral base address.
+ * param handle Pointer to flexspi_edma_handle_t structure
+ * param xfer FLEXSPI transfer structure.
+ * retval kStatus_FLEXSPI_Busy FLEXSPI is busy transfer.
+ * retval kStatus_InvalidArgument The watermark configuration is invalid, the watermark should be power of
+ 2 to do successfully EDMA transfer.
+ * retval kStatus_Success FLEXSPI successfully start edma transfer.
+ */
+status_t FLEXSPI_TransferEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, flexspi_transfer_t *xfer)
+{
+ uint32_t configValue = 0;
+ status_t result = kStatus_Success;
+ edma_transfer_config_t xferConfig;
+ uint32_t instance = FLEXSPI_GetInstance(base);
+ uint8_t power = 0;
+
+ assert(handle);
+ assert(xfer);
+
+ /* Check if the FLEXSPI bus is idle - if not return busy status. */
+ if (handle->state != (uint32_t)kFLEXSPI_Idle)
+ {
+ result = kStatus_FLEXSPI_Busy;
+ }
+ else
+ {
+ handle->transferSize = xfer->dataSize;
+ handle->state = kFLEXSPI_Busy;
+
+ /* Clear sequence pointer before sending data to external devices. */
+ base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
+
+ /* Clear former pending status before start this transfer. */
+ base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
+ FLEXSPI_INTR_IPCMDGE_MASK;
+
+ /* Configure base address. */
+ base->IPCR0 = xfer->deviceAddress;
+
+ /* Reset fifos. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+
+ /* Configure data size. */
+ if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
+ {
+ configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
+ }
+
+ /* Configure sequence ID. */
+ configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
+ base->IPCR1 = configValue;
+ }
+
+ if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
+ {
+ handle->count = (uint8_t)((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
+
+ if (xfer->dataSize < 8U * (uint32_t)handle->count)
+ {
+ handle->nbytes = (uint8_t)xfer->dataSize;
+ }
+ else
+ {
+ /* Check the handle->count is power of 2 */
+ if (((handle->count) & (handle->count - 1U)) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
+ handle->nbytes = (8U * handle->count);
+ }
+
+ power = FLEXSPI_CalculatePower(8U * handle->count);
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, (uint32_t)handle->nsize,
+ (void *)(uint32_t *)FLEXSPI_GetTxFifoAddress(base), (uint32_t)handle->nsize,
+ (uint32_t)handle->nbytes, xfer->dataSize, kEDMA_MemoryToMemory);
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
+ EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, kEDMA_ModuloDisable,
+ (edma_modulo_t)power);
+ EDMA_SetCallback(handle->txDmaHandle, FLEXSPI_TransferEDMACallback,
+ &s_edmaPrivateHandle[FLEXSPI_GetInstance(base)]);
+ EDMA_StartTransfer(handle->txDmaHandle);
+
+ /* Enable FLEXSPI TX EDMA. */
+ FLEXSPI_EnableTxDMA(base, true);
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+ }
+ else if (xfer->cmdType == kFLEXSPI_Read)
+ {
+ handle->count = (uint8_t)((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
+
+ if (xfer->dataSize < 8U * (uint32_t)handle->count)
+ {
+ handle->nbytes = (uint8_t)xfer->dataSize;
+ }
+ else
+ {
+ /* Check the handle->count is power of 2 */
+ if (((handle->count) & (handle->count - 1U)) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXSPI handle */
+ handle->nbytes = (8U * handle->count);
+ }
+
+ power = FLEXSPI_CalculatePower(8U * handle->count);
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)FLEXSPI_GetRxFifoAddress(base), (uint32_t)handle->nsize,
+ xfer->data, (uint32_t)handle->nsize, (uint32_t)handle->nbytes, xfer->dataSize,
+ kEDMA_MemoryToMemory);
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
+ EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, (edma_modulo_t)power,
+ kEDMA_ModuloDisable);
+ EDMA_SetCallback(handle->rxDmaHandle, FLEXSPI_TransferEDMACallback, &s_edmaPrivateHandle[instance]);
+ EDMA_StartTransfer(handle->rxDmaHandle);
+
+ /* Enable FLEXSPI RX EDMA. */
+ FLEXSPI_EnableRxDMA(base, true);
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+ }
+ else
+ {
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+ /* Wait for bus idle. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+
+ handle->state = kFLEXSPI_Idle;
+
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Aborts the transfer data using eDMA.
+ *
+ * This function aborts the transfer data using eDMA.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle Pointer to flexspi_edma_handle_t structure
+ */
+void FLEXSPI_TransferAbortEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle)
+{
+ assert(handle);
+
+ if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
+ {
+ FLEXSPI_EnableTxDMA(base, false);
+ EDMA_AbortTransfer(handle->txDmaHandle);
+ }
+
+ if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
+ {
+ FLEXSPI_EnableRxDMA(base, false);
+ EDMA_AbortTransfer(handle->rxDmaHandle);
+ }
+
+ handle->state = kFLEXSPI_Idle;
+}
+
+status_t FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+ assert(count);
+
+ status_t result = kStatus_Success;
+
+ if (handle->state != (uint32_t)kFLEXSPI_Busy)
+ {
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ if ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXDMAEN_MASK) != 0x00U)
+ {
+ *count = (handle->transferSize -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel));
+ }
+ else if ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXDMAEN_MASK) != 0x00U)
+ {
+ *count = (handle->transferSize -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel));
+ }
+ else
+ {
+ ; /* Intentional empty for MISRA C-2012 rule 15.7. */
+ }
+ }
+
+ return result;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.h
new file mode 100644
index 0000000000..6b939970e2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/flexspi/fsl_flexspi_edma.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_FLEXSPI_EDMA_H_
+#define _FSL_FLEXSPI_EDMA_H_
+
+#include "fsl_flexspi.h"
+#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
+#include "fsl_dmamux.h"
+#endif
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup flexspi_edma
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief FLEXSPI EDMA driver version 2.3.2. */
+#define FSL_FLEXSPI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 3, 2))
+/*@}*/
+
+typedef struct _flexspi_edma_handle flexspi_edma_handle_t;
+
+/*! @brief FLEXSPI eDMA transfer callback function for finish and error */
+typedef void (*flexspi_edma_callback_t)(FLEXSPI_Type *base,
+ flexspi_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief eDMA transfer configuration */
+typedef enum _flexspi_edma_ntransfer_size
+{
+ kFLEXPSI_EDMAnSize1Bytes = 0x1U, /*!< Source/Destination data transfer size is 1 byte every time */
+ kFLEXPSI_EDMAnSize2Bytes = 0x2U, /*!< Source/Destination data transfer size is 2 bytes every time */
+ kFLEXPSI_EDMAnSize4Bytes = 0x4U, /*!< Source/Destination data transfer size is 4 bytes every time */
+ kFLEXPSI_EDMAnSize8Bytes = 0x8U, /*!< Source/Destination data transfer size is 8 bytes every time */
+ kFLEXPSI_EDMAnSize32Bytes = 0x20U, /*!< Source/Destination data transfer size is 32 bytes every time */
+} flexspi_edma_transfer_nsize_t;
+
+/*! @brief FLEXSPI DMA transfer handle, users should not touch the content of the handle.*/
+struct _flexspi_edma_handle
+{
+ edma_handle_t *txDmaHandle; /*!< eDMA handler for FLEXSPI Tx. */
+ edma_handle_t *rxDmaHandle; /*!< eDMA handler for FLEXSPI Rx. */
+ size_t transferSize; /*!< Bytes need to transfer. */
+ flexspi_edma_transfer_nsize_t nsize; /*!< eDMA SSIZE/DSIZE in each transfer. */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t count; /*!< The transfer data count in a DMA request. */
+ uint32_t state; /*!< Internal state for FLEXSPI eDMA transfer. */
+ flexspi_edma_callback_t completionCallback; /*!< A callback function called after the eDMA transfer is finished. */
+ void *userData; /*!< User callback parameter */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name FLEXSPI eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the FLEXSPI handle for transfer which is used in transactional functions and set the callback.
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param handle Pointer to flexspi_edma_handle_t structure
+ * @param callback FLEXSPI callback, NULL means no callback.
+ * @param userData User callback function data.
+ * @param txDmaHandle User requested DMA handle for TX DMA transfer.
+ * @param rxDmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void FLEXSPI_TransferCreateHandleEDMA(FLEXSPI_Type *base,
+ flexspi_edma_handle_t *handle,
+ flexspi_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *txDmaHandle,
+ edma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Update FLEXSPI EDMA transfer source data transfer size(SSIZE) and destination data transfer size(DSIZE).
+ *
+ * @param base FLEXSPI peripheral base address
+ * @param handle Pointer to flexspi_edma_handle_t structure
+ * @param nsize FLEXSPI DMA transfer data transfer size(SSIZE/DSIZE), by default the size is
+ * kFLEXPSI_EDMAnSize1Bytes(one byte).
+ * @see flexspi_edma_transfer_nsize_t .
+ */
+void FLEXSPI_TransferUpdateSizeEDMA(FLEXSPI_Type *base,
+ flexspi_edma_handle_t *handle,
+ flexspi_edma_transfer_nsize_t nsize);
+
+/*!
+ * @brief Transfers FLEXSPI data using an eDMA non-blocking method.
+ *
+ * This function writes/receives data to/from the FLEXSPI transmit/receive FIFO. This function is non-blocking.
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_edma_handle_t structure
+ * @param xfer FLEXSPI transfer structure.
+ * @retval kStatus_FLEXSPI_Busy FLEXSPI is busy transfer.
+ * @retval kStatus_InvalidArgument The watermark configuration is invalid, the watermark should be power of
+ 2 to do successfully EDMA transfer.
+ * @retval kStatus_Success FLEXSPI successfully start edma transfer.
+ */
+status_t FLEXSPI_TransferEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, flexspi_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the transfer data using eDMA.
+ *
+ * This function aborts the transfer data using eDMA.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_edma_handle_t structure
+ */
+void FLEXSPI_TransferAbortEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the transferred counts of transfer.
+ *
+ * @param base FLEXSPI peripheral base address.
+ * @param handle Pointer to flexspi_edma_handle_t structure.
+ * @param count Bytes transfer.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXSPI_TransferGetTransferCountEDMA(FLEXSPI_Type *base, flexspi_edma_handle_t *handle, size_t *count);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* @} */
+
+#endif /* _FSL_FLEXSPI_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.c b/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.c
new file mode 100644
index 0000000000..e5cef48d1b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.gpc_1"
+#endif
+
+/*!
+ * brief Enable the IRQ.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_EnableIRQ(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ base->IMR5 &= ~(1UL << irqRegShiftNum);
+ }
+ else
+ {
+ base->IMR[irqRegNum] &= ~(1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ base->IMR[irqRegNum - 1UL] &= ~(1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+}
+
+/*!
+ * brief Disable the IRQ.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be disabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_DisableIRQ(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ base->IMR5 |= (1UL << irqRegShiftNum);
+ }
+ else
+ {
+ base->IMR[irqRegNum] |= (1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ base->IMR[irqRegNum - 1UL] |= (1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+}
+
+/*!
+ * brief Get the IRQ/Event flag.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ * return Indicated IRQ/Event is asserted or not.
+ */
+bool GPC_GetIRQStatusFlag(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+ uint32_t ret;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ ret = base->ISR5 & (1UL << irqRegShiftNum);
+ }
+ else
+ {
+ ret = base->ISR[irqRegNum] & (1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ ret = base->ISR[irqRegNum - 1UL] & (1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+
+ return (1UL << irqRegShiftNum) == ret;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.h b/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.h
new file mode 100644
index 0000000000..31375224bc
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/gpc_1/fsl_gpc.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_GPC_H_
+#define _FSL_GPC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup gpc
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief GPC driver version 2.1.1. */
+#define FSL_GPC_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_GPCIRQM) && FSL_FEATURE_GPC_HAS_CNTR_GPCIRQM)
+/*!
+ * @brief Allow all the IRQ/Events within the charge of GPC.
+ *
+ * @param base GPC peripheral base address.
+ */
+static inline void GPC_AllowIRQs(GPC_Type *base)
+{
+ base->CNTR &= ~GPC_CNTR_GPCIRQM_MASK; /* Events would not be masked. */
+}
+
+/*!
+ * @brief Disallow all the IRQ/Events within the charge of GPC.
+ *
+ * @param base GPC peripheral base address.
+ */
+static inline void GPC_DisallowIRQs(GPC_Type *base)
+{
+ base->CNTR |= GPC_CNTR_GPCIRQM_MASK; /* Mask all the events. */
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_GPCIRQM */
+
+/*!
+ * @brief Enable the IRQ.
+ *
+ * @param base GPC peripheral base address.
+ * @param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_EnableIRQ(GPC_Type *base, uint32_t irqId);
+
+/*!
+ * @brief Disable the IRQ.
+ *
+ * @param base GPC peripheral base address.
+ * @param irqId ID number of IRQ to be disabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_DisableIRQ(GPC_Type *base, uint32_t irqId);
+
+/*!
+ * @brief Get the IRQ/Event flag.
+ *
+ * @param base GPC peripheral base address.
+ * @param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ * @return Indicated IRQ/Event is asserted or not.
+ */
+bool GPC_GetIRQStatusFlag(GPC_Type *base, uint32_t irqId);
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_L2PGE) && FSL_FEATURE_GPC_HAS_CNTR_L2PGE)
+/*!
+ * @brief L2 Cache Power Gate Enable
+ *
+ * This function configures the L2 cache if it will keep power when in low power mode.
+ * When the L2 cache power is OFF, L2 cache will be power down once when CPU core is power down
+ * and will be hardware invalidated automatically when CPU core is re-power up.
+ * When the L2 cache power is ON, L2 cache will keep power on even if CPU core is power down and
+ * will not be hardware invalidated.
+ * When CPU core is re-power up, the default setting is OFF.
+ *
+ * @param base GPC peripheral base address.
+ * @param enable Enable the request or not.
+ */
+static inline void GPC_RequestL2CachePowerDown(GPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTR |= GPC_CNTR_L2_PGE_MASK; /* OFF. */
+ }
+ else
+ {
+ base->CNTR &= ~GPC_CNTR_L2_PGE_MASK; /* ON. */
+ }
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_L2PGE */
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_PDRAM0PGE) && FSL_FEATURE_GPC_HAS_CNTR_PDRAM0PGE)
+/*!
+ * @brief FLEXRAM PDRAM0 Power Gate Enable
+ *
+ * This function configures the FLEXRAM PDRAM0 if it will keep power when cpu core is power down.
+ * When the PDRAM0 Power is 1, PDRAM0 will be power down once when CPU core is power down.
+ * When the PDRAM0 Power is 0, PDRAM0 will keep power on even if CPU core is power down.
+ * When CPU core is re-power up, the default setting is 1.
+ *
+ * @param base GPC peripheral base address.
+ * @param enable Enable the request or not.
+ */
+static inline void GPC_RequestPdram0PowerDown(GPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTR |= GPC_CNTR_PDRAM0_PGE_MASK; /* OFF. */
+ }
+ else
+ {
+ base->CNTR &= ~GPC_CNTR_PDRAM0_PGE_MASK; /* ON. */
+ }
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_PDRAM0PGE */
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_VADC) && FSL_FEATURE_GPC_HAS_CNTR_VADC)
+/*!
+ * @brief VADC power down.
+ *
+ * This function requests the VADC power down.
+ *
+ * @param base GPC peripheral base address.
+ * @param enable Enable the request or not.
+ */
+static inline void GPC_RequestVADCPowerDown(GPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTR &= ~GPC_CNTR_VADC_EXT_PWD_N_MASK; /* VADC power down. */
+ }
+ else
+ {
+ base->CNTR |= GPC_CNTR_VADC_EXT_PWD_N_MASK; /* VADC not power down. */
+ }
+}
+
+/*!
+ * @brief Checks if the VADC is power off.
+ *
+ * @param base GPC peripheral base address.
+ * @return Whether the VADC is power off or not.
+ */
+static inline bool GPC_GetVADCPowerDownFlag(GPC_Type *base)
+{
+ return (GPC_CNTR_VADC_ANALOG_OFF_MASK == (GPC_CNTR_VADC_ANALOG_OFF_MASK & base->CNTR));
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_VADC */
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_DVFS0CR) && FSL_FEATURE_GPC_HAS_CNTR_DVFS0CR)
+/*!
+ * @brief Checks if the DVFS0 is requesting for frequency/voltage update.
+ *
+ * @param base GPC peripheral base address.
+ * @return Whether the DVFS0 is requesting for frequency/voltage update.
+ */
+static inline bool GPC_HasDVFS0ChangeRequest(GPC_Type *base)
+{
+ return (GPC_CNTR_DVFS0CR_MASK == (GPC_CNTR_DVFS0CR_MASK & base->CNTR));
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_DVFS0CR */
+
+#if (defined(FSL_FEATURE_GPC_HAS_CNTR_DISPLAY) && FSL_FEATURE_GPC_HAS_CNTR_DISPLAY)
+/*!
+ * @brief Requests the display power switch sequence.
+ *
+ * @param base GPC peripheral base address.
+ * @param enable Enable the power on sequence, or the power down sequence.
+ */
+static inline void GPC_RequestDisplayPowerOn(GPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTR |= GPC_CNTR_DISPLAY_PUP_REQ_MASK; /* Power on sequence. */
+ }
+ else
+ {
+ base->CNTR |= GPC_CNTR_DISPLAY_PDN_REQ_MASK; /* Power down sequence. */
+ }
+}
+#endif /* FSL_FEATURE_GPC_HAS_CNTR_DISPLAY */
+
+/*!
+ * @brief Requests the MEGA power switch sequence.
+ *
+ * @param base GPC peripheral base address.
+ * @param enable Enable the power on sequence, or the power down sequence.
+ */
+static inline void GPC_RequestMEGAPowerOn(GPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTR |= GPC_CNTR_MEGA_PUP_REQ_MASK; /* Power on sequence. */
+ }
+ else
+ {
+ base->CNTR |= GPC_CNTR_MEGA_PDN_REQ_MASK; /* Power down sequence. */
+ }
+}
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_GPC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.c b/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.c
new file mode 100644
index 0000000000..691cdf590e
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpt.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.gpt"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to GPT bases for each instance. */
+static GPT_Type *const s_gptBases[] = GPT_BASE_PTRS;
+
+/*! @brief Pointers to GPT clocks for each instance. */
+static const clock_ip_name_t s_gptClocks[] = GPT_CLOCKS;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t GPT_GetInstance(GPT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_gptBases); instance++)
+ {
+ if (s_gptBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_gptBases));
+
+ return instance;
+}
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*!
+ * brief Initialize GPT to reset state and initialize running mode.
+ *
+ * param base GPT peripheral base address.
+ * param initConfig GPT mode setting configuration.
+ */
+void GPT_Init(GPT_Type *base, const gpt_config_t *initConfig)
+{
+ assert(NULL != initConfig);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the GPT clock*/
+ (void)CLOCK_EnableClock(s_gptClocks[GPT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ base->CR = 0U;
+
+ GPT_SoftwareReset(base);
+
+ base->CR =
+ (initConfig->enableFreeRun ? GPT_CR_FRR_MASK : 0UL) | (initConfig->enableRunInWait ? GPT_CR_WAITEN_MASK : 0UL) |
+ (initConfig->enableRunInStop ? GPT_CR_STOPEN_MASK : 0UL) |
+ (initConfig->enableRunInDoze ? GPT_CR_DOZEEN_MASK : 0UL) |
+ (initConfig->enableRunInDbg ? GPT_CR_DBGEN_MASK : 0UL) | (initConfig->enableMode ? GPT_CR_ENMOD_MASK : 0UL);
+
+ GPT_SetClockSource(base, initConfig->clockSource);
+ GPT_SetClockDivider(base, initConfig->divider);
+}
+
+/*!
+ * brief Disables the module and gates the GPT clock.
+ *
+ * param base GPT peripheral base address.
+ */
+void GPT_Deinit(GPT_Type *base)
+{
+ /* Disable GPT timers */
+ base->CR = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the GPT clock*/
+ (void)CLOCK_DisableClock(s_gptClocks[GPT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fills in the GPT configuration structure with default settings.
+ *
+ * The default values are:
+ * code
+ * config->clockSource = kGPT_ClockSource_Periph;
+ * config->divider = 1U;
+ * config->enableRunInStop = true;
+ * config->enableRunInWait = true;
+ * config->enableRunInDoze = false;
+ * config->enableRunInDbg = false;
+ * config->enableFreeRun = false;
+ * config->enableMode = true;
+ * endcode
+ * param config Pointer to the user configuration structure.
+ */
+void GPT_GetDefaultConfig(gpt_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->clockSource = kGPT_ClockSource_Periph;
+ config->divider = 1U;
+ config->enableRunInStop = true;
+ config->enableRunInWait = true;
+ config->enableRunInDoze = false;
+ config->enableRunInDbg = false;
+ config->enableFreeRun = false;
+ config->enableMode = true;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.h b/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.h
new file mode 100644
index 0000000000..ec274588bf
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/gpt/fsl_gpt.h
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_GPT_H_
+#define _FSL_GPT_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup gpt
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_GPT_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+/*!
+ * @brief List of clock sources
+ * @note Actual number of clock sources is SoC dependent
+ */
+typedef enum _gpt_clock_source
+{
+ kGPT_ClockSource_Off = 0U, /*!< GPT Clock Source Off.*/
+ kGPT_ClockSource_Periph = 1U, /*!< GPT Clock Source from Peripheral Clock.*/
+ kGPT_ClockSource_HighFreq = 2U, /*!< GPT Clock Source from High Frequency Reference Clock.*/
+ kGPT_ClockSource_Ext = 3U, /*!< GPT Clock Source from external pin.*/
+ kGPT_ClockSource_LowFreq = 4U, /*!< GPT Clock Source from Low Frequency Reference Clock.*/
+ kGPT_ClockSource_Osc = 5U, /*!< GPT Clock Source from Crystal oscillator.*/
+} gpt_clock_source_t;
+
+/*! @brief List of input capture channel number. */
+typedef enum _gpt_input_capture_channel
+{
+ kGPT_InputCapture_Channel1 = 0U, /*!< GPT Input Capture Channel1.*/
+ kGPT_InputCapture_Channel2 = 1U, /*!< GPT Input Capture Channel2.*/
+} gpt_input_capture_channel_t;
+
+/*! @brief List of input capture operation mode. */
+typedef enum _gpt_input_operation_mode
+{
+ kGPT_InputOperation_Disabled = 0U, /*!< Don't capture.*/
+ kGPT_InputOperation_RiseEdge = 1U, /*!< Capture on rising edge of input pin.*/
+ kGPT_InputOperation_FallEdge = 2U, /*!< Capture on falling edge of input pin.*/
+ kGPT_InputOperation_BothEdge = 3U, /*!< Capture on both edges of input pin.*/
+} gpt_input_operation_mode_t;
+
+/*! @brief List of output compare channel number. */
+typedef enum _gpt_output_compare_channel
+{
+ kGPT_OutputCompare_Channel1 = 0U, /*!< Output Compare Channel1.*/
+ kGPT_OutputCompare_Channel2 = 1U, /*!< Output Compare Channel2.*/
+ kGPT_OutputCompare_Channel3 = 2U, /*!< Output Compare Channel3.*/
+} gpt_output_compare_channel_t;
+
+/*! @brief List of output compare operation mode. */
+typedef enum _gpt_output_operation_mode
+{
+ kGPT_OutputOperation_Disconnected = 0U, /*!< Don't change output pin.*/
+ kGPT_OutputOperation_Toggle = 1U, /*!< Toggle output pin.*/
+ kGPT_OutputOperation_Clear = 2U, /*!< Set output pin low.*/
+ kGPT_OutputOperation_Set = 3U, /*!< Set output pin high.*/
+ kGPT_OutputOperation_Activelow = 4U, /*!< Generate a active low pulse on output pin.*/
+} gpt_output_operation_mode_t;
+
+/*! @brief List of GPT interrupts */
+typedef enum _gpt_interrupt_enable
+{
+ kGPT_OutputCompare1InterruptEnable = GPT_IR_OF1IE_MASK, /*!< Output Compare Channel1 interrupt enable*/
+ kGPT_OutputCompare2InterruptEnable = GPT_IR_OF2IE_MASK, /*!< Output Compare Channel2 interrupt enable*/
+ kGPT_OutputCompare3InterruptEnable = GPT_IR_OF3IE_MASK, /*!< Output Compare Channel3 interrupt enable*/
+ kGPT_InputCapture1InterruptEnable = GPT_IR_IF1IE_MASK, /*!< Input Capture Channel1 interrupt enable*/
+ kGPT_InputCapture2InterruptEnable = GPT_IR_IF2IE_MASK, /*!< Input Capture Channel1 interrupt enable*/
+ kGPT_RollOverFlagInterruptEnable = GPT_IR_ROVIE_MASK, /*!< Counter rolled over interrupt enable*/
+} gpt_interrupt_enable_t;
+
+/*! @brief Status flag. */
+typedef enum _gpt_status_flag
+{
+ kGPT_OutputCompare1Flag = GPT_SR_OF1_MASK, /*!< Output compare channel 1 event.*/
+ kGPT_OutputCompare2Flag = GPT_SR_OF2_MASK, /*!< Output compare channel 2 event.*/
+ kGPT_OutputCompare3Flag = GPT_SR_OF3_MASK, /*!< Output compare channel 3 event.*/
+ kGPT_InputCapture1Flag = GPT_SR_IF1_MASK, /*!< Input Capture channel 1 event.*/
+ kGPT_InputCapture2Flag = GPT_SR_IF2_MASK, /*!< Input Capture channel 2 event.*/
+ kGPT_RollOverFlag = GPT_SR_ROV_MASK, /*!< Counter reaches maximum value and rolled over to 0 event.*/
+} gpt_status_flag_t;
+
+/*! @brief Structure to configure the running mode. */
+typedef struct _gpt_init_config
+{
+ gpt_clock_source_t clockSource; /*!< clock source for GPT module. */
+ uint32_t divider; /*!< clock divider (prescaler+1) from clock source to counter. */
+ bool enableFreeRun; /*!< true: FreeRun mode, false: Restart mode. */
+ bool enableRunInWait; /*!< GPT enabled in wait mode. */
+ bool enableRunInStop; /*!< GPT enabled in stop mode. */
+ bool enableRunInDoze; /*!< GPT enabled in doze mode. */
+ bool enableRunInDbg; /*!< GPT enabled in debug mode. */
+ bool enableMode; /*!< true: counter reset to 0 when enabled;
+ false: counter retain its value when enabled. */
+} gpt_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize GPT to reset state and initialize running mode.
+ *
+ * @param base GPT peripheral base address.
+ * @param initConfig GPT mode setting configuration.
+ */
+void GPT_Init(GPT_Type *base, const gpt_config_t *initConfig);
+
+/*!
+ * @brief Disables the module and gates the GPT clock.
+ *
+ * @param base GPT peripheral base address.
+ */
+void GPT_Deinit(GPT_Type *base);
+
+/*!
+ * @brief Fills in the GPT configuration structure with default settings.
+ *
+ * The default values are:
+ * @code
+ * config->clockSource = kGPT_ClockSource_Periph;
+ * config->divider = 1U;
+ * config->enableRunInStop = true;
+ * config->enableRunInWait = true;
+ * config->enableRunInDoze = false;
+ * config->enableRunInDbg = false;
+ * config->enableFreeRun = false;
+ * config->enableMode = true;
+ * @endcode
+ * @param config Pointer to the user configuration structure.
+ */
+void GPT_GetDefaultConfig(gpt_config_t *config);
+
+/*!
+ * @name Software Reset
+ * @{
+ */
+
+/*!
+ * @brief Software reset of GPT module.
+ *
+ * @param base GPT peripheral base address.
+ */
+static inline void GPT_SoftwareReset(GPT_Type *base)
+{
+ base->CR |= GPT_CR_SWR_MASK;
+ /* Wait reset finished. */
+ while ((base->CR & GPT_CR_SWR_MASK) == GPT_CR_SWR_MASK)
+ {
+ }
+}
+
+/*!
+ * @name Clock source and frequency control
+ * @{
+ */
+
+/*!
+ * @brief Set clock source of GPT.
+ *
+ * @param base GPT peripheral base address.
+ * @param gptClkSource Clock source (see @ref gpt_clock_source_t typedef enumeration).
+ */
+static inline void GPT_SetClockSource(GPT_Type *base, gpt_clock_source_t gptClkSource)
+{
+ if (gptClkSource == kGPT_ClockSource_Osc)
+ {
+ base->CR = (base->CR & ~GPT_CR_CLKSRC_MASK) | GPT_CR_EN_24M_MASK | GPT_CR_CLKSRC(gptClkSource);
+ }
+ else
+ {
+ base->CR = (base->CR & ~(GPT_CR_CLKSRC_MASK | GPT_CR_EN_24M_MASK)) | GPT_CR_CLKSRC(gptClkSource);
+ }
+}
+
+/*!
+ * @brief Get clock source of GPT.
+ *
+ * @param base GPT peripheral base address.
+ * @return clock source (see @ref gpt_clock_source_t typedef enumeration).
+ */
+static inline gpt_clock_source_t GPT_GetClockSource(GPT_Type *base)
+{
+ return (gpt_clock_source_t)(uint8_t)((base->CR & GPT_CR_CLKSRC_MASK) >> GPT_CR_CLKSRC_SHIFT);
+}
+
+/*!
+ * @brief Set pre scaler of GPT.
+ *
+ * @param base GPT peripheral base address.
+ * @param divider Divider of GPT (1-4096).
+ */
+static inline void GPT_SetClockDivider(GPT_Type *base, uint32_t divider)
+{
+ assert(divider - 1U <= GPT_PR_PRESCALER_MASK);
+
+ base->PR = (base->PR & ~GPT_PR_PRESCALER_MASK) | GPT_PR_PRESCALER(divider - 1U);
+}
+
+/*!
+ * @brief Get clock divider in GPT module.
+ *
+ * @param base GPT peripheral base address.
+ * @return clock divider in GPT module (1-4096).
+ */
+static inline uint32_t GPT_GetClockDivider(GPT_Type *base)
+{
+ return ((base->PR & GPT_PR_PRESCALER_MASK) >> GPT_PR_PRESCALER_SHIFT) + 1U;
+}
+
+/*!
+ * @brief OSC 24M pre-scaler before selected by clock source.
+ *
+ * @param base GPT peripheral base address.
+ * @param divider OSC Divider(1-16).
+ */
+static inline void GPT_SetOscClockDivider(GPT_Type *base, uint32_t divider)
+{
+ assert(divider - 1U <= (GPT_PR_PRESCALER24M_MASK >> GPT_PR_PRESCALER24M_SHIFT));
+
+ base->PR = (base->PR & ~GPT_PR_PRESCALER24M_MASK) | GPT_PR_PRESCALER24M(divider - 1U);
+}
+
+/*!
+ * @brief Get OSC 24M clock divider in GPT module.
+ *
+ * @param base GPT peripheral base address.
+ * @return OSC clock divider in GPT module (1-16).
+ */
+static inline uint32_t GPT_GetOscClockDivider(GPT_Type *base)
+{
+ return ((base->PR & GPT_PR_PRESCALER24M_MASK) >> GPT_PR_PRESCALER24M_SHIFT) + 1U;
+}
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+/*!
+ * @brief Start GPT timer.
+ *
+ * @param base GPT peripheral base address.
+ */
+static inline void GPT_StartTimer(GPT_Type *base)
+{
+ base->CR |= GPT_CR_EN_MASK;
+}
+
+/*!
+ * @brief Stop GPT timer.
+ *
+ * @param base GPT peripheral base address.
+ */
+static inline void GPT_StopTimer(GPT_Type *base)
+{
+ base->CR &= ~GPT_CR_EN_MASK;
+}
+
+/*!
+ * @name Read the timer period
+ * @{
+ */
+
+/*!
+ * @brief Reads the current GPT counting value.
+ *
+ * @param base GPT peripheral base address.
+ * @return Current GPT counter value.
+ */
+static inline uint32_t GPT_GetCurrentTimerCount(GPT_Type *base)
+{
+ return base->CNT;
+}
+
+/*@}*/
+
+/*!
+ * @name GPT Input/Output Signal Control
+ * @{
+ */
+
+/*!
+ * @brief Set GPT operation mode of input capture channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT capture channel (see @ref gpt_input_capture_channel_t typedef enumeration).
+ * @param mode GPT input capture operation mode (see @ref gpt_input_operation_mode_t typedef enumeration).
+ */
+static inline void GPT_SetInputOperationMode(GPT_Type *base,
+ gpt_input_capture_channel_t channel,
+ gpt_input_operation_mode_t mode)
+{
+ assert(channel <= kGPT_InputCapture_Channel2);
+
+ base->CR =
+ (base->CR & ~(GPT_CR_IM1_MASK << ((uint32_t)channel * 2UL))) | (GPT_CR_IM1(mode) << ((uint32_t)channel * 2UL));
+}
+
+/*!
+ * @brief Get GPT operation mode of input capture channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT capture channel (see @ref gpt_input_capture_channel_t typedef enumeration).
+ * @return GPT input capture operation mode (see @ref gpt_input_operation_mode_t typedef enumeration).
+ */
+static inline gpt_input_operation_mode_t GPT_GetInputOperationMode(GPT_Type *base, gpt_input_capture_channel_t channel)
+{
+ assert(channel <= kGPT_InputCapture_Channel2);
+
+ return (gpt_input_operation_mode_t)(uint8_t)((base->CR >> (GPT_CR_IM1_SHIFT + (uint32_t)channel * 2UL)) &
+ (GPT_CR_IM1_MASK >> GPT_CR_IM1_SHIFT));
+}
+
+/*!
+ * @brief Get GPT input capture value of certain channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT capture channel (see @ref gpt_input_capture_channel_t typedef enumeration).
+ * @return GPT input capture value.
+ */
+static inline uint32_t GPT_GetInputCaptureValue(GPT_Type *base, gpt_input_capture_channel_t channel)
+{
+ assert(channel <= kGPT_InputCapture_Channel2);
+
+ return base->ICR[(uint32_t)channel];
+}
+
+/*!
+ * @brief Set GPT operation mode of output compare channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT output compare channel (see @ref gpt_output_compare_channel_t typedef enumeration).
+ * @param mode GPT output operation mode (see @ref gpt_output_operation_mode_t typedef enumeration).
+ */
+static inline void GPT_SetOutputOperationMode(GPT_Type *base,
+ gpt_output_compare_channel_t channel,
+ gpt_output_operation_mode_t mode)
+{
+ assert(channel <= kGPT_OutputCompare_Channel3);
+
+ base->CR =
+ (base->CR & ~(GPT_CR_OM1_MASK << ((uint32_t)channel * 3UL))) | (GPT_CR_OM1(mode) << ((uint32_t)channel * 3UL));
+}
+
+/*!
+ * @brief Get GPT operation mode of output compare channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT output compare channel (see @ref gpt_output_compare_channel_t typedef enumeration).
+ * @return GPT output operation mode (see @ref gpt_output_operation_mode_t typedef enumeration).
+ */
+static inline gpt_output_operation_mode_t GPT_GetOutputOperationMode(GPT_Type *base,
+ gpt_output_compare_channel_t channel)
+{
+ assert(channel <= kGPT_OutputCompare_Channel3);
+
+ return (gpt_output_operation_mode_t)(uint8_t)((base->CR >> (GPT_CR_OM1_SHIFT + (uint32_t)channel * 3UL)) &
+ (GPT_CR_OM1_MASK >> GPT_CR_OM1_SHIFT));
+}
+
+/*!
+ * @brief Set GPT output compare value of output compare channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT output compare channel (see @ref gpt_output_compare_channel_t typedef enumeration).
+ * @param value GPT output compare value.
+ */
+static inline void GPT_SetOutputCompareValue(GPT_Type *base, gpt_output_compare_channel_t channel, uint32_t value)
+{
+ assert(channel <= kGPT_OutputCompare_Channel3);
+
+ base->OCR[(uint32_t)channel] = value;
+}
+
+/*!
+ * @brief Get GPT output compare value of output compare channel.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT output compare channel (see @ref gpt_output_compare_channel_t typedef enumeration).
+ * @return GPT output compare value.
+ */
+static inline uint32_t GPT_GetOutputCompareValue(GPT_Type *base, gpt_output_compare_channel_t channel)
+{
+ assert(channel <= kGPT_OutputCompare_Channel3);
+
+ return base->OCR[(uint32_t)channel];
+}
+
+/*!
+ * @brief Force GPT output action on output compare channel, ignoring comparator.
+ *
+ * @param base GPT peripheral base address.
+ * @param channel GPT output compare channel (see @ref gpt_output_compare_channel_t typedef enumeration).
+ */
+static inline void GPT_ForceOutput(GPT_Type *base, gpt_output_compare_channel_t channel)
+{
+ assert(channel <= kGPT_OutputCompare_Channel3);
+
+ base->CR |= (GPT_CR_FO1_MASK << (uint32_t)channel);
+}
+
+/*@}*/
+
+/*!
+ * @name GPT Interrupt and Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected GPT interrupts.
+ *
+ * @param base GPT peripheral base address.
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::gpt_interrupt_enable_t
+ */
+static inline void GPT_EnableInterrupts(GPT_Type *base, uint32_t mask)
+{
+ base->IR |= mask;
+}
+
+/*!
+ * @brief Disables the selected GPT interrupts.
+ *
+ * @param base GPT peripheral base address
+ * @param mask The interrupts to disable. This is a logical OR of members of the
+ * enumeration ::gpt_interrupt_enable_t
+ */
+static inline void GPT_DisableInterrupts(GPT_Type *base, uint32_t mask)
+{
+ base->IR &= ~mask;
+}
+
+/*!
+ * @brief Gets the enabled GPT interrupts.
+ *
+ * @param base GPT peripheral base address
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::gpt_interrupt_enable_t
+ */
+static inline uint32_t GPT_GetEnabledInterrupts(GPT_Type *base)
+{
+ return (base->IR & (GPT_IR_OF1IE_MASK | GPT_IR_OF2IE_MASK | GPT_IR_OF3IE_MASK | GPT_IR_IF1IE_MASK |
+ GPT_IR_IF2IE_MASK | GPT_IR_ROVIE_MASK));
+}
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Get GPT status flags.
+ *
+ * @param base GPT peripheral base address.
+ * @param flags GPT status flag mask (see @ref gpt_status_flag_t for bit definition).
+ * @return GPT status, each bit represents one status flag.
+ */
+static inline uint32_t GPT_GetStatusFlags(GPT_Type *base, gpt_status_flag_t flags)
+{
+ return base->SR & (uint32_t)flags;
+}
+
+/*!
+ * @brief Clears the GPT status flags.
+ *
+ * @param base GPT peripheral base address.
+ * @param flags GPT status flag mask (see @ref gpt_status_flag_t for bit definition).
+ */
+static inline void GPT_ClearStatusFlags(GPT_Type *base, gpt_status_flag_t flags)
+{
+ base->SR = (uint32_t)flags;
+}
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_GPT_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.c b/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.c
new file mode 100644
index 0000000000..43ae8f16ea
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_iee.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.iee"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Resets IEE module to factory default values.
+ *
+ * This function performs hardware reset of IEE module. Attributes and keys of all regions are cleared.
+ *
+ * param base IEER peripheral address.
+ */
+void IEE_Init(IEE_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable IEE clock. */
+ CLOCK_EnableClock(kCLOCK_Iee);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset IEE module and wait the reset operation done. */
+ base->GCFG |= IEE_GCFG_RST_MASK;
+}
+
+/*!
+ * brief Loads default values to the IEE configuration structure.
+ *
+ * Loads default values to the IEE region configuration structure. The default values are as follows.
+ * code
+ * config->bypass = kIEE_AesUseMdField;
+ * config->mode = kIEE_ModeNone;
+ * config->keySize = kIEE_AesCTR128XTS256;
+ * config->pageOffset = 0U;
+ * endcode
+ *
+ * param config Configuration for the selected IEE region.
+ */
+void IEE_GetDefaultConfig(iee_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->bypass = kIEE_AesUseMdField;
+ config->mode = kIEE_ModeNone;
+ config->keySize = kIEE_AesCTR128XTS256;
+ config->pageOffset = 0U;
+}
+
+/*!
+ * brief Sets the IEE module according to the configuration structure.
+ *
+ * This function configures IEE region according to configuration structure.
+ *
+ * param base IEE peripheral address.
+ * param region Selection of the IEE region to be configured.
+ * param config Configuration for the selected IEE region.
+ */
+void IEE_SetRegionConfig(IEE_Type *base, iee_region_t region, iee_config_t *config)
+{
+ base->REGX[region].REGATTR =
+ IEE_REGATTR_BYP(config->bypass) | IEE_REGATTR_MD(config->mode) | IEE_REGATTR_KS(config->keySize);
+#if (defined(FSL_IEE_USE_PAGE_OFFSET) && (FSL_IEE_USE_PAGE_OFFSET > 0U))
+ base->REGX[region].REGPO = IEE_REGPO_PGOFF(config->pageOffset);
+#endif /* FSL_IEE_USE_PAGE_OFFSET */
+}
+
+/*!
+ * brief Sets the IEE module key.
+ *
+ * This function sets specified AES key for the given region.
+ *
+ * param base IEE peripheral address.
+ * param region Selection of the IEE region to be configured.
+ * param keyNum Selection of AES KEY1 or KEY2.
+ * param key AES key.
+ * param keySize Size of AES key.
+ */
+status_t IEE_SetRegionKey(
+ IEE_Type *base, iee_region_t region, iee_aes_key_num_t keyNum, const uint8_t *key, size_t keySize)
+{
+ register const uint32_t *from32 = (const uint32_t *)(uintptr_t)key;
+ register volatile uint32_t *to32 = NULL;
+
+ if (keyNum == kIEE_AesKey1)
+ {
+ to32 = &base->REGX[region].REGKEY1[0];
+ }
+
+ else if (keyNum == kIEE_AesKey2)
+ {
+ to32 = &base->REGX[region].REGKEY2[0];
+ }
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ while (keySize >= sizeof(uint32_t))
+ {
+ *to32 = *from32;
+ keySize -= sizeof(uint32_t);
+ from32++;
+ to32++;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Lock the IEE region configuration.
+ *
+ * IEE region Key, Offset and Attribute registers are locked.
+ * Only system reset can clear the Lock bit.
+ *
+ * param base IEE peripheral address.
+ * param region Selection of the IEE region to be locked.
+ */
+void IEE_LockRegionConfig(IEE_Type *base, iee_region_t region)
+{
+ base->GCFG |= (uint32_t)(0x1UL << (uint32_t)region);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.h b/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.h
new file mode 100644
index 0000000000..7400ec932f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/iee/fsl_iee.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_IEE_H_
+#define _FSL_IEE_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup iee
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief IEE driver version. Version 2.1.1.
+ *
+ * Current version: 2.1.1
+ *
+ * Change log:
+ * - Version 2.0.0
+ * - Initial version
+ * - Version 2.1.0
+ * - Add region lock function IEE_LockRegionConfig() and driver clock control
+ * - Version 2.1.1
+ * - Fixed MISRA issues.
+ */
+#define FSL_IEE_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+
+/*! @brief IEE region. */
+typedef enum _iee_region
+{
+ kIEE_Region0 = 0U, /*!< IEE region 0 */
+ kIEE_Region1 = 1U, /*!< IEE region 1 */
+ kIEE_Region2 = 2U, /*!< IEE region 2 */
+ kIEE_Region3 = 3U, /*!< IEE region 3 */
+ kIEE_Region4 = 4U, /*!< IEE region 4 */
+ kIEE_Region5 = 5U, /*!< IEE region 5 */
+ kIEE_Region6 = 6U, /*!< IEE region 6 */
+ kIEE_Region7 = 7U /*!< IEE region 7 */
+} iee_region_t;
+
+/*! @brief IEE AES enablement/bypass. */
+typedef enum _iee_aes_bypass
+{
+ kIEE_AesUseMdField = 0U, /*!< AES encryption/decryption enabled */
+ kIEE_AesBypass = 1U /*!< AES encryption/decryption bypass */
+} iee_aes_bypass_t;
+
+/*! @brief IEE AES mode. */
+typedef enum _iee_aes_mode
+{
+ kIEE_ModeNone = 0U, /*!< AES NONE mode */
+ kIEE_ModeAesXTS = 1U, /*!< AES XTS mode */
+ kIEE_ModeAesCTRWAddress = 2U, /*!< CTR w address binding mode */
+ kIEE_ModeAesCTRWOAddress = 3U, /*!< AES CTR w/o address binding mode */
+ kIEE_ModeAesCTRkeystream = 4U /*!< AES CTR keystream only */
+} iee_aes_mode_t;
+
+/*! @brief IEE AES key size. */
+typedef enum _iee_aes_key_size
+{
+ kIEE_AesCTR128XTS256 = 0U, /*!< AES 128 bits (CTR), 256 bits (XTS) */
+ kIEE_AesCTR256XTS512 = 1U /*!< AES 256 bits (CTR), 512 bits (XTS) */
+} iee_aes_key_size_t;
+
+/*! @brief IEE AES ke number. */
+typedef enum _iee_aes_key_num
+{
+ kIEE_AesKey1 = 1U, /*!< AES Key 1 */
+ kIEE_AesKey2 = 2U /*!< AES Key 2 */
+} iee_aes_key_num_t;
+
+/*! @brief IEE configuration structure. */
+typedef struct _iee_config
+{
+ iee_aes_bypass_t bypass; /*!< AES encryption/decryption bypass */
+ iee_aes_mode_t mode; /*!< AES mode */
+ iee_aes_key_size_t keySize; /*!< size of AES key */
+ uint32_t pageOffset; /*!< Offset to physical memory location from IEE start address */
+} iee_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Resets IEE module to factory default values.
+ *
+ * This function performs hardware reset of IEE module. Attributes and keys of all regions are cleared.
+ *
+ * @param base IEER peripheral address.
+ */
+void IEE_Init(IEE_Type *base);
+
+/*!
+ * @brief Loads default values to the IEE configuration structure.
+ *
+ * Loads default values to the IEE region configuration structure. The default values are as follows.
+ * @code
+ * config->bypass = kIEE_AesUseMdField;
+ * config->mode = kIEE_ModeNone;
+ * config->keySize = kIEE_AesCTR128XTS256;
+ * config->pageOffset = 0U;
+ * @endcode
+ *
+ * @param config Configuration for the selected IEE region.
+ */
+void IEE_GetDefaultConfig(iee_config_t *config);
+
+/*!
+ * @brief Sets the IEE module according to the configuration structure.
+ *
+ * This function configures IEE region according to configuration structure.
+ *
+ * @param base IEE peripheral address.
+ * @param region Selection of the IEE region to be configured.
+ * @param config Configuration for the selected IEE region.
+ */
+void IEE_SetRegionConfig(IEE_Type *base, iee_region_t region, iee_config_t *config);
+
+/*!
+ * @brief Sets the IEE module key.
+ *
+ * This function sets specified AES key for the given region.
+ *
+ * @param base IEE peripheral address.
+ * @param region Selection of the IEE region to be configured.
+ * @param keyNum Selection of AES KEY1 or KEY2.
+ * @param key AES key.
+ * @param keySize Size of AES key.
+ */
+status_t IEE_SetRegionKey(
+ IEE_Type *base, iee_region_t region, iee_aes_key_num_t keyNum, const uint8_t *key, size_t keySize);
+
+/*!
+ * @brief Computes IEE offset to be set for specifed memory location.
+ *
+ * This function calculates offset that must be set for IEE region to access physical memory location.
+ *
+ * @param addressIee Address of IEE peripheral.
+ * @param addressMemory Address of physical memory location.
+ */
+static inline uint32_t IEE_GetOffset(uint32_t addressIee, uint32_t addressMemory)
+{
+ return (addressMemory - addressIee) >> 12;
+}
+
+/*!
+ * @brief Lock the IEE region configuration.
+ *
+ * This function locks IEE region registers for Key, Offset and Attribute.
+ * Only system reset can clear the Lock bit.
+ *
+ * @param base IEE peripheral address.
+ * @param region Selection of the IEE region to be locked.
+ */
+void IEE_LockRegionConfig(IEE_Type *base, iee_region_t region);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ *@}
+ */
+
+#endif /* _FSL_IEE_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.c b/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.c
new file mode 100644
index 0000000000..afc6af6f87
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2020-2021, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_iee_apc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.iee_apc"
+#endif
+
+#define IOMUXC_LPSR_GPR_APC_ADDR_MASK 0xFFFFFFF8U
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Enable the APC IEE Region setting.
+ *
+ * This function enables IOMUXC LPSR GPR and APC IEE for setting the region.
+ *
+ * param base APC IEE peripheral address.
+ */
+void IEE_APC_GlobalEnable(IEE_APC_Type *base)
+{
+ /* APC_x bits in GPR2 to GPR25 only take effect when this bit is set high */
+ IOMUXC_LPSR_GPR->GPR25 |= IOMUXC_LPSR_GPR_GPR25_APC_VALID_MASK;
+ __DSB();
+ return;
+}
+
+/*!
+ * brief Disables the APC IEE Region setting.
+ *
+ * This function disables IOMUXC LPSR GPR and APC IEE for setting the region.
+ *
+ * param base APC IEE peripheral address.
+ */
+void IEE_APC_GlobalDisable(IEE_APC_Type *base)
+{
+ /* APC_x bits in GPR2 to GPR25 only take effect when this bit is set high */
+ IOMUXC_LPSR_GPR->GPR25 &= ~IOMUXC_LPSR_GPR_GPR25_APC_VALID_MASK;
+ __DSB();
+ return;
+}
+
+/*!
+ * brief Sets the APC IEE Memory Region setting.
+ *
+ * This function configure IOMUXC LPSR GPR and APC IEE for the encryption region.
+ *
+ * param base APC IEE peripheral address.
+ * param region Selection of the APC IEE region to be configured.
+ * param startAddr Start encryption adress for the selected APC IEE region.
+ * param endAddr End encryption adress for the selected APC IEE region.
+ */
+status_t IEE_APC_SetRegionConfig(IEE_APC_Type *base, iee_apc_region_t region, uint32_t startAddr, uint32_t endAddr)
+{
+ /* bit[2:0] of adress must be zero
+ *
+ * Note: For i.MXRT1170, region is [bot:top), the end is open interval. So the bit[2:0] of the end address must
+ * be zero.
+ * Note: from design's aspect, 'top' means the top of the space, the higher address which is the end
+ * address.
+ */
+ if ((startAddr & (~IOMUXC_LPSR_GPR_GPR3_APC_AC_R0_TOP_MASK)) != 0U ||
+ (endAddr & (~IOMUXC_LPSR_GPR_GPR2_APC_AC_R0_BOT_MASK)) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (region == kIEE_APC_Region0)
+ {
+ IOMUXC_LPSR_GPR->GPR2 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR3 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION0_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION0_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region1)
+ {
+ IOMUXC_LPSR_GPR->GPR4 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR5 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION1_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION1_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region2)
+ {
+ IOMUXC_LPSR_GPR->GPR6 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR7 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION2_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION2_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region3)
+ {
+ IOMUXC_LPSR_GPR->GPR8 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR9 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION3_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION3_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region4)
+ {
+ IOMUXC_LPSR_GPR->GPR10 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR11 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION4_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION4_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region5)
+ {
+ IOMUXC_LPSR_GPR->GPR12 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR13 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION5_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION5_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region6)
+ {
+ IOMUXC_LPSR_GPR->GPR14 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR15 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION6_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION6_TOP_ADDR = endAddr >> 3;
+ }
+ if (region == kIEE_APC_Region7)
+ {
+ IOMUXC_LPSR_GPR->GPR16 |= startAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IOMUXC_LPSR_GPR->GPR17 |= endAddr & IOMUXC_LPSR_GPR_APC_ADDR_MASK;
+ IEE_APC->REGION7_BOT_ADDR = startAddr >> 3;
+ IEE_APC->REGION7_TOP_ADDR = endAddr >> 3;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Lock the LPSR GPR and APC IEE configuration.
+ *
+ * This function locks writting to IOMUXC LPSR GPR and APC IEE encryption region setting registers.
+ * Only system reset can clear the LPSR GPR and APC IEE-RDC_D0/1 Lock bit
+ *
+ * param base APC IEE peripheral address.
+ * param region Selection of the APC IEE region to be locked.
+ */
+status_t IEE_APC_LockRegionConfig(IEE_APC_Type *base, iee_apc_region_t region, iee_apc_domain_t domain)
+{
+ if (region == kIEE_APC_Region0)
+ {
+ /* Locks write into APC Region 0 BOT address */
+ IOMUXC_LPSR_GPR->GPR2 |= IOMUXC_LPSR_GPR_GPR2_LOCK(1);
+ /* Locks write into APC Region 0 TOP address */
+ IOMUXC_LPSR_GPR->GPR3 |= IOMUXC_LPSR_GPR_GPR3_LOCK(1);
+ /* Locks write into APC REGION 0 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR18 |= IOMUXC_LPSR_GPR_GPR18_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION0_RDC_D0 |= IEE_APC_REGION0_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION0_RDC_D0 |= IEE_APC_REGION0_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION0_RDC_D1 |= IEE_APC_REGION0_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION0_RDC_D1 |= IEE_APC_REGION0_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region1)
+ {
+ /* Locks write into APC Region 1 BOT address */
+ IOMUXC_LPSR_GPR->GPR4 |= IOMUXC_LPSR_GPR_GPR4_LOCK(1);
+ /* Locks write into APC Region 1 TOP address */
+ IOMUXC_LPSR_GPR->GPR5 |= IOMUXC_LPSR_GPR_GPR5_LOCK(1);
+ /* Locks write into APC REGION 1 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR19 |= IOMUXC_LPSR_GPR_GPR19_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION1_RDC_D0 |= IEE_APC_REGION1_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION1_RDC_D0 |= IEE_APC_REGION1_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION1_RDC_D1 |= IEE_APC_REGION1_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION1_RDC_D1 |= IEE_APC_REGION1_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region2)
+ {
+ /* Locks write into APC Region 2 BOT address */
+ IOMUXC_LPSR_GPR->GPR6 |= IOMUXC_LPSR_GPR_GPR6_LOCK(1);
+ /* Locks write into APC Region 2 TOP address */
+ IOMUXC_LPSR_GPR->GPR7 |= IOMUXC_LPSR_GPR_GPR7_LOCK(1);
+ /* Locks write into APC REGION 2 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR20 |= IOMUXC_LPSR_GPR_GPR20_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION2_RDC_D0 |= IEE_APC_REGION2_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION2_RDC_D0 |= IEE_APC_REGION2_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION2_RDC_D1 |= IEE_APC_REGION2_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION2_RDC_D1 |= IEE_APC_REGION2_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region3)
+ {
+ /* Locks write into APC Region 3 BOT address */
+ IOMUXC_LPSR_GPR->GPR8 |= IOMUXC_LPSR_GPR_GPR8_LOCK(1);
+ /* Locks write into APC Region 3 TOP address */
+ IOMUXC_LPSR_GPR->GPR9 |= IOMUXC_LPSR_GPR_GPR9_LOCK(1);
+ /* Locks write into APC REGION 3 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR21 |= IOMUXC_LPSR_GPR_GPR21_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION3_RDC_D0 |= IEE_APC_REGION3_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION3_RDC_D0 |= IEE_APC_REGION3_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION3_RDC_D1 |= IEE_APC_REGION3_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION3_RDC_D1 |= IEE_APC_REGION3_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region4)
+ {
+ /* Locks write into APC Region 4 BOT address */
+ IOMUXC_LPSR_GPR->GPR10 |= IOMUXC_LPSR_GPR_GPR10_LOCK(1);
+ /* Locks write into APC Region 4 TOP address */
+ IOMUXC_LPSR_GPR->GPR11 |= IOMUXC_LPSR_GPR_GPR11_LOCK(1);
+ /* Locks write into APC REGION 4 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR22 |= IOMUXC_LPSR_GPR_GPR22_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION4_RDC_D0 |= IEE_APC_REGION4_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION4_RDC_D0 |= IEE_APC_REGION4_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION4_RDC_D1 |= IEE_APC_REGION4_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION4_RDC_D1 |= IEE_APC_REGION4_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region5)
+ {
+ /* Locks write into APC Region 5 BOT address */
+ IOMUXC_LPSR_GPR->GPR12 |= IOMUXC_LPSR_GPR_GPR12_LOCK(1);
+ /* Locks write into APC Region 5 TOP address */
+ IOMUXC_LPSR_GPR->GPR13 |= IOMUXC_LPSR_GPR_GPR13_LOCK(1);
+ /* Locks write into APC REGION 5 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR23 |= IOMUXC_LPSR_GPR_GPR23_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION5_RDC_D0 |= IEE_APC_REGION5_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION5_RDC_D0 |= IEE_APC_REGION5_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION5_RDC_D1 |= IEE_APC_REGION5_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION5_RDC_D1 |= IEE_APC_REGION5_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region6)
+ {
+ /* Locks write into APC Region 6 BOT address */
+ IOMUXC_LPSR_GPR->GPR14 |= IOMUXC_LPSR_GPR_GPR14_LOCK(1);
+ /* Locks write into APC Region 6 TOP address */
+ IOMUXC_LPSR_GPR->GPR15 |= IOMUXC_LPSR_GPR_GPR15_LOCK(1);
+ /* Locks write into APC REGION 6 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR24 |= IOMUXC_LPSR_GPR_GPR24_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION6_RDC_D0 |= IEE_APC_REGION6_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION6_RDC_D0 |= IEE_APC_REGION6_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION6_RDC_D1 |= IEE_APC_REGION6_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION6_RDC_D1 |= IEE_APC_REGION6_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ if (region == kIEE_APC_Region7)
+ {
+ /* Locks write into APC Region 7 BOT address */
+ IOMUXC_LPSR_GPR->GPR16 |= IOMUXC_LPSR_GPR_GPR15_LOCK(1);
+ /* Locks write into APC Region 7 TOP address */
+ IOMUXC_LPSR_GPR->GPR17 |= IOMUXC_LPSR_GPR_GPR16_LOCK(1);
+ /* Locks write into APC REGION 7 Valid, Debug, Sand box, Safe box, Execute only and Encrytp enable bits */
+ IOMUXC_LPSR_GPR->GPR25 |= IOMUXC_LPSR_GPR_GPR25_LOCK(1);
+
+ if (domain == kIEE_APC_Domain0)
+ {
+ IEE_APC->REGION7_RDC_D0 |= IEE_APC_REGION7_RDC_D0_RDC_D0_WRITE_DIS_MASK;
+ IEE_APC->REGION7_RDC_D0 |= IEE_APC_REGION7_RDC_D0_RDC_D0_LOCK_MASK;
+ }
+ else if (domain == kIEE_APC_Domain1)
+ {
+ IEE_APC->REGION7_RDC_D1 |= IEE_APC_REGION7_RDC_D1_RDC_D1_WRITE_DIS_MASK;
+ IEE_APC->REGION7_RDC_D1 |= IEE_APC_REGION7_RDC_D1_RDC_D1_LOCK_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Enable the IEE encryption/decryption for specific region.
+ *
+ * This function enables encryption/decryption by writting to IOMUXC LPSR GPR.
+ *
+ * param base APC IEE peripheral address.
+ * param region Selection of the APC IEE region to be enabled.
+ */
+void IEE_APC_RegionEnable(IEE_APC_Type *base, iee_apc_region_t region)
+{
+ if (region == kIEE_APC_Region0)
+ {
+ IOMUXC_LPSR_GPR->GPR18 |= IOMUXC_LPSR_GPR_GPR18_APC_R0_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region1)
+ {
+ IOMUXC_LPSR_GPR->GPR19 |= IOMUXC_LPSR_GPR_GPR19_APC_R1_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region2)
+ {
+ IOMUXC_LPSR_GPR->GPR20 |= IOMUXC_LPSR_GPR_GPR20_APC_R2_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region3)
+ {
+ IOMUXC_LPSR_GPR->GPR21 |= IOMUXC_LPSR_GPR_GPR21_APC_R3_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region4)
+ {
+ IOMUXC_LPSR_GPR->GPR22 |= IOMUXC_LPSR_GPR_GPR22_APC_R4_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region5)
+ {
+ IOMUXC_LPSR_GPR->GPR23 |= IOMUXC_LPSR_GPR_GPR23_APC_R5_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region6)
+ {
+ IOMUXC_LPSR_GPR->GPR24 |= IOMUXC_LPSR_GPR_GPR24_APC_R6_ENCRYPT_ENABLE_MASK;
+ }
+ if (region == kIEE_APC_Region7)
+ {
+ IOMUXC_LPSR_GPR->GPR25 |= IOMUXC_LPSR_GPR_GPR25_APC_R7_ENCRYPT_ENABLE_MASK;
+ }
+
+ return;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.h b/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.h
new file mode 100644
index 0000000000..e179ac0ecc
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/iee_apc/fsl_iee_apc.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020-2021, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_IEE_APC_H_
+#define _FSL_IEE_APC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup ieer
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief IEE_APC driver version. Version 2.0.1.
+ *
+ * Current version: 2.0.1
+ *
+ * Change log:
+ * - Version 2.0.0
+ * - Initial version
+ * - Version 2.0.1
+ * - Fixed MISRA issues.
+ */
+#define FSL_IEE_APC_DRIVER_VERSION (MAKE_VERSION(2, 0, 1))
+/*@}*/
+
+/*! @brief APC IEE regions. */
+typedef enum _iee_apc_region
+{
+ kIEE_APC_Region0 = 0U, /*!< APC IEE region 0 */
+ kIEE_APC_Region1 = 1U, /*!< APC IEE region 1 */
+ kIEE_APC_Region2 = 2U, /*!< APC IEE region 2 */
+ kIEE_APC_Region3 = 3U, /*!< APC IEE region 3 */
+ kIEE_APC_Region4 = 4U, /*!< APC IEE region 4 */
+ kIEE_APC_Region5 = 5U, /*!< APC IEE region 5 */
+ kIEE_APC_Region6 = 6U, /*!< APC IEE region 6 */
+ kIEE_APC_Region7 = 7U /*!< APC IEE region 7 */
+} iee_apc_region_t;
+
+/*! @brief APC IEE domains. */
+typedef enum _apc_iee_domain
+{
+ kIEE_APC_Domain0 = 0U, /*!< APC IEE region 0 */
+ kIEE_APC_Domain1 = 1U /*!< APC IEE region 1 */
+} iee_apc_domain_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Enable the APC IEE Region setting.
+ *
+ * This function enables IOMUXC LPSR GPR and APC IEE for setting the region.
+ *
+ * @param base APC IEE peripheral address.
+ */
+void IEE_APC_GlobalEnable(IEE_APC_Type *base);
+
+/*!
+ * @brief Disables the APC IEE Region setting.
+ *
+ * This function disables IOMUXC LPSR GPR and APC IEE for setting the region.
+ *
+ * @param base APC IEE peripheral address.
+ */
+void IEE_APC_GlobalDisable(IEE_APC_Type *base);
+
+/*!
+ * @brief Sets the APC IEE Memory Region Descriptors.
+ *
+ * This function configures APC IEE Memory Region Descriptor according to region configuration structure.
+ *
+ * @param base APC IEE peripheral address.
+ * @param region Selection of the APC IEE region to be configured.
+ * @param startAddr Start encryption adress for the selected APC IEE region.
+ * @param endAddr End encryption adress for the selected APC IEE region.
+ */
+status_t IEE_APC_SetRegionConfig(IEE_APC_Type *base, iee_apc_region_t region, uint32_t startAddr, uint32_t endAddr);
+
+/*!
+ * @brief Lock the LPSR GPR and APC IEE configuration.
+ *
+ * This function locks writting to IOMUXC LPSR GPR and APC IEE encryption region setting registers.
+ * Only system reset can clear the LPSR GPR and APC IEE-RDC_D0/1 Lock bit
+ *
+ * @param base APC IEE peripheral address.
+ * @param region Selection of the APC IEE region to be locked.
+ * @param domain
+ */
+status_t IEE_APC_LockRegionConfig(IEE_APC_Type *base, iee_apc_region_t region, iee_apc_domain_t domain);
+
+/*!
+ * @brief Enable the IEE encryption/decryption and can lock this setting.
+ *
+ * This function enables encryption/decryption by writting to IOMUXC LPSR GPR.
+ *
+ * @param base APC IEE peripheral address.
+ * @param region Selection of the APC IEE region to be enabled.
+ */
+void IEE_APC_RegionEnable(IEE_APC_Type *base, iee_apc_region_t region);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ *@}
+ */
+
+#endif /* _FSL_IEE_APC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.c b/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.c
new file mode 100644
index 0000000000..68ccade87d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpio.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.igpio"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of GPIO peripheral base address. */
+static GPIO_Type *const s_gpioBases[] = GPIO_BASE_PTRS;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of GPIO clock name. */
+static const clock_ip_name_t s_gpioClock[] = GPIO_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*!
+ * @brief Gets the GPIO instance according to the GPIO base
+ *
+ * @param base GPIO peripheral base pointer(PTA, PTB, PTC, etc.)
+ * @retval GPIO instance
+ */
+static uint32_t GPIO_GetInstance(GPIO_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t GPIO_GetInstance(GPIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_gpioBases); instance++)
+ {
+ if (s_gpioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_gpioBases));
+
+ return instance;
+}
+#endif
+
+/*!
+ * brief Initializes the GPIO peripheral according to the specified
+ * parameters in the initConfig.
+ *
+ * param base GPIO base pointer.
+ * param pin Specifies the pin number
+ * param initConfig pointer to a ref gpio_pin_config_t structure that
+ * contains the configuration information.
+ */
+void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable GPIO clock. */
+ uint32_t instance = GPIO_GetInstance(base);
+
+ /* If The clock IP is valid, enable the clock gate. */
+ if ((instance < ARRAY_SIZE(s_gpioClock)) && (kCLOCK_IpInvalid != s_gpioClock[instance]))
+ {
+ (void)CLOCK_EnableClock(s_gpioClock[instance]);
+ }
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Register reset to default value */
+ base->IMR &= ~(1UL << pin);
+
+ /* Configure GPIO pin direction */
+ if (Config->direction == kGPIO_DigitalInput)
+ {
+ base->GDIR &= ~(1UL << pin);
+ }
+ else
+ {
+ GPIO_PinWrite(base, pin, Config->outputLogic);
+ base->GDIR |= (1UL << pin);
+ }
+
+ /* Configure GPIO pin interrupt mode */
+ GPIO_SetPinInterruptConfig(base, pin, Config->interruptMode);
+}
+
+/*!
+ * brief Sets the output level of the individual GPIO pin to logic 1 or 0.
+ *
+ * param base GPIO base pointer.
+ * param pin GPIO port pin number.
+ * param output GPIOpin output logic level.
+ * - 0: corresponding pin output low-logic level.
+ * - 1: corresponding pin output high-logic level.
+ */
+void GPIO_PinWrite(GPIO_Type *base, uint32_t pin, uint8_t output)
+{
+ assert(pin < 32U);
+ if (output == 0U)
+ {
+#if (defined(FSL_FEATURE_IGPIO_HAS_DR_CLEAR) && FSL_FEATURE_IGPIO_HAS_DR_CLEAR)
+ base->DR_CLEAR = (1UL << pin);
+#else
+ base->DR &= ~(1UL << pin); /* Set pin output to low level.*/
+#endif
+ }
+ else
+ {
+#if (defined(FSL_FEATURE_IGPIO_HAS_DR_SET) && FSL_FEATURE_IGPIO_HAS_DR_SET)
+ base->DR_SET = (1UL << pin);
+#else
+ base->DR |= (1UL << pin); /* Set pin output to high level.*/
+#endif
+ }
+}
+
+/*!
+ * brief Sets the current pin interrupt mode.
+ *
+ * param base GPIO base pointer.
+ * param pin GPIO port pin number.
+ * param pininterruptMode pointer to a ref gpio_interrupt_mode_t structure
+ * that contains the interrupt mode information.
+ */
+void GPIO_PinSetInterruptConfig(GPIO_Type *base, uint32_t pin, gpio_interrupt_mode_t pinInterruptMode)
+{
+ volatile uint32_t *icr;
+ uint32_t icrShift;
+
+ icrShift = pin;
+
+ /* Register reset to default value */
+ base->EDGE_SEL &= ~(1UL << pin);
+
+ if (pin < 16U)
+ {
+ icr = &(base->ICR1);
+ }
+ else
+ {
+ icr = &(base->ICR2);
+ icrShift -= 16U;
+ }
+ switch (pinInterruptMode)
+ {
+ case (kGPIO_IntLowLevel):
+ *icr &= ~(3UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntHighLevel):
+ *icr = (*icr & (~(3UL << (2UL * icrShift)))) | (1UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntRisingEdge):
+ *icr = (*icr & (~(3UL << (2UL * icrShift)))) | (2UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntFallingEdge):
+ *icr |= (3UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntRisingOrFallingEdge):
+ base->EDGE_SEL |= (1UL << pin);
+ break;
+ default:; /* Intentional empty default */
+ break;
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.h b/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.h
new file mode 100644
index 0000000000..bd0e7f20bb
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/igpio/fsl_gpio.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_GPIO_H_
+#define _FSL_GPIO_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup gpio_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief GPIO driver version. */
+#define FSL_GPIO_DRIVER_VERSION (MAKE_VERSION(2, 0, 6))
+/*@}*/
+
+/*! @brief GPIO direction definition. */
+typedef enum _gpio_pin_direction
+{
+ kGPIO_DigitalInput = 0U, /*!< Set current pin as digital input.*/
+ kGPIO_DigitalOutput = 1U, /*!< Set current pin as digital output.*/
+} gpio_pin_direction_t;
+
+/*! @brief GPIO interrupt mode definition. */
+typedef enum _gpio_interrupt_mode
+{
+ kGPIO_NoIntmode = 0U, /*!< Set current pin general IO functionality.*/
+ kGPIO_IntLowLevel = 1U, /*!< Set current pin interrupt is low-level sensitive.*/
+ kGPIO_IntHighLevel = 2U, /*!< Set current pin interrupt is high-level sensitive.*/
+ kGPIO_IntRisingEdge = 3U, /*!< Set current pin interrupt is rising-edge sensitive.*/
+ kGPIO_IntFallingEdge = 4U, /*!< Set current pin interrupt is falling-edge sensitive.*/
+ kGPIO_IntRisingOrFallingEdge = 5U, /*!< Enable the edge select bit to override the ICR register's configuration.*/
+} gpio_interrupt_mode_t;
+
+/*! @brief GPIO Init structure definition. */
+typedef struct _gpio_pin_config
+{
+ gpio_pin_direction_t direction; /*!< Specifies the pin direction. */
+ uint8_t outputLogic; /*!< Set a default output logic, which has no use in input */
+ gpio_interrupt_mode_t
+ interruptMode; /*!< Specifies the pin interrupt mode, a value of @ref gpio_interrupt_mode_t. */
+} gpio_pin_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name GPIO Initialization and Configuration functions
+ * @{
+ */
+
+/*!
+ * @brief Initializes the GPIO peripheral according to the specified
+ * parameters in the initConfig.
+ *
+ * @param base GPIO base pointer.
+ * @param pin Specifies the pin number
+ * @param Config pointer to a @ref gpio_pin_config_t structure that
+ * contains the configuration information.
+ */
+void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config);
+/*@}*/
+
+/*!
+ * @name GPIO Reads and Write Functions
+ * @{
+ */
+
+/*!
+ * @brief Sets the output level of the individual GPIO pin to logic 1 or 0.
+ *
+ * @param base GPIO base pointer.
+ * @param pin GPIO port pin number.
+ * @param output GPIOpin output logic level.
+ * - 0: corresponding pin output low-logic level.
+ * - 1: corresponding pin output high-logic level.
+ */
+void GPIO_PinWrite(GPIO_Type *base, uint32_t pin, uint8_t output);
+
+/*!
+ * @brief Sets the output level of the individual GPIO pin to logic 1 or 0.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PinWrite.
+ */
+static inline void GPIO_WritePinOutput(GPIO_Type *base, uint32_t pin, uint8_t output)
+{
+ GPIO_PinWrite(base, pin, output);
+}
+
+/*!
+ * @brief Sets the output level of the multiple GPIO pins to the logic 1.
+ *
+ * @param base GPIO peripheral base pointer (GPIO1, GPIO2, GPIO3, and so on.)
+ * @param mask GPIO pin number macro
+ */
+static inline void GPIO_PortSet(GPIO_Type *base, uint32_t mask)
+{
+#if (defined(FSL_FEATURE_IGPIO_HAS_DR_SET) && (FSL_FEATURE_IGPIO_HAS_DR_SET == 1))
+ base->DR_SET = mask;
+#else
+ base->DR |= mask;
+#endif /* FSL_FEATURE_IGPIO_HAS_DR_SET */
+}
+
+/*!
+ * @brief Sets the output level of the multiple GPIO pins to the logic 1.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PortSet.
+ */
+static inline void GPIO_SetPinsOutput(GPIO_Type *base, uint32_t mask)
+{
+ GPIO_PortSet(base, mask);
+}
+
+/*!
+ * @brief Sets the output level of the multiple GPIO pins to the logic 0.
+ *
+ * @param base GPIO peripheral base pointer (GPIO1, GPIO2, GPIO3, and so on.)
+ * @param mask GPIO pin number macro
+ */
+static inline void GPIO_PortClear(GPIO_Type *base, uint32_t mask)
+{
+#if (defined(FSL_FEATURE_IGPIO_HAS_DR_CLEAR) && (FSL_FEATURE_IGPIO_HAS_DR_CLEAR == 1))
+ base->DR_CLEAR = mask;
+#else
+ base->DR &= ~mask;
+#endif /* FSL_FEATURE_IGPIO_HAS_DR_CLEAR */
+}
+
+/*!
+ * @brief Sets the output level of the multiple GPIO pins to the logic 0.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PortClear.
+ */
+static inline void GPIO_ClearPinsOutput(GPIO_Type *base, uint32_t mask)
+{
+ GPIO_PortClear(base, mask);
+}
+
+/*!
+ * @brief Reverses the current output logic of the multiple GPIO pins.
+ *
+ * @param base GPIO peripheral base pointer (GPIO1, GPIO2, GPIO3, and so on.)
+ * @param mask GPIO pin number macro
+ */
+static inline void GPIO_PortToggle(GPIO_Type *base, uint32_t mask)
+{
+#if (defined(FSL_FEATURE_IGPIO_HAS_DR_TOGGLE) && (FSL_FEATURE_IGPIO_HAS_DR_TOGGLE == 1))
+ base->DR_TOGGLE = mask;
+#else
+ base->DR ^= mask;
+#endif /* FSL_FEATURE_IGPIO_HAS_DR_TOGGLE */
+}
+
+/*!
+ * @brief Reads the current input value of the GPIO port.
+ *
+ * @param base GPIO base pointer.
+ * @param pin GPIO port pin number.
+ * @retval GPIO port input value.
+ */
+static inline uint32_t GPIO_PinRead(GPIO_Type *base, uint32_t pin)
+{
+ assert(pin < 32U);
+
+ return (((base->DR) >> pin) & 0x1U);
+}
+
+/*!
+ * @brief Reads the current input value of the GPIO port.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PinRead.
+ */
+static inline uint32_t GPIO_ReadPinInput(GPIO_Type *base, uint32_t pin)
+{
+ return GPIO_PinRead(base, pin);
+}
+/*@}*/
+
+/*!
+ * @name GPIO Reads Pad Status Functions
+ * @{
+ */
+
+/*!
+ * @brief Reads the current GPIO pin pad status.
+ *
+ * @param base GPIO base pointer.
+ * @param pin GPIO port pin number.
+ * @retval GPIO pin pad status value.
+ */
+static inline uint8_t GPIO_PinReadPadStatus(GPIO_Type *base, uint32_t pin)
+{
+ assert(pin < 32U);
+
+ return (uint8_t)(((base->PSR) >> pin) & 0x1U);
+}
+
+/*!
+ * @brief Reads the current GPIO pin pad status.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PinReadPadStatus.
+ */
+static inline uint8_t GPIO_ReadPadStatus(GPIO_Type *base, uint32_t pin)
+{
+ return GPIO_PinReadPadStatus(base, pin);
+}
+
+/*@}*/
+
+/*!
+ * @name Interrupts and flags management functions
+ * @{
+ */
+
+/*!
+ * @brief Sets the current pin interrupt mode.
+ *
+ * @param base GPIO base pointer.
+ * @param pin GPIO port pin number.
+ * @param pinInterruptMode pointer to a @ref gpio_interrupt_mode_t structure
+ * that contains the interrupt mode information.
+ */
+void GPIO_PinSetInterruptConfig(GPIO_Type *base, uint32_t pin, gpio_interrupt_mode_t pinInterruptMode);
+
+/*!
+ * @brief Sets the current pin interrupt mode.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PinSetInterruptConfig.
+ */
+static inline void GPIO_SetPinInterruptConfig(GPIO_Type *base, uint32_t pin, gpio_interrupt_mode_t pinInterruptMode)
+{
+ GPIO_PinSetInterruptConfig(base, pin, pinInterruptMode);
+}
+
+/*!
+ * @brief Enables the specific pin interrupt.
+ *
+ * @param base GPIO base pointer.
+ * @param mask GPIO pin number macro.
+ */
+static inline void GPIO_PortEnableInterrupts(GPIO_Type *base, uint32_t mask)
+{
+ base->IMR |= mask;
+}
+
+/*!
+ * @brief Enables the specific pin interrupt.
+ *
+ * @param base GPIO base pointer.
+ * @param mask GPIO pin number macro.
+ */
+static inline void GPIO_EnableInterrupts(GPIO_Type *base, uint32_t mask)
+{
+ GPIO_PortEnableInterrupts(base, mask);
+}
+
+/*!
+ * @brief Disables the specific pin interrupt.
+ *
+ * @param base GPIO base pointer.
+ * @param mask GPIO pin number macro.
+ */
+static inline void GPIO_PortDisableInterrupts(GPIO_Type *base, uint32_t mask)
+{
+ base->IMR &= ~mask;
+}
+
+/*!
+ * @brief Disables the specific pin interrupt.
+ * @deprecated Do not use this function. It has been superceded by @ref GPIO_PortDisableInterrupts.
+ */
+static inline void GPIO_DisableInterrupts(GPIO_Type *base, uint32_t mask)
+{
+ GPIO_PortDisableInterrupts(base, mask);
+}
+
+/*!
+ * @brief Reads individual pin interrupt status.
+ *
+ * @param base GPIO base pointer.
+ * @retval current pin interrupt status flag.
+ */
+static inline uint32_t GPIO_PortGetInterruptFlags(GPIO_Type *base)
+{
+ return base->ISR;
+}
+
+/*!
+ * @brief Reads individual pin interrupt status.
+ *
+ * @param base GPIO base pointer.
+ * @retval current pin interrupt status flag.
+ */
+static inline uint32_t GPIO_GetPinsInterruptFlags(GPIO_Type *base)
+{
+ return GPIO_PortGetInterruptFlags(base);
+}
+
+/*!
+ * @brief Clears pin interrupt flag. Status flags are cleared by
+ * writing a 1 to the corresponding bit position.
+ *
+ * @param base GPIO base pointer.
+ * @param mask GPIO pin number macro.
+ */
+static inline void GPIO_PortClearInterruptFlags(GPIO_Type *base, uint32_t mask)
+{
+ base->ISR = mask;
+}
+
+/*!
+ * @brief Clears pin interrupt flag. Status flags are cleared by
+ * writing a 1 to the corresponding bit position.
+ *
+ * @param base GPIO base pointer.
+ * @param mask GPIO pin number macro.
+ */
+static inline void GPIO_ClearPinsInterruptFlags(GPIO_Type *base, uint32_t mask)
+{
+ GPIO_PortClearInterruptFlags(base, mask);
+}
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_GPIO_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.c b/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.c
new file mode 100644
index 0000000000..b7b0c03d45
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2020-2021, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_key_manager.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.key_manager"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Configures Master key settings.
+ *
+ * This function configures Key Manager's setting for Master key.
+ *
+ * param base Key Manager peripheral address.
+ * param select select source for Master key.
+ * param lock setting for lock Master key.
+ * return status of Master key control operation
+ */
+status_t KEYMGR_MasterKeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock)
+{
+ if ((select != (uint8_t)(KEYMGR_SEL_UDF)) && (select != (uint8_t)(KEYMGR_SEL_PUF)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Clear KEY_CTRL_SELECT bitfield */
+ base->MASTER_KEY_CTRL &= ~KEY_MANAGER_MASTER_KEY_CTRL_SELECT_MASK;
+
+ /* Write new setting in MASTER_KEY_CTRL register */
+ base->MASTER_KEY_CTRL |= KEY_MANAGER_MASTER_KEY_CTRL_SELECT(select) | KEY_MANAGER_MASTER_KEY_CTRL_LOCK(lock);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures OTFAD1 key settings.
+ *
+ * This function configures Key Manager's setting for OTFAD1 key.
+ *
+ * param base Key Manager peripheral address.
+ * param select select source for OTFAD1 key.
+ * param lock setting for lock OTFAD1 key.
+ * return status of OTFAD1 key control operation
+ */
+status_t KEYMGR_OTFAD1KeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock)
+{
+ if ((select != (uint8_t)(KEYMGR_SEL_OCOTP)) && (select != (uint8_t)(KEYMGR_SEL_PUF)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Clear KEY_CTRL_SELECT bitfield */
+ base->OTFAD1_KEY_CTRL &= ~KEY_MANAGER_OTFAD1_KEY_CTRL_SELECT_MASK;
+
+ /* Write new setting in OTFAD1_KEY_CTRL register */
+ base->OTFAD1_KEY_CTRL |= KEY_MANAGER_OTFAD1_KEY_CTRL_SELECT(select) | KEY_MANAGER_OTFAD1_KEY_CTRL_LOCK(lock);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures OTFAD2 key settings.
+ *
+ * This function configures Key Manager's setting for OTFAD2 key.
+ *
+ * param base Key Manager peripheral address.
+ * param select select source for OTFAD2 key.
+ * param lock setting for lock OTFAD2 key.
+ * return status of OTFAD2 key control operation
+ */
+status_t KEYMGR_OTFAD2KeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock)
+{
+ if ((select != (uint8_t)(KEYMGR_SEL_OCOTP)) && (select != (uint8_t)(KEYMGR_SEL_PUF)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Clear KEY_CTRL_SELECT bitfield */
+ base->OTFAD2_KEY_CTRL &= ~KEY_MANAGER_OTFAD2_KEY_CTRL_SELECT_MASK;
+
+ /* Write new setting in OTFAD2_KEY_CTRL register */
+ base->OTFAD2_KEY_CTRL |= KEY_MANAGER_OTFAD2_KEY_CTRL_SELECT(select) | KEY_MANAGER_OTFAD2_KEY_CTRL_LOCK(lock);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Restart load key signal for IEE.
+ *
+ * This function genrates Key Manager's restart signal for IEE key.
+ *
+ * param base Key Manager peripheral address.
+ */
+void KEYMGR_IEEKeyReload(KEY_MANAGER_Type *base)
+{
+ base->IEE_KEY_CTRL |= KEYMGR_IEE_RELOAD;
+}
+
+/*!
+ * brief Lock the key select from PUF.
+ *
+ * This function locks selection of key for PUF.
+ *
+ * param base Key Manager peripheral address.
+ */
+void KEYMGR_PUFKeyLock(KEY_MANAGER_Type *base, keymgr_lock_t lock)
+{
+ base->PUF_KEY_CTRL |= KEY_MANAGER_PUF_KEY_CTRL_LOCK(lock);
+}
+
+/*!
+ * brief Sets the default configuration of Key manager slot.
+ *
+ * This function initialize Key Manager slot config structure to default values.
+ *
+ * param config Pointer to slot configuration structure.
+ */
+status_t KEYMGR_GetDefaultConfig(domain_slot_config_t *config)
+{
+ if (config == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ config->lockControl = kKEYMGR_Unlock;
+ config->allowUser = kKEYMGR_Allow;
+ config->allowNonSecure = kKEYMGR_Allow;
+ config->lockList = kKEYMGR_Unlock;
+ config->whiteList = 0u;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures Slot Domain control.
+ *
+ * This function configures domain slot control which locks and allows writes.
+ *
+ * param base Key Manager peripheral address.
+ * param config Pointer to slot configuration structure.
+ * param slot Select slot to be configured.
+ */
+status_t KEYMGR_SlotControl(KEY_MANAGER_Type *base, domain_slot_config_t *config, keymgr_slot_t slot)
+{
+ if (slot == kKEYMGR_Slot0)
+ {
+ base->SLOT0_CTRL |=
+ KEY_MANAGER_SLOT0_CTRL_WHITE_LIST(config->whiteList) | KEY_MANAGER_SLOT0_CTRL_LOCK_LIST(config->lockList) |
+ KEY_MANAGER_SLOT0_CTRL_TZ_NS(config->allowNonSecure) | KEY_MANAGER_SLOT0_CTRL_TZ_USER(config->allowUser) |
+ KEY_MANAGER_SLOT0_CTRL_LOCK_CONTROL(config->lockControl);
+ }
+ else if (slot == kKEYMGR_Slot1)
+ {
+ base->SLOT1_CTRL |=
+ KEY_MANAGER_SLOT0_CTRL_WHITE_LIST(config->whiteList) | KEY_MANAGER_SLOT0_CTRL_LOCK_LIST(config->lockList) |
+ KEY_MANAGER_SLOT0_CTRL_TZ_NS(config->allowNonSecure) | KEY_MANAGER_SLOT0_CTRL_TZ_USER(config->allowUser) |
+ KEY_MANAGER_SLOT1_CTRL_LOCK_CONTROL(config->lockControl);
+ }
+ else if (slot == kKEYMGR_Slot2)
+ {
+ base->SLOT2_CTRL |=
+ KEY_MANAGER_SLOT0_CTRL_WHITE_LIST(config->whiteList) | KEY_MANAGER_SLOT0_CTRL_LOCK_LIST(config->lockList) |
+ KEY_MANAGER_SLOT0_CTRL_TZ_NS(config->allowNonSecure) | KEY_MANAGER_SLOT0_CTRL_TZ_USER(config->allowUser) |
+ KEY_MANAGER_SLOT2_CTRL_LOCK_CONTROL(config->lockControl);
+ }
+ else if (slot == kKEYMGR_Slot3)
+ {
+ base->SLOT3_CTRL |=
+ KEY_MANAGER_SLOT0_CTRL_WHITE_LIST(config->whiteList) | KEY_MANAGER_SLOT0_CTRL_LOCK_LIST(config->lockList) |
+ KEY_MANAGER_SLOT0_CTRL_TZ_NS(config->allowNonSecure) | KEY_MANAGER_SLOT0_CTRL_TZ_USER(config->allowUser) |
+ KEY_MANAGER_SLOT3_CTRL_LOCK_CONTROL(config->lockControl);
+ }
+ else if (slot == kKEYMGR_Slot4)
+ {
+ base->SLOT4_CTRL |=
+ KEY_MANAGER_SLOT0_CTRL_WHITE_LIST(config->whiteList) | KEY_MANAGER_SLOT0_CTRL_LOCK_LIST(config->lockList) |
+ KEY_MANAGER_SLOT0_CTRL_TZ_NS(config->allowNonSecure) | KEY_MANAGER_SLOT0_CTRL_TZ_USER(config->allowUser) |
+ KEY_MANAGER_SLOT4_CTRL_LOCK_CONTROL(config->lockControl);
+ }
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Enables clock for Key Manager module.
+ *
+ * This function enables clocks for Key Manager module.
+ *
+ * param base Key Manager peripheral address.
+ */
+void KEYMGR_Init(KEY_MANAGER_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Key_Manager);
+#endif
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.h b/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.h
new file mode 100644
index 0000000000..03e3af3f46
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/key_manager/fsl_key_manager.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2020-2021, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_KEYMGR_H_
+#define _FSL_KEYMGR_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup key_manager
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Key Manager driver version. Version 2.0.2.
+ *
+ * Current version: 2.0.2
+ *
+ * Change log:
+ *
+ * - Version 2.0.2
+ * - Fix MISRA-2012 issues
+ *
+ * - Version 2.0.1
+ * - Fix MISRA-2012 issues
+ *
+ * - Version 2.0.0
+ * - Initial version
+ */
+#define FSL_KEYMGR_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+/*@}*/
+
+typedef enum _keymgr_lock
+{
+ kKEYMGR_Unlock = 0u,
+ kKEYMGR_Lock = 1u,
+} keymgr_lock_t;
+
+typedef enum _keymgr_allow
+{
+ kKEYMGR_Disallow = 0u,
+ kKEYMGR_Allow = 1u,
+} keymgr_allow_t;
+
+typedef enum _keymgr_slot
+{
+ kKEYMGR_Slot0 = 0u,
+ kKEYMGR_Slot1 = 1u,
+ kKEYMGR_Slot2 = 2u,
+ kKEYMGR_Slot3 = 3u,
+ kKEYMGR_Slot4 = 4u,
+} keymgr_slot_t;
+
+#define KEYMGR_IEE_RELOAD 1u
+#define KEYMGR_SEL_OCOTP 0u
+#define KEYMGR_SEL_UDF 0u
+#define KEYMGR_SEL_PUF 1u
+
+#define keymgr_select_t uint8_t
+
+/*! @brief Key Manager slot configuration structure. */
+typedef struct _domain_slot_config
+{
+ keymgr_lock_t lockControl; /*!< Lock control register of slot. */
+ keymgr_allow_t allowUser; /*!< Allow user write access to domain control register or domain register. */
+ keymgr_allow_t allowNonSecure; /*!< Allow non-secure write access to domain control register or domain register. */
+ keymgr_lock_t lockList; /*!< Lock whitelist. SLOTx_CTRL[WHITE_LIST] cannot be changed. */
+ uint8_t whiteList; /*!< Domains that on the Whitelist can change given slot. */
+ /*!< Each field represents one domain. Bit0~Bit3 represent DOMAIN0~DOMAIN3 respectively. */
+} domain_slot_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Configures Master key settings.
+ *
+ * This function configures Key Manager's setting for Master key.
+ *
+ * @param base Key Manager peripheral address.
+ * @param select select source for Master key.
+ * @param lock setting for lock Master key.
+ * @return status of Master key control operation
+ */
+status_t KEYMGR_MasterKeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock);
+
+/*!
+ * @brief Configures OTFAD1 key settings.
+ *
+ * This function configures Key Manager's setting for OTFAD1 key.
+ *
+ * @param base Key Manager peripheral address.
+ * @param select select source for OTFAD1 key.
+ * @param lock setting for lock OTFAD1 key.
+ * @return status of OTFAD1 key control operation
+ */
+status_t KEYMGR_OTFAD1KeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock);
+
+/*!
+ * @brief Configures OTFAD2 key settings.
+ *
+ * This function configures Key Manager's setting for OTFAD2 key.
+ *
+ * @param base Key Manager peripheral address.
+ * @param select select source for OTFAD2 key.
+ * @param lock setting for lock OTFAD2 key.
+ * @return status of OTFAD2 key control operation
+ */
+status_t KEYMGR_OTFAD2KeyControll(KEY_MANAGER_Type *base, keymgr_select_t select, keymgr_lock_t lock);
+
+/*!
+ * @brief Restart load key signal for IEE.
+ *
+ * This function genrates Key Manager's restart signal for IEE key.
+ *
+ * @param base Key Manager peripheral address.
+ */
+void KEYMGR_IEEKeyReload(KEY_MANAGER_Type *base);
+
+/*!
+ * @brief Lock the key select from PUF.
+ *
+ * This function locks selection of key for PUF.
+ *
+ * @param base Key Manager peripheral address.
+ * @param lock Setting for selection of key for PUF.
+ */
+void KEYMGR_PUFKeyLock(KEY_MANAGER_Type *base, keymgr_lock_t lock);
+
+/*!
+ * @brief Configures Slot Domain control.
+ *
+ * This function configures domain slot control which locks and allows writes.
+ *
+ * @param base Key Manager peripheral address.
+ * @param config Pointer to slot configuration structure.
+ * @param slot Select slot to be configured.
+ * @return status of slot control operation
+ */
+status_t KEYMGR_SlotControl(KEY_MANAGER_Type *base, domain_slot_config_t *config, keymgr_slot_t slot);
+
+/*!
+ * @brief Resets Key Manager module to factory default values.
+ *
+ * This function performs hardware reset of Key Manager module.
+ *
+ * @param base Key Manager peripheral address.
+ */
+void KEYMGR_Init(KEY_MANAGER_Type *base);
+
+/*!
+ * @brief Sets the default configuration of Key manager slot.
+ *
+ * This function initialize Key Manager slot config structure to default values.
+ *
+ * @param config Pointer to slot configuration structure.
+ */
+status_t KEYMGR_GetDefaultConfig(domain_slot_config_t *config);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ *@}
+ */
+
+#endif /* _FSL_IEE_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c
new file mode 100644
index 0000000000..8c0b1958be
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_kpp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.kpp"
+#endif
+
+#define KPP_KEYPAD_SCAN_TIMES (3U)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * 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_kppClock[FSL_FEATURE_SOC_KPP_COUNT] = KPP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to SEMC bases for each instance. */
+static KPP_Type *const s_kppBases[] = KPP_BASE_PTRS;
+
+/*! @brief Pointers to KPP IRQ number for each instance. */
+static const IRQn_Type s_kppIrqs[] = KPP_IRQS;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t KPP_GetInstance(KPP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_kppBases); instance++)
+ {
+ if (s_kppBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_kppBases));
+
+ return instance;
+}
+static void KPP_Mdelay(uint64_t tickets)
+{
+ while ((tickets--) != 0UL)
+ {
+ __NOP();
+ }
+}
+
+/*!
+ * brief KPP initialize.
+ * This function ungates the KPP clock and initializes KPP.
+ * This function must be called before calling any other KPP driver functions.
+ *
+ * param base KPP peripheral base address.
+ * param configure The KPP configuration structure pointer.
+ */
+void KPP_Init(KPP_Type *base, kpp_config_t *configure)
+{
+ assert(configure);
+
+ uint32_t instance = KPP_GetInstance(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Un-gate sdram controller clock. */
+ CLOCK_EnableClock(s_kppClock[KPP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Clear all. */
+ base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
+
+ /* Enable the keypad row and set the column strobe output to open drain. */
+ base->KPCR = KPP_KPCR_KRE(configure->activeRow);
+ base->KPDR = KPP_KPDR_KCD((uint8_t) ~(configure->activeColumn));
+ base->KPCR |= KPP_KPCR_KCO(configure->activeColumn);
+
+ /* Set the input direction for row and output direction for column. */
+ base->KDDR = KPP_KDDR_KCDD(configure->activeColumn) | KPP_KDDR_KRDD((uint8_t) ~(configure->activeRow));
+
+ /* Clear the status flag and enable the interrupt. */
+ base->KPSR = KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK | KPP_KPSR_KDSC_MASK | configure->interrupt;
+
+ if ((configure->interrupt) != 0U)
+ {
+ /* Enable at the Interrupt */
+ (void)EnableIRQ(s_kppIrqs[instance]);
+ }
+}
+
+/*!
+ * brief Deinitializes the KPP module and gates the clock.
+ * This function gates the KPP clock. As a result, the KPP
+ * module doesn't work after calling this function.
+ *
+ * param base KPP peripheral base address.
+ */
+void KPP_Deinit(KPP_Type *base)
+{
+ /* Disable interrupts and disable all rows. */
+ base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
+ base->KPCR = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable KPP clock. */
+ CLOCK_DisableClock(s_kppClock[KPP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Keypad press scanning.
+ *
+ * This function will scanning all columns and rows. so
+ * all scanning data will be stored in the data pointer.
+ *
+ * param base KPP peripheral base address.
+ * param data KPP key press scanning data. The data buffer should be prepared with
+ * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX.
+ * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX].
+ * for example the data[2] = 4, that means in column 1 row 2 has a key press event.
+ * param clockSrc_Hz Source clock.
+ */
+void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz)
+{
+ assert(data);
+
+ uint16_t kppKCO = base->KPCR & KPP_KPCR_KCO_MASK;
+ uint8_t columIndex = 0;
+ uint8_t activeColumn = (uint8_t)((base->KPCR & KPP_KPCR_KCO_MASK) >> KPP_KPCR_KCO_SHIFT);
+ uint8_t times;
+ uint8_t rowData[KPP_KEYPAD_SCAN_TIMES][KPP_KEYPAD_COLUMNNUM_MAX];
+ bool press = false;
+ uint8_t column;
+
+ /* Initialize row data to zero. */
+ (void)memset(&rowData[0][0], 0, sizeof(rowData));
+
+ /* Scanning. */
+ /* Configure the column data to 1 according to column numbers. */
+ base->KPDR = KPP_KPDR_KCD_MASK;
+ /* Configure column to totem pole for quick discharge of keypad capacitance. */
+ base->KPCR &= (uint16_t)(((uint16_t)~kppKCO) | KPP_KPCR_KRE_MASK);
+ /* Recover. */
+ base->KPCR |= kppKCO;
+ /* Three times scanning. */
+ for (times = 0; times < KPP_KEYPAD_SCAN_TIMES; times++)
+ {
+ for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
+ {
+ column = activeColumn & (1U << columIndex);
+ if (column != 0U)
+ {
+ /* Set the single column line to 0. */
+ base->KPDR = KPP_KPDR_KCD(~(uint16_t)column);
+ /* Take 100us delays. */
+ KPP_Mdelay(((uint64_t)clockSrc_Hz / 10000000UL));
+ /* Read row data. */
+ rowData[times][columIndex] = (uint8_t)(~(base->KPDR & KPP_KPDR_KRD_MASK));
+ }
+ else
+ {
+ /* Read row data. */
+ rowData[times][columIndex] = 0;
+ }
+ }
+ }
+
+ /* Return all columns to 0 in preparation for standby mode. */
+ base->KPDR &= (uint16_t)(~KPP_KPDR_KCD_MASK);
+
+ /* Check if three time scan data is the same. */
+ for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
+ {
+ if (((uint8_t)(rowData[0][columIndex] & rowData[1][columIndex]) & rowData[2][columIndex]) != 0U)
+ {
+ press = true;
+ }
+ }
+
+ if (press)
+ {
+ (void)memcpy(data, &rowData[0][0], sizeof(rowData[0]));
+ }
+ else
+ {
+ (void)memset(data, 0, sizeof(rowData[0]));
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h
new file mode 100644
index 0000000000..dc65aaf8d7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_KPP_H_
+#define _FSL_KPP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup kpp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief KPP driver version 2.0.0. */
+#define FSL_KPP_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+/*@}*/
+
+#define KPP_KEYPAD_COLUMNNUM_MAX (8U)
+#define KPP_KEYPAD_ROWNUM_MAX (8U)
+
+/*! @brief List of interrupts supported by the peripheral. This
+ * enumeration uses one-bot encoding to allow a logical OR of multiple
+ * members. Members usually map to interrupt enable bits in one or more
+ * peripheral registers.
+ */
+typedef enum _kpp_interrupt_enable
+{
+ kKPP_keyDepressInterrupt = KPP_KPSR_KDIE_MASK, /*!< Keypad depress interrupt source */
+ kKPP_keyReleaseInterrupt = KPP_KPSR_KRIE_MASK /*!< Keypad release interrupt source */
+} kpp_interrupt_enable_t;
+
+/*! @brief Lists of KPP synchronize chain operation. */
+typedef enum _kpp_sync_operation
+{
+ kKPP_ClearKeyDepressSyncChain = KPP_KPSR_KDSC_MASK, /*!< Keypad depress interrupt status. */
+ kKPP_SetKeyReleasesSyncChain = KPP_KPSR_KRSS_MASK, /*!< Keypad release interrupt status. */
+} kpp_sync_operation_t;
+
+/*! @brief Lists of KPP status. */
+typedef struct _kpp_config
+{
+ uint8_t activeRow; /*!< The row number: bit 7 ~ 0 represents the row 7 ~ 0. */
+ uint8_t activeColumn; /*!< The column number: bit 7 ~ 0 represents the column 7 ~ 0. */
+ uint16_t interrupt; /*!< KPP interrupt source. A logical OR of "kpp_interrupt_enable_t". */
+} kpp_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and De-initialization
+ * @{
+ */
+
+/*!
+ * @brief KPP initialize.
+ * This function ungates the KPP clock and initializes KPP.
+ * This function must be called before calling any other KPP driver functions.
+ *
+ * @param base KPP peripheral base address.
+ * @param configure The KPP configuration structure pointer.
+ */
+void KPP_Init(KPP_Type *base, kpp_config_t *configure);
+
+/*!
+ * @brief Deinitializes the KPP module and gates the clock.
+ * This function gates the KPP clock. As a result, the KPP
+ * module doesn't work after calling this function.
+ *
+ * @param base KPP peripheral base address.
+ */
+void KPP_Deinit(KPP_Type *base);
+
+/* @} */
+
+/*!
+ * @name KPP Basic Operation
+ * @{
+ */
+
+/*!
+ * @brief Enable the interrupt.
+ *
+ * @param base KPP peripheral base address.
+ * @param mask KPP interrupts to enable. This is a logical OR of the
+ * enumeration :: kpp_interrupt_enable_t.
+ */
+static inline void KPP_EnableInterrupts(KPP_Type *base, uint16_t mask)
+{
+ uint16_t data = (uint16_t)(base->KPSR & ~(KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK));
+ base->KPSR = data | mask;
+}
+
+/*!
+ * @brief Disable the interrupt.
+ *
+ * @param base KPP peripheral base address.
+ * @param mask KPP interrupts to disable. This is a logical OR of the
+ * enumeration :: kpp_interrupt_enable_t.
+ */
+static inline void KPP_DisableInterrupts(KPP_Type *base, uint16_t mask)
+{
+ base->KPSR &= ~(mask | KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK);
+}
+
+/*!
+ * @brief Gets the KPP interrupt event status.
+ *
+ * @param base KPP peripheral base address.
+ * @return The status of the KPP. Application can use the enum type in the "kpp_interrupt_enable_t"
+ * to get the right status of the related event.
+ */
+static inline uint16_t KPP_GetStatusFlag(KPP_Type *base)
+{
+ return (base->KPSR & (KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK)) << KPP_KPSR_KDIE_SHIFT;
+}
+
+/*!
+ * @brief Clears KPP status flag.
+ *
+ * @param base KPP peripheral base address.
+ * @param mask KPP mask to be cleared. This is a logical OR of the
+ * enumeration :: kpp_interrupt_enable_t.
+ */
+static inline void KPP_ClearStatusFlag(KPP_Type *base, uint16_t mask)
+{
+ base->KPSR |= (uint16_t)((mask) >> KPP_KPSR_KDIE_SHIFT);
+}
+
+/*!
+ * @brief Set KPP synchronization chain.
+ *
+ * @param base KPP peripheral base address.
+ * @param mask KPP mask to be cleared. This is a logical OR of the
+ * enumeration :: kpp_sync_operation_t.
+ */
+static inline void KPP_SetSynchronizeChain(KPP_Type *base, uint16_t mask)
+{
+ uint16_t data = base->KPSR & (KPP_KPSR_KRSS_MASK | KPP_KPSR_KDSC_MASK | KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK);
+ base->KPSR = data | mask;
+}
+
+/*!
+ * @brief Keypad press scanning.
+ *
+ * This function will scanning all columns and rows. so
+ * all scanning data will be stored in the data pointer.
+ *
+ * @param base KPP peripheral base address.
+ * @param data KPP key press scanning data. The data buffer should be prepared with
+ * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX.
+ * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX].
+ * for example the data[2] = 4, that means in column 1 row 2 has a key press event.
+ * @param clockSrc_Hz Source clock.
+ */
+void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_KPP_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c
new file mode 100644
index 0000000000..356a4625b0
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2019-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lcdifv2.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lcdifv2"
+#endif
+
+#define LCDIFV2_LUT_MEM(base) \
+ ((volatile uint32_t *)(((uint32_t)(base)) + (uint32_t)FSL_FEATURE_LCDIFV2_CLUT_RAM_OFFSET))
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for LCDIF module.
+ *
+ * @param base LCDIF peripheral base address
+ */
+static uint32_t LCDIFV2_GetInstance(const LCDIFV2_Type *base);
+
+/*!
+ * @brief Reset register value to default status.
+ *
+ * @param base LCDIF peripheral base address
+ */
+static void LCDIFV2_ResetRegister(LCDIFV2_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to LCDIF clock for each instance. */
+static const clock_ip_name_t s_lcdifv2Clocks[] = LCDIFV2_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t LCDIFV2_GetInstance(const LCDIFV2_Type *base)
+{
+ static LCDIFV2_Type *const s_lcdifv2Bases[] = LCDIFV2_BASE_PTRS;
+
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lcdifv2Bases); instance++)
+ {
+ if (s_lcdifv2Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lcdifv2Bases));
+
+ return instance;
+}
+
+static void LCDIFV2_ResetRegister(LCDIFV2_Type *base)
+{
+ uint32_t i;
+
+ base->DISP_PARA = 0U;
+ base->CTRL = 0x80000000U;
+ base->DISP_SIZE = 0U;
+ base->HSYN_PARA = 0x00C01803U;
+ base->VSYN_PARA = 0x00C01803U;
+ base->INT[0].INT_ENABLE = 0U;
+ base->INT[1].INT_ENABLE = 0U;
+ base->PDI_PARA = 0x00001000U;
+
+ for (i = 0; i < (uint32_t)LCDIFV2_LAYER_COUNT; i++)
+ {
+ base->LAYER[i].CTRLDESCL5 = 0U;
+ base->LAYER[i].CTRLDESCL1 = 0U;
+ base->LAYER[i].CTRLDESCL2 = 0U;
+ base->LAYER[i].CTRLDESCL3 = 0U;
+ base->LAYER[i].CTRLDESCL4 = 0U;
+ base->LAYER[i].CTRLDESCL6 = 0U;
+ }
+
+ for (i = 0; i < (uint32_t)LCDIFV2_LAYER_CSC_COUNT; i++)
+ {
+ base->LAYER[i].CSC_COEF0 = 0x04000000U;
+ base->LAYER[i].CSC_COEF1 = 0x01230208U;
+ base->LAYER[i].CSC_COEF2 = 0x076B079CU;
+ }
+
+ /* Clear interrupt status. */
+ base->INT[0].INT_STATUS = 0xFFFFFFFFU;
+ base->INT[1].INT_STATUS = 0xFFFFFFFFU;
+}
+
+/*!
+ * brief Initializes the LCDIF v2.
+ *
+ * This function ungates the LCDIF v2 clock and release the peripheral reset.
+ *
+ * param base LCDIF v2 peripheral base address.
+ */
+void LCDIFV2_Init(LCDIFV2_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = LCDIFV2_GetInstance(base);
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_lcdifv2Clocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ LCDIFV2_ResetRegister(base);
+
+ /* Out of reset. */
+ base->CTRL = 0U;
+}
+
+/*!
+ * brief Deinitializes the LCDIF peripheral.
+ *
+ * param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Deinit(LCDIFV2_Type *base)
+{
+ LCDIFV2_ResetRegister(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = LCDIFV2_GetInstance(base);
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_lcdifv2Clocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Reset the LCDIF v2.
+ *
+ * param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Reset(LCDIFV2_Type *base)
+{
+ LCDIFV2_ResetRegister(base);
+
+ /* Release and ready to work. */
+ base->CTRL = 0U;
+}
+
+/*!
+ * brief Gets the LCDIF display default configuration structure.
+ *
+ * param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_DisplayGetDefaultConfig(lcdifv2_display_config_t *config)
+{
+ assert(NULL != config);
+
+ config->panelWidth = 0U;
+ config->panelHeight = 0U;
+ config->hsw = 3U;
+ config->hfp = 3U;
+ config->hbp = 3U;
+ config->vsw = 3U;
+ config->vfp = 3U;
+ config->vbp = 3U;
+ config->polarityFlags = (uint32_t)kLCDIFV2_VsyncActiveHigh | (uint32_t)kLCDIFV2_HsyncActiveHigh |
+ (uint32_t)kLCDIFV2_DataEnableActiveHigh | (uint32_t)kLCDIFV2_DriveDataOnRisingClkEdge |
+ (uint32_t)kLCDIFV2_DataActiveHigh;
+ config->lineOrder = kLCDIFV2_LineOrderRGB;
+}
+
+/*!
+ * brief Set the LCDIF v2 display configurations.
+ *
+ * param base LCDIF peripheral base address.
+ * param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_SetDisplayConfig(LCDIFV2_Type *base, const lcdifv2_display_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Configure the parameters. */
+ base->DISP_SIZE = ((uint32_t)config->panelWidth << LCDIFV2_DISP_SIZE_DELTA_X_SHIFT) |
+ ((uint32_t)config->panelHeight << LCDIFV2_DISP_SIZE_DELTA_Y_SHIFT);
+
+ base->HSYN_PARA = ((uint32_t)config->hsw << LCDIFV2_HSYN_PARA_PW_H_SHIFT) |
+ ((uint32_t)config->hbp << LCDIFV2_HSYN_PARA_BP_H_SHIFT) |
+ ((uint32_t)config->hfp << LCDIFV2_HSYN_PARA_FP_H_SHIFT);
+
+ base->VSYN_PARA = ((uint32_t)config->vsw << LCDIFV2_VSYN_PARA_PW_V_SHIFT) |
+ ((uint32_t)config->vbp << LCDIFV2_VSYN_PARA_BP_V_SHIFT) |
+ ((uint32_t)config->vfp << LCDIFV2_VSYN_PARA_FP_V_SHIFT);
+
+ base->DISP_PARA = LCDIFV2_DISP_PARA_LINE_PATTERN((uint32_t)config->lineOrder);
+
+ base->CTRL = (uint32_t)(config->polarityFlags);
+}
+
+/*!
+ * brief Set the color space conversion mode.
+ *
+ * Supports YUV2RGB and YCbCr2RGB.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Index of the layer.
+ * param mode The conversion mode.
+ */
+void LCDIFV2_SetCscMode(LCDIFV2_Type *base, uint8_t layerIndex, lcdifv2_csc_mode_t mode)
+{
+ assert(layerIndex < (uint32_t)LCDIFV2_LAYER_CSC_COUNT);
+
+ /*
+ * The equations used for Colorspace conversion are:
+ *
+ * R = C0*(Y+Y_OFFSET) + C1(V+UV_OFFSET)
+ * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
+ * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
+ */
+
+ if (kLCDIFV2_CscYUV2RGB == mode)
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_C0(0x100U) /* 1.00. */
+ | LCDIFV2_CSC_COEF0_Y_OFFSET(0x0U) /* 0. */
+ | LCDIFV2_CSC_COEF0_UV_OFFSET(0x0U); /* 0. */
+
+ base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0123U) /* 1.140. */
+ | LCDIFV2_CSC_COEF1_C4(0x0208U); /* 2.032. */
+ base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x076BU) /* -0.851. */
+ | LCDIFV2_CSC_COEF2_C3(0x079BU); /* -0.394. */
+ }
+ else if (kLCDIFV2_CscYCbCr2RGB == mode)
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_YCBCR_MODE_MASK |
+ LCDIFV2_CSC_COEF0_C0(0x12AU) /* 1.164. */
+ | LCDIFV2_CSC_COEF0_Y_OFFSET(0x1F0U) /* -16. */
+ | LCDIFV2_CSC_COEF0_UV_OFFSET(0x180U); /* -128. */
+ base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0198U) /* 1.596. */
+ | LCDIFV2_CSC_COEF1_C4(0x0204U); /* 2.017. */
+ base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x0730U) /* -0.813. */
+ | LCDIFV2_CSC_COEF2_C3(0x079CU); /* -0.392. */
+ }
+ else
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = 0U;
+ base->LAYER[layerIndex].CSC_COEF1 = 0U;
+ base->LAYER[layerIndex].CSC_COEF2 = 0U;
+ }
+}
+
+/*!
+ * brief Set the layer source buffer configuration.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Layer layerIndex.
+ * param config Pointer to the configuration.
+ */
+void LCDIFV2_SetLayerBufferConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_buffer_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ base->LAYER[layerIndex].CTRLDESCL3 = config->strideBytes;
+
+ reg = base->LAYER[layerIndex].CTRLDESCL5;
+ reg = (reg & ~(LCDIFV2_CTRLDESCL5_BPP_MASK | LCDIFV2_CTRLDESCL5_YUV_FORMAT_MASK)) | (uint32_t)config->pixelFormat;
+
+ if (0U == (reg & LCDIFV2_CTRLDESCL5_AB_MODE_MASK))
+ {
+ reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
+ }
+
+ base->LAYER[layerIndex].CTRLDESCL5 = reg;
+}
+
+/*!
+ * brief Set the LUT data.
+ *
+ * This function sets the specific layer LUT data, if useShadowLoad is true,
+ * call LCDIFV2_TriggerLayerShadowLoad after this function, the
+ * LUT will be loaded to the hardware during next vertical blanking period.
+ * If useShadowLoad is false, the LUT data is loaded to hardware directly.
+ *
+ * param base LCDIF v2 peripheral base address.
+ * param layerIndex Which layer to set.
+ * param lutData The LUT data to load.
+ * param count Count of lutData.
+ * retval kStatus_Success Set success.
+ * retval kStatus_Fail Previous LUT data is not loaded to hardware yet.
+ */
+status_t LCDIFV2_SetLut(
+ LCDIFV2_Type *base, uint8_t layerIndex, const uint32_t *lutData, uint16_t count, bool useShadowLoad)
+{
+ assert(count <= LCDIFV2_LUT_ENTRY_NUM);
+
+ uint16_t i;
+ status_t status;
+
+ /* Previous setting is not updated. */
+ if ((base->CLUT_LOAD & LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK) != 0U)
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ if (useShadowLoad)
+ {
+ base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex) | LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK;
+ }
+ else
+ {
+ base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex);
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ (LCDIFV2_LUT_MEM(base))[i + (LCDIFV2_LUT_ENTRY_NUM * layerIndex)] = lutData[i];
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set the layer alpha blend mode.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Index of the CSC unit.
+ * param config Pointer to the blend configuration.
+ */
+void LCDIFV2_SetLayerBlendConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_blend_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t reg;
+
+ reg = base->LAYER[layerIndex].CTRLDESCL5;
+ reg &= ~(LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA_MASK | LCDIFV2_CTRLDESCL5_AB_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_PD_COLOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK);
+
+ reg |=
+ (LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA(config->globalAlpha) | LCDIFV2_CTRLDESCL5_AB_MODE(config->alphaMode) |
+ LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE(config->pdFactorMode) |
+ LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE(config->pdAlphaMode) | LCDIFV2_CTRLDESCL5_PD_COLOR_MODE(config->pdColorMode) |
+ LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE(config->pdGlobalAlphaMode));
+
+ if (config->alphaMode == kLCDIFV2_AlphaDisable)
+ {
+ reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
+ }
+
+ base->LAYER[layerIndex].CTRLDESCL5 = reg;
+}
+
+/*
+ * brief Get the blend configuration for Porter Duff blend.
+ *
+ * This is the basic Porter Duff blend configuration, user still could
+ * modify the configurations after this function.
+ *
+ * param mode Porter Duff blend mode.
+ * param layer The configuration for source layer or destination layer.
+ * param config Pointer to the configuration.
+ * retval kStatus_Success Get the configuration successfully.
+ * retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetPorterDuffConfig(lcdifv2_pd_blend_mode_t mode,
+ lcdifv2_pd_layer_t layer,
+ lcdifv2_blend_config_t *config)
+{
+ static const lcdifv2_pd_factor_mode_t s_lcdifv2PdLayerFactors[][2] = {
+ /* kLCDIFV2_PD_Src */
+ {
+ /* s1_s0_factor_mode. */
+ kLCDIFV2_PD_FactorZero,
+
+ /* s0_s1_factor_mode. */
+ kLCDIFV2_PD_FactorOne,
+ },
+
+ /* kLCDIFV2_PD_Atop */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorStraightAlpha},
+
+ /* kLCDIFV2_PD_Over */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorOne},
+
+ /* kLCDIFV2_PD_In */
+ {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorStraightAlpha},
+
+ /* kLCDIFV2_PD_Out */
+ {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_Dst */
+ {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_DstAtop */
+ {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_DstOver */
+ {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_DstIn */
+ {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_DstOut */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_Xor */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_Clear */
+ {
+ kLCDIFV2_PD_FactorZero,
+ kLCDIFV2_PD_FactorZero,
+ },
+ };
+
+ status_t status;
+
+ if ((NULL == config) || (mode >= kLCDIFV2_PD_Max) || (layer >= kLCDIFV2_PD_LayerMax))
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ config->pdAlphaMode = kLCDIFV2_PD_AlphaStraight;
+ config->pdColorMode = kLCDIFV2_PD_ColorWithAlpha;
+ config->pdGlobalAlphaMode = kLCDIFV2_PD_LocalAlpha;
+ config->pdFactorMode = s_lcdifv2PdLayerFactors[mode][(uint8_t)layer];
+ config->alphaMode = kLCDIFV2_AlphaPoterDuff;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*
+ * brief Get the global alpha values for multiple layer blend.
+ *
+ * When all layers use the global alpha, the relationship blended alpha
+ * and global alpha of each layer is:
+ *
+ * Layer 7: ba7 = ga7
+ * Layer 6: ba6 = ga6 * (1-ga7)
+ * Layer 5: ba5 = ga5 * (1-ga6) * (1-ga7)
+ * Layer 4: ba4 = ga4 * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 3: ba3 = ga3 * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 2: ba2 = ga2 * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 1: ba1 = ga1 * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 0: ba0 = 1 * (1-ga1) * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ *
+ * Here baN is the blended alpha of layer N, gaN is the global alpha configured to layer N.
+ *
+ * This function calculates the global alpha based on the blended alpha. The blendedAlpha and
+ * globalAlpha are all arrays of size layerCount. The first layer is a background layer,
+ * so blendedAlpha[0] is useless, globalAlpha[0] is always 255.
+ *
+ * param blendedAlpha The desired blended alpha value, alpha range 0~255.
+ * param globalAlpha Calculated global alpha set to each layer register.
+ * param layerCount Total layer count.
+ * retval kStatus_Success Get successfully.
+ * retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetMultiLayerGlobalAlpha(const uint8_t blendedAlpha[], uint8_t globalAlpha[], uint8_t layerCount)
+{
+ status_t status = kStatus_Success;
+ int16_t curLayer = (int16_t)layerCount - 1;
+ int left = 255;
+ int tmpAlpha;
+
+ assert((layerCount > 1U) && (layerCount <= (uint8_t)LCDIFV2_LAYER_COUNT));
+
+ /*
+ * Assume the layer counter is 7, and alpha range is 0~1, define:
+ *
+ * left_7 = 1
+ * left_i = (1-ga_(i+1)) * ... * (1-ga7)
+ *
+ * Then:
+ * ba_i = ga_i * left_i
+ * left_i = left_(i+1) - ba_i
+ * ga_i = ba_i / left_i
+ *
+ * Now change alpha range to 0~255, then:
+ *
+ * ga_i = ba_i * 255 / left_i
+ * left_i = left_(i+1) - ba_i
+ */
+
+ globalAlpha[0] = 255U;
+
+ while (curLayer > 0)
+ {
+ tmpAlpha = (int)blendedAlpha[curLayer] * 255 / left;
+ if (tmpAlpha > 255)
+ {
+ status = kStatus_InvalidArgument;
+ break;
+ }
+
+ globalAlpha[curLayer] = (uint8_t)tmpAlpha;
+ left -= (int)blendedAlpha[curLayer];
+
+ if (left <= 0)
+ {
+ status = kStatus_InvalidArgument;
+ break;
+ }
+
+ curLayer--;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.h b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.h
new file mode 100644
index 0000000000..41a5d90ac6
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.h
@@ -0,0 +1,655 @@
+/*
+ * Copyright 2019-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_LCDIFV2_H_
+#define _FSL_LCDIFV2_H_
+
+#include "fsl_common.h"
+
+#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && (0 != FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET))
+#include "fsl_memory.h"
+#endif
+
+/*!
+ * @addtogroup lcdifv2
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LCDIF v2 driver version */
+#define FSL_LCDIFV2_DRIVER_VERSION (MAKE_VERSION(2, 3, 2))
+/*@}*/
+
+#if defined(FSL_FEATURE_LCDIFV2_LAYER_COUNT) && (!defined(LCDIFV2_LAYER_COUNT))
+#define LCDIFV2_LAYER_COUNT FSL_FEATURE_LCDIFV2_LAYER_COUNT
+#endif
+
+#if defined(FSL_FEATURE_LCDIFV2_LAYER_CSC_COUNT) && (!defined(LCDIFV2_LAYER_CSC_COUNT))
+#define LCDIFV2_LAYER_CSC_COUNT FSL_FEATURE_LCDIFV2_LAYER_CSC_COUNT
+#endif
+
+#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && (0 != FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET))
+#define LCDIFV2_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
+#else
+#define LCDIFV2_ADDR_CPU_2_IP(addr) (addr)
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+/*! @brief LCDIF v2 FIFO empty interrupt. */
+#define LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(layer) (1UL << ((uint32_t)(layer) + 24U))
+/*! @brief LCDIF v2 DMA done interrupt. */
+#define LCDIFV2_MAKE_DMA_DONE_INTERRUPT(layer) (1UL << ((uint32_t)(layer) + 16U))
+/*! @brief LCDIF v2 DMA error interrupt. */
+#define LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(layer) (1UL << ((uint32_t)(layer) + 8U))
+
+/* LUT memory entery number. */
+#define LCDIFV2_LUT_ENTRY_NUM 256U
+
+/*!
+ * @brief LCDIF v2 signal polarity flags
+ */
+enum _lcdifv2_polarity_flags
+{
+ kLCDIFV2_VsyncActiveHigh = 0U, /*!< VSYNC active high. */
+ kLCDIFV2_HsyncActiveHigh = 0U, /*!< HSYNC active high. */
+ kLCDIFV2_DataEnableActiveHigh = 0U, /*!< Data enable line active high. */
+ kLCDIFV2_DriveDataOnRisingClkEdge = 0U, /*!< Output data on rising clock edge, capture data
+ on falling clock edge. */
+ kLCDIFV2_DataActiveHigh = 0U, /*!< Data active high. */
+
+ kLCDIFV2_VsyncActiveLow = LCDIFV2_CTRL_INV_VS_MASK, /*!< VSYNC active low. */
+ kLCDIFV2_HsyncActiveLow = LCDIFV2_CTRL_INV_HS_MASK, /*!< HSYNC active low. */
+ kLCDIFV2_DataEnableActiveLow = LCDIFV2_CTRL_INV_DE_MASK, /*!< Data enable line active low. */
+ kLCDIFV2_DriveDataOnFallingClkEdge = LCDIFV2_CTRL_INV_PXCK_MASK, /*!< Output data on falling clock edge, capture
+ data on rising clock edge. */
+ kLCDIFV2_DataActiveLow = LCDIFV2_CTRL_NEG_MASK, /*!< Data active high. */
+};
+
+/*!
+ * @brief The LCDIF v2 interrupts.
+ */
+enum _lcdifv2_interrupt
+{
+ kLCDIFV2_Layer0FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(0), /*!< Layer 0 FIFO empty. */
+ kLCDIFV2_Layer1FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(1), /*!< Layer 1 FIFO empty. */
+ kLCDIFV2_Layer2FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(2), /*!< Layer 2 FIFO empty. */
+ kLCDIFV2_Layer3FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(3), /*!< Layer 3 FIFO empty. */
+ kLCDIFV2_Layer4FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(4), /*!< Layer 4 FIFO empty. */
+ kLCDIFV2_Layer5FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(5), /*!< Layer 5 FIFO empty. */
+ kLCDIFV2_Layer6FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(6), /*!< Layer 6 FIFO empty. */
+ kLCDIFV2_Layer7FifoEmptyInterrupt = LCDIFV2_MAKE_FIFO_EMPTY_INTERRUPT(7), /*!< Layer 7 FIFO empty. */
+ kLCDIFV2_Layer0DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(0), /*!< Layer 0 DMA done. */
+ kLCDIFV2_Layer1DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(1), /*!< Layer 1 DMA done. */
+ kLCDIFV2_Layer2DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(2), /*!< Layer 2 DMA done. */
+ kLCDIFV2_Layer3DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(3), /*!< Layer 3 DMA done. */
+ kLCDIFV2_Layer4DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(4), /*!< Layer 4 DMA done. */
+ kLCDIFV2_Layer5DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(5), /*!< Layer 5 DMA done. */
+ kLCDIFV2_Layer6DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(6), /*!< Layer 6 DMA done. */
+ kLCDIFV2_Layer7DmaDoneInterrupt = LCDIFV2_MAKE_DMA_DONE_INTERRUPT(7), /*!< Layer 7 DMA done. */
+ kLCDIFV2_Layer0DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(0), /*!< Layer 0 DMA error. */
+ kLCDIFV2_Layer1DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(1), /*!< Layer 1 DMA error. */
+ kLCDIFV2_Layer2DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(2), /*!< Layer 2 DMA error. */
+ kLCDIFV2_Layer3DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(3), /*!< Layer 3 DMA error. */
+ kLCDIFV2_Layer4DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(4), /*!< Layer 4 DMA error. */
+ kLCDIFV2_Layer5DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(5), /*!< Layer 5 DMA error. */
+ kLCDIFV2_Layer6DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(6), /*!< Layer 6 DMA error. */
+ kLCDIFV2_Layer7DmaErrorInterrupt = LCDIFV2_MAKE_DMA_ERROR_INTERRUPT(7), /*!< Layer 7 DMA error. */
+ kLCDIFV2_VerticalBlankingInterrupt = (1U << 2U), /*!< Start of vertical blanking period. */
+ kLCDIFV2_OutputUnderrunInterrupt = (1U << 1U), /*!< Output buffer underrun. */
+ kLCDIFV2_VsyncEdgeInterrupt = (1U << 0U), /*!< Interrupt at VSYNC edge. */
+};
+
+/*! @brief The LCDIF v2 output line order. */
+typedef enum _lcdifv2_line_order
+{
+ kLCDIFV2_LineOrderRGB = 0, /*!< RGB */
+ kLCDIFV2_LineOrderRBG, /*!< RBG */
+ kLCDIFV2_LineOrderGBR, /*!< GBR */
+ kLCDIFV2_LineOrderGRB, /*!< GRB */
+ kLCDIFV2_LineOrderBRG, /*!< BRG */
+ kLCDIFV2_LineOrderBGR, /*!< BGR */
+} lcdifv2_line_order_t;
+
+/*!
+ * @brief LCDIF v2 display configure structure.
+ */
+typedef struct _lcdifv2_display_config
+{
+ uint16_t panelWidth; /*!< Display panel width, pixels per line. */
+ uint16_t panelHeight; /*!< Display panel height, how many lines per panel. */
+ uint8_t hsw; /*!< HSYNC pulse width. */
+ uint8_t hfp; /*!< Horizontal front porch. */
+ uint8_t hbp; /*!< Horizontal back porch. */
+ uint8_t vsw; /*!< VSYNC pulse width. */
+ uint8_t vfp; /*!< Vrtical front porch. */
+ uint8_t vbp; /*!< Vertical back porch. */
+ uint32_t polarityFlags; /*!< OR'ed value of @ref _lcdifv2_polarity_flags, used to contol the signal polarity. */
+ lcdifv2_line_order_t lineOrder; /*!< Line order. */
+} lcdifv2_display_config_t;
+
+/*! @brief LCDIF v2 color space conversion mode. */
+typedef enum _lcdifv2_csc_mode
+{
+ kLCDIFV2_CscDisable = 0U, /*!< Disable the CSC. */
+ kLCDIFV2_CscYUV2RGB, /*!< YUV to RGB. */
+ kLCDIFV2_CscYCbCr2RGB, /*!< YCbCr to RGB. */
+} lcdifv2_csc_mode_t;
+
+/*! @brief LCDIF v2 pixel format. */
+typedef enum _lcdifv2_pixel_format
+{
+ kLCDIFV2_PixelFormatIndex1BPP = LCDIFV2_CTRLDESCL5_BPP(0U), /*!< LUT index 1 bit. */
+ kLCDIFV2_PixelFormatIndex2BPP = LCDIFV2_CTRLDESCL5_BPP(1U), /*!< LUT index 2 bit. */
+ kLCDIFV2_PixelFormatIndex4BPP = LCDIFV2_CTRLDESCL5_BPP(2U), /*!< LUT index 4 bit. */
+ kLCDIFV2_PixelFormatIndex8BPP = LCDIFV2_CTRLDESCL5_BPP(3U), /*!< LUT index 8 bit. */
+ kLCDIFV2_PixelFormatRGB565 = LCDIFV2_CTRLDESCL5_BPP(4U), /*!< RGB565, two pixels use 32 bits. */
+ kLCDIFV2_PixelFormatARGB1555 = LCDIFV2_CTRLDESCL5_BPP(5U), /*!< ARGB1555, two pixels use 32 bits. */
+ kLCDIFV2_PixelFormatARGB4444 = LCDIFV2_CTRLDESCL5_BPP(6U), /*!< ARGB4444, two pixels use 32 bits. */
+ kLCDIFV2_PixelFormatUYVY = LCDIFV2_CTRLDESCL5_BPP(7U) |
+ LCDIFV2_CTRLDESCL5_YUV_FORMAT(0U), /*!< UYVY, only layer 0 and layer 1 support this. */
+ kLCDIFV2_PixelFormatVYUY = LCDIFV2_CTRLDESCL5_BPP(7U) |
+ LCDIFV2_CTRLDESCL5_YUV_FORMAT(1U), /*!< VYUY, only layer 0 and layer 1 support this. */
+ kLCDIFV2_PixelFormatYUYV = LCDIFV2_CTRLDESCL5_BPP(7U) |
+ LCDIFV2_CTRLDESCL5_YUV_FORMAT(2U), /*!< YUYV, only layer 0 and layer 1 support this. */
+ kLCDIFV2_PixelFormatYVYU = LCDIFV2_CTRLDESCL5_BPP(7U) |
+ LCDIFV2_CTRLDESCL5_YUV_FORMAT(3U), /*!< YVYU, only layer 0 and layer 1 support this. */
+ kLCDIFV2_PixelFormatRGB888 = LCDIFV2_CTRLDESCL5_BPP(8U), /*!< RGB888 packed, one pixel uses 24 bits. */
+ kLCDIFV2_PixelFormatARGB8888 = LCDIFV2_CTRLDESCL5_BPP(9U), /*!< ARGB8888 unpacked, one pixel uses 32 bits. */
+ kLCDIFV2_PixelFormatABGR8888 = LCDIFV2_CTRLDESCL5_BPP(10U), /*!< ABGR8888 unpacked, one pixel uses 32 bits. */
+} lcdifv2_pixel_format_t;
+
+/*! @brief LCDIF v2 source buffer configuration. */
+typedef struct _lcdifv2_buffer_config
+{
+ uint16_t strideBytes; /*!< Number of bytes between two vertically adjacent pixels, suggest 64-bit aligned. */
+ lcdifv2_pixel_format_t pixelFormat; /*!< Source buffer pixel format. */
+} lcdifv2_buffer_config_t;
+
+/*!
+ * @brief LCDIF v2 layer alpha blending mode.
+ */
+typedef enum _lcdifv2_alpha_mode
+{
+ kLCDIFV2_AlphaDisable, /*!< Disable alpha blend. */
+ kLCDIFV2_AlphaOverride, /*!< Use the gobal alpha value, pixel defined alpha value is overridden. */
+ kLCDIFV2_AlphaEmbedded, /*!< Use the pixel defined alpha value. */
+ kLCDIFV2_AlphaPoterDuff, /*!< Use the PoterDuff alpha blending. */
+} lcdifv2_alpha_mode_t;
+
+/*!
+ * @brief LCDIF v2 PoterDuff alpha mode.
+ */
+typedef enum _lcdifv2_pd_alpha_mode
+{
+ kLCDIFV2_PD_AlphaStraight = 0, /*!< Straight mode. */
+ kLCDIFV2_PD_AlphaInversed = 1, /*!< Inversed mode. */
+} lcdifv2_pd_alpha_mode_t;
+
+/*!
+ * @brief LCDIF v2 PoterDuff color mode.
+ */
+typedef enum _lcdifv2_pd_color_mode
+{
+ kLCDIFV2_PD_ColorNoAlpha = 0, /*!< Output color directly. */
+ kLCDIFV2_PD_ColorWithAlpha = 1, /*!< Output color multiples alpha. */
+} lcdifv2_pd_color_mode_t;
+
+/*!
+ * @brief LCDIF v2 PoterDuff global alpha mode.
+ */
+typedef enum _lcdifv2_pd_global_alpha_mode
+{
+ kLCDIFV2_PD_GlobalAlpha = 0, /*!< Use global alpha. */
+ kLCDIFV2_PD_LocalAlpha = 1, /*!< Use local alpha. */
+ kLCDIFV2_PD_ScaledAlpha = 2, /*!< Use scaled alpha. */
+} lcdifv2_pd_global_alpha_mode_t;
+
+/*!
+ * @brief LCDIF v2 PoterDuff factor mode.
+ */
+typedef enum _lcdifv2_pd_factor_mode
+{
+ kLCDIFV2_PD_FactorOne = 0, /*!< Use 1. */
+ kLCDIFV2_PD_FactorZero = 1, /*!< Use 0. */
+ kLCDIFV2_PD_FactorStraightAlpha = 2, /*!< Use straight alpha. */
+ kLCDIFV2_PD_FactorInversedAlpha = 3, /*!< Use inversed alpha. */
+} lcdifv2_pd_factor_mode_t;
+
+/*!
+ * @brief LCDIF v2 layer alpha blending configuration.
+ */
+typedef struct _lcdifv2_blend_config
+{
+ uint8_t globalAlpha; /*!< Global alpha value, only used when
+ @ref alphaMode is @ref kLCDIFV2_AlphaOverride or
+ @ref kLCDIFV2_AlphaPoterDuff */
+ lcdifv2_alpha_mode_t alphaMode; /*!< Alpha mode. */
+ lcdifv2_pd_alpha_mode_t pdAlphaMode; /*!< PoterDuff alpha mode, only used when @ref alphaMode is @ref
+ kLCDIFV2_AlphaPoterDuff */
+ lcdifv2_pd_color_mode_t pdColorMode; /*!< PoterDuff color mode, only used when @ref alphaMode is @ref
+ kLCDIFV2_AlphaPoterDuff */
+ lcdifv2_pd_global_alpha_mode_t pdGlobalAlphaMode; /*!< PoterDuff global alpha mode, only used when @ref alphaMode is
+ @ref kLCDIFV2_AlphaPoterDuff */
+ lcdifv2_pd_factor_mode_t pdFactorMode; /*!< PoterDuff factor mode, only used when @ref alphaMode is @ref
+ kLCDIFV2_AlphaPoterDuff */
+} lcdifv2_blend_config_t;
+
+/*! @brief LCDIFv2 Porter Duff blend mode. Note: Don't change the enum item value */
+typedef enum _lcdifv2_pd_blend_mode
+{
+ kLCDIFV2_PD_Src = 0, /*!< Source Only */
+ kLCDIFV2_PD_Atop, /*!< Source Atop */
+ kLCDIFV2_PD_Over, /*!< Source Over */
+ kLCDIFV2_PD_In, /*!< Source In. */
+ kLCDIFV2_PD_Out, /*!< Source Out. */
+ kLCDIFV2_PD_Dst, /*!< Destination Only. */
+ kLCDIFV2_PD_DstAtop, /*!< Destination Atop. */
+ kLCDIFV2_PD_DstOver, /*!< Destination Over. */
+ kLCDIFV2_PD_DstIn, /*!< Destination In. */
+ kLCDIFV2_PD_DstOut, /*!< Destination Out. */
+ kLCDIFV2_PD_Xor, /*!< XOR. */
+ kLCDIFV2_PD_Clear, /*!< Clear. */
+ kLCDIFV2_PD_Max, /*!< Used for boarder detection. */
+} lcdifv2_pd_blend_mode_t;
+
+/*! @brief LCDIFv2 Porter Duff layer. Note: Don't change the enum item value */
+typedef enum _lcdifv2_pd_layer
+{
+ kLCDIFV2_PD_SrcLayer = 0, /*!< Source layer. */
+ kLCDIFV2_PD_DestLayer = 1, /*!< Destination layer. */
+ kLCDIFV2_PD_LayerMax = 2, /*!< Used for boarder detection. */
+} lcdifv2_pd_layer_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name LCDIF v2 initialization and de-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LCDIF v2.
+ *
+ * This function ungates the LCDIF v2 clock and release the peripheral reset.
+ *
+ * @param base LCDIF v2 peripheral base address.
+ */
+void LCDIFV2_Init(LCDIFV2_Type *base);
+
+/*!
+ * @brief Deinitializes the LCDIF peripheral.
+ *
+ * @param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Deinit(LCDIFV2_Type *base);
+
+/*!
+ * @brief Reset the LCDIF v2.
+ *
+ * @param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Reset(LCDIFV2_Type *base);
+
+/* @} */
+
+/*!
+ * @name Display
+ * @{
+ */
+
+/*!
+ * @brief Gets the LCDIF display default configuration structure.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * @code
+ config->panelWidth = 0U;
+ config->panelHeight = 0U;
+ config->hsw = 3U;
+ config->hfp = 3U;
+ config->hbp = 3U;
+ config->vsw = 3U;
+ config->vfp = 3U;
+ config->vbp = 3U;
+ config->polarityFlags = kLCDIFV2_VsyncActiveHigh | kLCDIFV2_HsyncActiveHigh | kLCDIFV2_DataEnableActiveHigh |
+ kLCDIFV2_DriveDataOnRisingClkEdge | kLCDIFV2_DataActiveHigh;
+ config->lineOrder = kLCDIFV2_LineOrderRGB;
+ @endcode
+ *
+ * @param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_DisplayGetDefaultConfig(lcdifv2_display_config_t *config);
+
+/*!
+ * @brief Set the LCDIF v2 display configurations.
+ *
+ * @param base LCDIF peripheral base address.
+ * @param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_SetDisplayConfig(LCDIFV2_Type *base, const lcdifv2_display_config_t *config);
+
+/*!
+ * @brief Enable or disable the display
+ *
+ * @param base LCDIF peripheral base address.
+ * @param enable Enable or disable.
+ */
+static inline void LCDIFV2_EnableDisplay(LCDIFV2_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DISP_PARA |= LCDIFV2_DISP_PARA_DISP_ON_MASK;
+ }
+ else
+ {
+ base->DISP_PARA &= ~LCDIFV2_DISP_PARA_DISP_ON_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables LCDIF interrupt requests.
+ *
+ * @param base LCDIF peripheral base address.
+ * @param domain CPU domain the interrupt signal routed to.
+ * @param mask interrupt source, OR'ed value of _lcdifv2_interrupt.
+ */
+static inline void LCDIFV2_EnableInterrupts(LCDIFV2_Type *base, uint8_t domain, uint32_t mask)
+{
+ base->INT[domain].INT_ENABLE |= mask;
+}
+
+/*!
+ * @brief Disables LCDIF interrupt requests.
+ *
+ * @param base LCDIF peripheral base address.
+ * @param domain CPU domain the interrupt signal routed to.
+ * @param mask interrupt source, OR'ed value of _lcdifv2_interrupt.
+ */
+static inline void LCDIFV2_DisableInterrupts(LCDIFV2_Type *base, uint8_t domain, uint32_t mask)
+{
+ base->INT[domain].INT_ENABLE &= ~mask;
+}
+
+/*!
+ * @brief Get LCDIF interrupt peding status.
+ *
+ * @param base LCDIF peripheral base address.
+ * @param domain CPU domain the interrupt signal routed to.
+ * @return Interrupt pending status, OR'ed value of _lcdifv2_interrupt.
+ */
+static inline uint32_t LCDIFV2_GetInterruptStatus(LCDIFV2_Type *base, uint8_t domain)
+{
+ return base->INT[domain].INT_STATUS;
+}
+
+/*!
+ * @brief Clear LCDIF interrupt peding status.
+ *
+ * @param base LCDIF peripheral base address.
+ * @param domain CPU domain the interrupt signal routed to.
+ * @param mask of the flags to clear, OR'ed value of _lcdifv2_interrupt.
+ */
+static inline void LCDIFV2_ClearInterruptStatus(LCDIFV2_Type *base, uint8_t domain, uint32_t mask)
+{
+ base->INT[domain].INT_STATUS = mask;
+}
+
+/* @} */
+
+/*!
+ * @name LUT
+ * @{
+ */
+
+/*!
+ * @brief Set the LUT data.
+ *
+ * This function sets the specific layer LUT data, if @p useShadowLoad is true,
+ * call @ref LCDIFV2_TriggerLayerShadowLoad after this function, the
+ * LUT will be loaded to the hardware during next vertical blanking period.
+ * If @p useShadowLoad is false, the LUT data is loaded to hardware directly.
+ *
+ * @param base LCDIF v2 peripheral base address.
+ * @param layerIndex Which layer to set.
+ * @param lutData The LUT data to load.
+ * @param count Count of @p lutData.
+ * @param useShadowLoad Use shadow load.
+ * @retval kStatus_Success Set success.
+ * @retval kStatus_Fail Previous LUT data is not loaded to hardware yet.
+ */
+status_t LCDIFV2_SetLut(
+ LCDIFV2_Type *base, uint8_t layerIndex, const uint32_t *lutData, uint16_t count, bool useShadowLoad);
+
+/* @} */
+
+/*!
+ * @name Layer operation
+ * @{
+ */
+
+/*!
+ * @brief Set the layer dimension.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ * @param width Layer width in pixel.
+ * @param height Layer height.
+ *
+ * @note The layer width must be in multiples of the number of pixels that can be stored in 32 bits
+ */
+static inline void LCDIFV2_SetLayerSize(LCDIFV2_Type *base, uint8_t layerIndex, uint16_t width, uint16_t height)
+{
+ base->LAYER[layerIndex].CTRLDESCL1 =
+ ((uint32_t)height << LCDIFV2_CTRLDESCL1_HEIGHT_SHIFT) | ((uint32_t)width << LCDIFV2_CTRLDESCL1_WIDTH_SHIFT);
+}
+
+/*!
+ * @brief Set the layer position in output frame.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ * @param offsetX Horizontal offset, start from 0.
+ * @param offsetY Vertical offset, start from 0.
+ */
+static inline void LCDIFV2_SetLayerOffset(LCDIFV2_Type *base, uint8_t layerIndex, uint16_t offsetX, uint16_t offsetY)
+{
+ base->LAYER[layerIndex].CTRLDESCL2 =
+ ((uint32_t)offsetX << LCDIFV2_CTRLDESCL2_POSX_SHIFT) | ((uint32_t)offsetY << LCDIFV2_CTRLDESCL2_POSY_SHIFT);
+}
+
+/*!
+ * @brief Set the layer source buffer configuration.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ * @param config Pointer to the configuration.
+ */
+void LCDIFV2_SetLayerBufferConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_buffer_config_t *config);
+
+/*!
+ * @brief Set the layer source buffer address.
+ *
+ * This function is used for fast runtime source buffer change.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ * @param addr The new source buffer address passed to the layer, should be 64-bit aligned.
+ */
+static inline void LCDIFV2_SetLayerBufferAddr(LCDIFV2_Type *base, uint8_t layerIndex, uint32_t addr)
+{
+ base->LAYER[layerIndex].CTRLDESCL4 = LCDIFV2_ADDR_CPU_2_IP(addr);
+}
+
+/*!
+ * @brief Enable or disable the layer.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ * @param enable Pass in true to enable, false to disable.
+ */
+static inline void LCDIFV2_EnableLayer(LCDIFV2_Type *base, uint8_t layerIndex, bool enable)
+{
+ if (enable)
+ {
+ base->LAYER[layerIndex].CTRLDESCL5 |= LCDIFV2_CTRLDESCL5_EN_MASK;
+ }
+ else
+ {
+ base->LAYER[layerIndex].CTRLDESCL5 &= ~LCDIFV2_CTRLDESCL5_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Trigger the layer configuration shadow load.
+ *
+ * The new layer configurations are written to the shadow registers first,
+ * When all configurations written finished, call this function, then shadowed
+ * control registers are updated to the active control registers on VSYNC of
+ * next frame.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Layer layerIndex.
+ */
+static inline void LCDIFV2_TriggerLayerShadowLoad(LCDIFV2_Type *base, uint8_t layerIndex)
+{
+ base->LAYER[layerIndex].CTRLDESCL5 |= LCDIFV2_CTRLDESCL5_SHADOW_LOAD_EN_MASK;
+}
+
+/*!
+ * @brief Set the layer back ground color.
+ *
+ * The back ground color is used when layer not actived.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Index of the layer.
+ * @param backGroundColor Background color to use when this layer is not active.
+ */
+static inline void LCDIFV2_SetLayerBackGroundColor(LCDIFV2_Type *base, uint8_t layerIndex, uint32_t backGroundColor)
+{
+ base->LAYER[layerIndex].CTRLDESCL6 = backGroundColor;
+}
+
+/*!
+ * @brief Set the layer alpha blend mode.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Index of the CSC unit.
+ * @param config Pointer to the blend configuration.
+ */
+void LCDIFV2_SetLayerBlendConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_blend_config_t *config);
+
+/*!
+ * @brief Set the color space conversion mode.
+ *
+ * Supports YUV2RGB and YCbCr2RGB.
+ *
+ * @param base LCDIFv2 peripheral base address.
+ * @param layerIndex Index of the layer.
+ * @param mode The conversion mode.
+ */
+void LCDIFV2_SetCscMode(LCDIFV2_Type *base, uint8_t layerIndex, lcdifv2_csc_mode_t mode);
+
+/* @} */
+
+/*!
+ * @name Porter Duff
+ * @{
+ */
+
+/*!
+ * @brief Get the blend configuration for Porter Duff blend.
+ *
+ * This function gets the blend configuration for Porter Duff blend,
+ * config->pdFactorMode is set according to @p layer and @p mode,
+ * other blend configurations are set to:
+ *
+ * @code
+ config->pdAlphaMode = kLCDIFV2_PD_AlphaStraight;
+ config->pdColorMode = kLCDIFV2_PD_ColorStraight;
+ config->pdGlobalAlphaMode = kLCDIFV2_PD_LocalAlpha;
+ config->alphaMode = kLCDIFV2_AlphaPoterDuff;
+ @endcode
+ *
+ * This is the basic Porter Duff blend configuration, user still could
+ * modify the configurations after this function.
+ *
+ * @param mode Porter Duff blend mode.
+ * @param layer The configuration for source layer or destination layer.
+ * @param config Pointer to the configuration.
+ * @retval kStatus_Success Get the configuration successfully.
+ * @retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetPorterDuffConfig(lcdifv2_pd_blend_mode_t mode,
+ lcdifv2_pd_layer_t layer,
+ lcdifv2_blend_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Misc
+ * @{
+ */
+
+/*!
+ * @brief Get the global alpha values for multiple layer blend.
+ *
+ * This function calculates the global alpha value for each layer based on the
+ * desired blended alpha.
+ *
+ * When all layers use the global alpha, the relationship of blended alpha
+ * and global alpha of each layer is:
+ *
+ * Layer 7: ba7 = ga7
+ * Layer 6: ba6 = ga6 * (1-ga7)
+ * Layer 5: ba5 = ga5 * (1-ga6) * (1-ga7)
+ * Layer 4: ba4 = ga4 * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 3: ba3 = ga3 * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 2: ba2 = ga2 * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 1: ba1 = ga1 * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 0: ba0 = 1 * (1-ga1) * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ *
+ * Here baN is the blended alpha of layer N, gaN is the global alpha configured to layer N.
+ *
+ * This function calculates the global alpha based on the blended alpha. The @p blendedAlpha and
+ * @p globalAlpha are all arrays of size @p layerCount. The first layer is a background layer,
+ * so blendedAlpha[0] is useless, globalAlpha[0] is always 255.
+ *
+ * @param[in] blendedAlpha The desired blended alpha value, alpha range 0~255.
+ * @param[out] globalAlpha Calculated global alpha set to each layer register.
+ * @param[in] layerCount Total layer count.
+ * @retval kStatus_Success Get successfully.
+ * @retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetMultiLayerGlobalAlpha(const uint8_t blendedAlpha[], uint8_t globalAlpha[], uint8_t layerCount);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/* @} */
+
+#endif /*_FSL_LCDIFV2_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.c
new file mode 100644
index 0000000000..b930fd9f93
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpadc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpadc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for LPADC module.
+ *
+ * @param base LPADC peripheral base address
+ */
+static uint32_t LPADC_GetInstance(ADC_Type *base);
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
+/*!
+ * @brief Get gain conversion result .
+ *
+ * @param gainAdjustment gain adjustment value.
+ */
+static uint32_t LPADC_GetGainConvResult(float gainAdjustment);
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to LPADC bases for each instance. */
+static ADC_Type *const s_lpadcBases[] = ADC_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to LPADC clocks for each instance. */
+static const clock_ip_name_t s_lpadcClocks[] = LPADC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t LPADC_GetInstance(ADC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lpadcBases); instance++)
+ {
+ if (s_lpadcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lpadcBases));
+
+ return instance;
+}
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
+/*!
+ * brief Get gain conversion Result .
+ *
+ * param gainAdjustment gain adjustment value.
+ */
+static uint32_t LPADC_GetGainConvResult(float gainAdjustment)
+{
+ int8_t i = 0;
+ uint32_t tmp32 = 0U;
+ uint32_t GCRa[17] = {0};
+ uint32_t GCALR = 0U;
+
+ for (i = 0x10; i >= 0; i--)
+ {
+ tmp32 = (uint32_t)((gainAdjustment) / ((float)(1.0 / (0x01 << (0x10 - i)))));
+ GCRa[i] = tmp32;
+ gainAdjustment = gainAdjustment - ((float)tmp32) * ((float)(1.0 / (0x01 << (0x10 - i))));
+ }
+ /* Get GCALR value calculated */
+ for (i = 0x10; i >= 0; i--)
+ {
+ GCALR += GCRa[i] * (0x01 << i);
+ }
+
+ /* to return GCALR value calculated */
+ return GCALR;
+}
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+
+/*!
+ * brief Initializes the LPADC module.
+ *
+ * param base LPADC peripheral base address.
+ * param config Pointer to configuration structure. See "lpadc_config_t".
+ */
+void LPADC_Init(ADC_Type *base, const lpadc_config_t *config)
+{
+ /* Check if the pointer is available. */
+ assert(config != NULL);
+
+ uint32_t tmp32 = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock for LPADC instance. */
+ (void)CLOCK_EnableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the module. */
+ LPADC_DoResetConfig(base);
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ LPADC_DoResetFIFO0(base);
+ LPADC_DoResetFIFO1(base);
+#else
+ LPADC_DoResetFIFO(base);
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+ /* Disable the module before setting configuration. */
+ LPADC_Enable(base, false);
+
+ /* Configure the module generally. */
+ if (config->enableInDozeMode)
+ {
+ base->CTRL &= ~ADC_CTRL_DOZEN_MASK;
+ }
+ else
+ {
+ base->CTRL |= ADC_CTRL_DOZEN_MASK;
+ }
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
+ /* Set calibration average mode. */
+ base->CTRL |= ADC_CTRL_CAL_AVGS(config->conversionAverageMode);
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
+
+/* ADCx_CFG. */
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
+ if (config->enableInternalClock)
+ {
+ tmp32 |= ADC_CFG_ADCKEN_MASK;
+ }
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
+ if (config->enableVref1LowVoltage)
+ {
+ tmp32 |= ADC_CFG_VREF1RNG_MASK;
+ }
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
+ if (config->enableAnalogPreliminary)
+ {
+ tmp32 |= ADC_CFG_PWREN_MASK;
+ }
+ tmp32 |= ADC_CFG_PUDLY(config->powerUpDelay) /* Power up delay. */
+ | ADC_CFG_REFSEL(config->referenceVoltageSource) /* Reference voltage. */
+
+#if !(defined(FSL_FEATURE_LPADC_HAS_CFG_PWRSEL) && (FSL_FEATURE_LPADC_HAS_CFG_PWRSEL == 0))
+ | ADC_CFG_PWRSEL(config->powerLevelMode) /* Power configuration. */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_PWRSEL */
+ | ADC_CFG_TPRICTRL(config->triggerPriorityPolicy); /* Trigger priority policy. */
+ base->CFG = tmp32;
+
+ /* ADCx_PAUSE. */
+ if (config->enableConvPause)
+ {
+ base->PAUSE = ADC_PAUSE_PAUSEEN_MASK | ADC_PAUSE_PAUSEDLY(config->convPauseDelay);
+ }
+ else
+ {
+ base->PAUSE = 0U;
+ }
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ /* ADCx_FCTRL0. */
+ base->FCTRL[0] = ADC_FCTRL_FWMARK(config->FIFO0Watermark);
+ /* ADCx_FCTRL1. */
+ base->FCTRL[1] = ADC_FCTRL_FWMARK(config->FIFO1Watermark);
+#else
+ /* ADCx_FCTRL. */
+ base->FCTRL = ADC_FCTRL_FWMARK(config->FIFOWatermark);
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+ /* Enable the module after setting configuration. */
+ LPADC_Enable(base, true);
+}
+
+/*!
+ * brief Gets an available pre-defined settings for initial configuration.
+ *
+ * This function initializes the converter configuration structure with an available settings. The default values are:
+ * code
+ * config->enableInDozeMode = true;
+ * config->conversionAverageMode = kLPADC_ConversionAverage1;
+ * config->enableAnalogPreliminary = false;
+ * config->powerUpDelay = 0x80;
+ * config->referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
+ * config->powerLevelMode = kLPADC_PowerLevelAlt1;
+ * config->triggerPriorityPolicy = kLPADC_TriggerPriorityPreemptImmediately;
+ * config->enableConvPause = false;
+ * config->convPauseDelay = 0U;
+ * config->FIFO0Watermark = 0U;
+ * config->FIFO1Watermark = 0U;
+ * config->FIFOWatermark = 0U;
+ * endcode
+ * param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConfig(lpadc_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
+ config->enableInternalClock = false;
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
+ config->enableVref1LowVoltage = false;
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
+ config->enableInDozeMode = true;
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
+ /* Set calibration average mode. */
+ config->conversionAverageMode = kLPADC_ConversionAverage1;
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
+ config->enableAnalogPreliminary = false;
+ config->powerUpDelay = 0x80;
+ config->referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
+#if !(defined(FSL_FEATURE_LPADC_HAS_CFG_PWRSEL) && (FSL_FEATURE_LPADC_HAS_CFG_PWRSEL == 0))
+ config->powerLevelMode = kLPADC_PowerLevelAlt1;
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_PWRSEL */
+ config->triggerPriorityPolicy = kLPADC_TriggerPriorityPreemptImmediately;
+ config->enableConvPause = false;
+ config->convPauseDelay = 0U;
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ config->FIFO0Watermark = 0U;
+ config->FIFO1Watermark = 0U;
+#else
+ config->FIFOWatermark = 0U;
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+}
+
+/*!
+ * brief De-initializes the LPADC module.
+ *
+ * param base LPADC peripheral base address.
+ */
+void LPADC_Deinit(ADC_Type *base)
+{
+ /* Disable the module. */
+ LPADC_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the clock. */
+ (void)CLOCK_DisableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+/*!
+ * brief Get the result in conversion FIFOn.
+ *
+ * param base LPADC peripheral base address.
+ * param result Pointer to structure variable that keeps the conversion result in conversion FIFOn.
+ * param index Result FIFO index.
+ *
+ * return Status whether FIFOn entry is valid.
+ */
+bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result, uint8_t index)
+{
+ assert(result != NULL); /* Check if the input pointer is available. */
+
+ uint32_t tmp32;
+
+ tmp32 = base->RESFIFO[index];
+
+ if (0U == (ADC_RESFIFO_VALID_MASK & tmp32))
+ {
+ return false; /* FIFO is empty. Discard any read from RESFIFO. */
+ }
+
+ result->commandIdSource = (tmp32 & ADC_RESFIFO_CMDSRC_MASK) >> ADC_RESFIFO_CMDSRC_SHIFT;
+ result->loopCountIndex = (tmp32 & ADC_RESFIFO_LOOPCNT_MASK) >> ADC_RESFIFO_LOOPCNT_SHIFT;
+ result->triggerIdSource = (tmp32 & ADC_RESFIFO_TSRC_MASK) >> ADC_RESFIFO_TSRC_SHIFT;
+ result->convValue = (uint16_t)(tmp32 & ADC_RESFIFO_D_MASK);
+
+ return true;
+}
+#else
+/*!
+ * brief Get the result in conversion FIFO.
+ *
+ * param base LPADC peripheral base address.
+ * param result Pointer to structure variable that keeps the conversion result in conversion FIFO.
+ *
+ * return Status whether FIFO entry is valid.
+ */
+bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result)
+{
+ assert(result != NULL); /* Check if the input pointer is available. */
+
+ uint32_t tmp32;
+
+ tmp32 = base->RESFIFO;
+
+ if (0U == (ADC_RESFIFO_VALID_MASK & tmp32))
+ {
+ return false; /* FIFO is empty. Discard any read from RESFIFO. */
+ }
+
+ result->commandIdSource = (tmp32 & ADC_RESFIFO_CMDSRC_MASK) >> ADC_RESFIFO_CMDSRC_SHIFT;
+ result->loopCountIndex = (tmp32 & ADC_RESFIFO_LOOPCNT_MASK) >> ADC_RESFIFO_LOOPCNT_SHIFT;
+ result->triggerIdSource = (tmp32 & ADC_RESFIFO_TSRC_MASK) >> ADC_RESFIFO_TSRC_SHIFT;
+ result->convValue = (uint16_t)(tmp32 & ADC_RESFIFO_D_MASK);
+
+ return true;
+}
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+/*!
+ * brief Configure the conversion trigger source.
+ *
+ * Each programmable trigger can launch the conversion command in command buffer.
+ *
+ * param base LPADC peripheral base address.
+ * param triggerId ID for each trigger. Typically, the available value range is from 0.
+ * param config Pointer to configuration structure. See to #lpadc_conv_trigger_config_t.
+ */
+void LPADC_SetConvTriggerConfig(ADC_Type *base, uint32_t triggerId, const lpadc_conv_trigger_config_t *config)
+{
+ assert(triggerId < ADC_TCTRL_COUNT); /* Check if the triggerId is available in this device. */
+ assert(config != NULL); /* Check if the input pointer is available. */
+
+ uint32_t tmp32;
+
+ tmp32 = ADC_TCTRL_TCMD(config->targetCommandId) /* Trigger command select. */
+ | ADC_TCTRL_TDLY(config->delayPower) /* Trigger delay select. */
+ | ADC_TCTRL_TPRI(config->priority) /* Trigger priority setting. */
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ | ADC_TCTRL_FIFO_SEL_A(config->channelAFIFOSelect)
+#if !(defined(FSL_FEATURE_LPADC_HAS_NO_TCTRL_FIFO_SEL_B) && FSL_FEATURE_LPADC_HAS_NO_TCTRL_FIFO_SEL_B)
+ | ADC_TCTRL_FIFO_SEL_B(config->channelBFIFOSelect)
+#endif /* FSL_FEATURE_LPADC_HAS_NO_TCTRL_FIFO_SEL_B */
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+ ;
+ if (config->enableHardwareTrigger)
+ {
+ tmp32 |= ADC_TCTRL_HTEN_MASK;
+ }
+
+ base->TCTRL[triggerId] = tmp32;
+}
+
+/*!
+ * brief Gets an available pre-defined settings for trigger's configuration.
+ *
+ * This function initializes the trigger's configuration structure with an available settings. The default values are:
+ * code
+ * config->commandIdSource = 0U;
+ * config->loopCountIndex = 0U;
+ * config->triggerIdSource = 0U;
+ * config->enableHardwareTrigger = false;
+ * config->channelAFIFOSelect = 0U;
+ * config->channelBFIFOSelect = 0U;
+ * endcode
+ * param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t *config)
+{
+ assert(config != NULL); /* Check if the input pointer is available. */
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->targetCommandId = 0U;
+ config->delayPower = 0U;
+ config->priority = 0U;
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ config->channelAFIFOSelect = 0U;
+ config->channelBFIFOSelect = 0U;
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+ config->enableHardwareTrigger = false;
+}
+
+/*!
+ * brief Configure conversion command.
+ *
+ * param base LPADC peripheral base address.
+ * param commandId ID for command in command buffer. Typically, the available value range is 1 - 15.
+ * param config Pointer to configuration structure. See to #lpadc_conv_command_config_t.
+ */
+void LPADC_SetConvCommandConfig(ADC_Type *base, uint32_t commandId, const lpadc_conv_command_config_t *config)
+{
+ assert(commandId < (ADC_CMDL_COUNT + 1U)); /* Check if the commandId is available on this device. */
+ assert(config != NULL); /* Check if the input pointer is available. */
+
+ uint32_t tmp32 = 0;
+
+ commandId--; /* The available command number are 1-15, while the index of register group are 0-14. */
+
+ /* ADCx_CMDL. */
+ tmp32 = ADC_CMDL_ADCH(config->channelNumber); /* Channel number. */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH
+ tmp32 |= ADC_CMDL_ALTB_ADCH(config->channelBNumber); /* Alternate channel B number. */
+#endif
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
+ tmp32 |= ADC_CMDL_CSCALE(config->sampleScaleMode); /* Full/Part scale input voltage. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE
+ tmp32 |= ADC_CMDL_ALTB_CSCALE(config->channelBScaleMode); /* Alternate channel B full/Part scale input voltage. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CTYPE) && FSL_FEATURE_LPADC_HAS_CMDL_CTYPE
+ tmp32 |= ADC_CMDL_CTYPE(config->sampleChannelMode);
+#else
+ switch (config->sampleChannelMode) /* Sample input. */
+ {
+ case kLPADC_SampleChannelSingleEndSideB:
+ tmp32 |= ADC_CMDL_ABSEL_MASK;
+ break;
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
+ case kLPADC_SampleChannelDiffBothSideAB:
+ tmp32 |= ADC_CMDL_DIFF_MASK;
+ break;
+ case kLPADC_SampleChannelDiffBothSideBA:
+ tmp32 |= ADC_CMDL_ABSEL_MASK | ADC_CMDL_DIFF_MASK;
+ break;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_DIFF */
+ default: /* kLPADC_SampleChannelSingleEndSideA. */
+ break;
+ }
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_CTYPE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) && FSL_FEATURE_LPADC_HAS_CMDL_MODE
+ tmp32 |= ADC_CMDL_MODE(config->conversionResolutionMode);
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_MODE */
+
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN) && FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN
+ /* Enable alternate channel B.*/
+ if (config->enableChannelB)
+ {
+ tmp32 |= ADC_CMDL_ALTBEN_MASK;
+ }
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN */
+
+ base->CMD[commandId].CMDL = tmp32;
+
+ /* ADCx_CMDH. */
+ tmp32 = ADC_CMDH_NEXT(config->chainedNextCommandNumber) /* Next Command Select. */
+ | ADC_CMDH_LOOP(config->loopCount) /* Loop Count Select. */
+ | ADC_CMDH_AVGS(config->hardwareAverageMode) /* Hardware Average Select. */
+ | ADC_CMDH_STS(config->sampleTimeMode) /* Sample Time Select. */
+ | ADC_CMDH_CMPEN(config->hardwareCompareMode); /* Hardware compare enable. */
+#if (defined(FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG) && FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG)
+ if (config->enableWaitTrigger)
+ {
+ tmp32 |= ADC_CMDH_WAIT_TRIG_MASK; /* Wait trigger enable. */
+ }
+#endif /* FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG */
+
+ if (config->enableAutoChannelIncrement)
+ {
+ tmp32 |= ADC_CMDH_LWI_MASK;
+ }
+ base->CMD[commandId].CMDH = tmp32;
+
+ /* Hardware compare settings.
+ * Not all Command Buffers have an associated Compare Value register. The compare function is only available on
+ * Command Buffers that have a corresponding Compare Value register.
+ */
+ if (kLPADC_HardwareCompareDisabled != config->hardwareCompareMode)
+ {
+ /* Check if the hardware compare feature is available for indicated command buffer. */
+ assert(commandId < ADC_CV_COUNT);
+
+ /* Set CV register. */
+ base->CV[commandId] = ADC_CV_CVH(config->hardwareCompareValueHigh) /* Compare value high. */
+ | ADC_CV_CVL(config->hardwareCompareValueLow); /* Compare value low. */
+ }
+}
+
+/*!
+ * brief Gets an available pre-defined settings for conversion command's configuration.
+ *
+ * This function initializes the conversion command's configuration structure with an available settings. The default
+ * values are:
+ * code
+ * config->sampleScaleMode = kLPADC_SampleFullScale;
+ * config->channelBScaleMode = kLPADC_SampleFullScale;
+ * config->channelSampleMode = kLPADC_SampleChannelSingleEndSideA;
+ * config->channelNumber = 0U;
+ * config ->alternateChannelNumber = 0U;
+ * config->chainedNextCmdNumber = 0U;
+ * config->enableAutoChannelIncrement = false;
+ * config->loopCount = 0U;
+ * config->hardwareAverageMode = kLPADC_HardwareAverageCount1;
+ * config->sampleTimeMode = kLPADC_SampleTimeADCK3;
+ * config->hardwareCompareMode = kLPADC_HardwareCompareDisabled;
+ * config->hardwareCompareValueHigh = 0U;
+ * config->hardwareCompareValueLow = 0U;
+ * config->conversionResolutionMode = kLPADC_ConversionResolutionStandard;
+ * config->enableWaitTrigger = false;
+ * config->enableChannelB = false;
+ * endcode
+ * param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t *config)
+{
+ assert(config != NULL); /* Check if the input pointer is available. */
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
+ config->sampleScaleMode = kLPADC_SampleFullScale;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE
+ config->channelBScaleMode = kLPADC_SampleFullScale;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE */
+ config->sampleChannelMode = kLPADC_SampleChannelSingleEndSideA;
+ config->channelNumber = 0U;
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH
+ config->channelBNumber = 0U;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE */
+ config->chainedNextCommandNumber = 0U; /* No next command defined. */
+ config->enableAutoChannelIncrement = false;
+ config->loopCount = 0U;
+ config->hardwareAverageMode = kLPADC_HardwareAverageCount1;
+ config->sampleTimeMode = kLPADC_SampleTimeADCK3;
+ config->hardwareCompareMode = kLPADC_HardwareCompareDisabled;
+ config->hardwareCompareValueHigh = 0U; /* No used. */
+ config->hardwareCompareValueLow = 0U; /* No used. */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) && FSL_FEATURE_LPADC_HAS_CMDL_MODE
+ config->conversionResolutionMode = kLPADC_ConversionResolutionStandard;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_MODE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG) && FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG
+ config->enableWaitTrigger = false;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN) && FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN
+ config->enableChannelB = false; /* Enable alternate channel B.*/
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN */
+}
+
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS
+/*!
+ * brief Enable the calibration function.
+ *
+ * When CALOFS is set, the ADC is configured to perform a calibration function anytime the ADC executes
+ * a conversion. Any channel selected is ignored and the value returned in the RESFIFO is a signed value
+ * between -31 and 31. -32 is not a valid and is never a returned value. Software should copy the lower 6-
+ * bits of the conversion result stored in the RESFIFO after a completed calibration conversion to the
+ * OFSTRIM field. The OFSTRIM field is used in normal operation for offset correction.
+ *
+ * param base LPADC peripheral base address.
+ * param enable switcher to the calibration function.
+ */
+void LPADC_EnableCalibration(ADC_Type *base, bool enable)
+{
+ LPADC_Enable(base, false);
+ if (enable)
+ {
+ base->CFG |= ADC_CFG_CALOFS_MASK;
+ }
+ else
+ {
+ base->CFG &= ~ADC_CFG_CALOFS_MASK;
+ }
+ LPADC_Enable(base, true);
+}
+
+#if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
+/*!
+ * brief Do auto calibration.
+ *
+ * Calibration function should be executed before using converter in application. It used the software trigger and a
+ * dummy conversion, get the offset and write them into the OFSTRIM register. It called some of functional API
+ * including: -LPADC_EnableCalibration(...) -LPADC_LPADC_SetOffsetValue(...) -LPADC_SetConvCommandConfig(...)
+ * -LPADC_SetConvTriggerConfig(...)
+ *
+ * param base LPADC peripheral base address.
+ */
+void LPADC_DoAutoCalibration(ADC_Type *base)
+{
+ assert(0u == LPADC_GetConvResultCount(base));
+
+ uint32_t mLpadcCMDL;
+ uint32_t mLpadcCMDH;
+ uint32_t mLpadcTrigger;
+ lpadc_conv_trigger_config_t mLpadcTriggerConfigStruct;
+ lpadc_conv_command_config_t mLpadcCommandConfigStruct;
+ lpadc_conv_result_t mLpadcResultConfigStruct;
+
+ /* Enable the calibration function. */
+ LPADC_EnableCalibration(base, true);
+
+ /* Keep the CMD and TRG state here and restore it later if the calibration completes.*/
+ mLpadcCMDL = base->CMD[0].CMDL; /* CMD1L. */
+ mLpadcCMDH = base->CMD[0].CMDH; /* CMD1H. */
+ mLpadcTrigger = base->TCTRL[0]; /* Trigger0. */
+
+ /* Set trigger0 configuration - for software trigger. */
+ LPADC_GetDefaultConvTriggerConfig(&mLpadcTriggerConfigStruct);
+ mLpadcTriggerConfigStruct.targetCommandId = 1U; /* CMD1 is executed. */
+ LPADC_SetConvTriggerConfig(base, 0U, &mLpadcTriggerConfigStruct); /* Configurate the trigger0. */
+
+ /* Set conversion CMD configuration. */
+ LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
+ mLpadcCommandConfigStruct.hardwareAverageMode = kLPADC_HardwareAverageCount128;
+ LPADC_SetConvCommandConfig(base, 1U, &mLpadcCommandConfigStruct); /* Set CMD1 configuration. */
+
+ /* Do calibration. */
+ LPADC_DoSoftwareTrigger(base, 1U); /* 1U is trigger0 mask. */
+ while (!LPADC_GetConvResult(base, &mLpadcResultConfigStruct))
+ {
+ }
+ /* The valid bits of data are bits 14:3 in the RESFIFO register. */
+ LPADC_SetOffsetValue(base, (uint32_t)(mLpadcResultConfigStruct.convValue) >> 3UL);
+ /* Disable the calibration function. */
+ LPADC_EnableCalibration(base, false);
+
+ /* restore CMD and TRG registers. */
+ base->CMD[0].CMDL = mLpadcCMDL; /* CMD1L. */
+ base->CMD[0].CMDH = mLpadcCMDH; /* CMD1H. */
+ base->TCTRL[0] = mLpadcTrigger; /* Trigger0. */
+}
+#endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS
+/*!
+ * brief Do offset calibration.
+ *
+ * param base LPADC peripheral base address.
+ */
+void LPADC_DoOffsetCalibration(ADC_Type *base)
+{
+ LPADC_EnableOffsetCalibration(base, true);
+ while (ADC_STAT_CAL_RDY_MASK != (base->STAT & ADC_STAT_CAL_RDY_MASK))
+ {
+ }
+}
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ
+/*!
+ * brief Do auto calibration.
+ *
+ * param base LPADC peripheral base address.
+ */
+void LPADC_DoAutoCalibration(ADC_Type *base)
+{
+ assert((0u == LPADC_GetConvResultCount(base, 0)) && (0u == LPADC_GetConvResultCount(base, 1)));
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
+ int32_t GCCa;
+ int32_t GCCb;
+ float GCRa;
+ float GCRb;
+#else
+ uint32_t GCCa;
+ uint32_t GCCb;
+ uint32_t GCRa;
+ uint32_t GCRb;
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+
+ /* Request gain calibration. */
+ base->CTRL |= ADC_CTRL_CAL_REQ_MASK;
+ while ((ADC_GCC_RDY_MASK != (base->GCC[0] & ADC_GCC_RDY_MASK)) ||
+ (ADC_GCC_RDY_MASK != (base->GCC[1] & ADC_GCC_RDY_MASK)))
+ {
+ }
+
+ /* Calculate gain offset. */
+ GCCa = (base->GCC[0] & ADC_GCC_GAIN_CAL_MASK);
+ GCCb = (base->GCC[1] & ADC_GCC_GAIN_CAL_MASK);
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
+ if (((base->GCC[0]) & 0x8000U))
+ {
+ GCCa = GCCa - 0x10000;
+ GCRa =
+ (float)((131072.0) / (0x20000 - GCCa)); /* Gain_CalA = (131072.0 / (131072-(ADC_GCC_GAIN_CAL(ADC->GCC[0]))*/
+ base->GCR[0] = LPADC_GetGainConvResult(GCRa); /* write A side GCALR. */
+ }
+
+ if (((base->GCC[1]) & 0x8000U))
+ {
+ GCCb = GCCb - 0x10000;
+ GCRb =
+ (float)((131072.0) / (0x20000 - GCCb)); /* Gain_CalB = (131072.0 / (131072-(ADC_GCC_GAIN_CAL(ADC->GCC[1]))*/
+ base->GCR[1] = LPADC_GetGainConvResult(GCRb); /* write B side GCALR. */
+ }
+#else
+ GCRa = (uint16_t)((GCCa << 16U) /
+ (0x1FFFFU - GCCa)); /* Gain_CalA = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC[0])) - 1. */
+ GCRb = (uint16_t)((GCCb << 16U) /
+ (0x1FFFFU - GCCb)); /* Gain_CalB = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC[1])) - 1. */
+ base->GCR[0] = ADC_GCR_GCALR(GCRa);
+ base->GCR[1] = ADC_GCR_GCALR(GCRb);
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+ /* Indicate the values are valid. */
+ base->GCR[0] |= ADC_GCR_RDY_MASK;
+ base->GCR[1] |= ADC_GCR_RDY_MASK;
+
+ while (ADC_STAT_CAL_RDY_MASK != (base->STAT & ADC_STAT_CAL_RDY_MASK))
+ {
+ }
+}
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.h
new file mode 100644
index 0000000000..dc058c9081
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpadc/fsl_lpadc.h
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPADC_H_
+#define _FSL_LPADC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup lpadc
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPADC driver version 2.6.1. */
+#define FSL_LPADC_DRIVER_VERSION (MAKE_VERSION(2, 6, 1))
+/*@}*/
+
+/*!
+ * @brief Define the MACRO function to get command status from status value.
+ *
+ * The statusVal is the return value from LPADC_GetStatusFlags().
+ */
+#define LPADC_GET_ACTIVE_COMMAND_STATUS(statusVal) ((statusVal & ADC_STAT_CMDACT_MASK) >> ADC_STAT_CMDACT_SHIFT)
+
+/*!
+ * @brief Define the MACRO function to get trigger status from status value.
+ *
+ * The statusVal is the return value from LPADC_GetStatusFlags().
+ */
+#define LPADC_GET_ACTIVE_TRIGGER_STATUE(statusVal) ((statusVal & ADC_STAT_TRGACT_MASK) >> ADC_STAT_TRGACT_SHIFT)
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+/*!
+ * @brief Define hardware flags of the module.
+ */
+enum _lpadc_status_flags
+{
+ kLPADC_ResultFIFO0OverflowFlag = ADC_STAT_FOF0_MASK, /*!< Indicates that more data has been written to the Result
+ FIFO 0 than it can hold. */
+ kLPADC_ResultFIFO0ReadyFlag = ADC_STAT_RDY0_MASK, /*!< Indicates when the number of valid datawords in the result
+ FIFO 0 is greater than the setting watermark level. */
+ kLPADC_ResultFIFO1OverflowFlag = ADC_STAT_FOF1_MASK, /*!< Indicates that more data has been written to the Result
+ FIFO 1 than it can hold. */
+ kLPADC_ResultFIFO1ReadyFlag = ADC_STAT_RDY1_MASK, /*!< Indicates when the number of valid datawords in the result
+ FIFO 1 is greater than the setting watermark level. */
+};
+
+/*!
+ * @brief Define interrupt switchers of the module.
+ */
+enum _lpadc_interrupt_enable
+{
+ kLPADC_ResultFIFO0OverflowInterruptEnable = ADC_IE_FOFIE0_MASK, /*!< Configures ADC to generate overflow interrupt
+ requests when FOF0 flag is asserted. */
+ kLPADC_FIFO0WatermarkInterruptEnable = ADC_IE_FWMIE0_MASK, /*!< Configures ADC to generate watermark interrupt
+ requests when RDY0 flag is asserted. */
+ kLPADC_ResultFIFO1OverflowInterruptEnable = ADC_IE_FOFIE1_MASK, /*!< Configures ADC to generate overflow interrupt
+ requests when FOF1 flag is asserted. */
+ kLPADC_FIFO1WatermarkInterruptEnable = ADC_IE_FWMIE1_MASK, /*!< Configures ADC to generate watermark interrupt
+ requests when RDY1 flag is asserted. */
+#if (defined(FSL_FEATURE_LPADC_HAS_TSTAT) && FSL_FEATURE_LPADC_HAS_TSTAT)
+ kLPADC_TriggerExceptionInterruptEnable = ADC_IE_TEXC_IE_MASK, /*!< Configures ADC to generate trigger exception
+ interrupt. */
+ kLPADC_Trigger0CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 0UL), /*!< Configures ADC to generate interrupt
+ when trigger 0 completion. */
+ kLPADC_Trigger1CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 1UL), /*!< Configures ADC to generate interrupt
+ when trigger 1 completion. */
+ kLPADC_Trigger2CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 2UL), /*!< Configures ADC to generate interrupt
+ when trigger 2 completion. */
+ kLPADC_Trigger3CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 3UL), /*!< Configures ADC to generate interrupt
+ when trigger 3 completion. */
+ kLPADC_Trigger4CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 4UL), /*!< Configures ADC to generate interrupt
+ when trigger 4 completion. */
+ kLPADC_Trigger5CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 5UL), /*!< Configures ADC to generate interrupt
+ when trigger 5 completion. */
+ kLPADC_Trigger6CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 6UL), /*!< Configures ADC to generate interrupt
+ when trigger 6 completion. */
+ kLPADC_Trigger7CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 7UL), /*!< Configures ADC to generate interrupt
+ when trigger 7 completion. */
+ kLPADC_Trigger8CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 8UL), /*!< Configures ADC to generate interrupt
+ when trigger 8 completion. */
+ kLPADC_Trigger9CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 9UL), /*!< Configures ADC to generate interrupt
+ when trigger 9 completion. */
+ kLPADC_Trigger10CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 10UL), /*!< Configures ADC to generate interrupt
+ when trigger 10 completion. */
+ kLPADC_Trigger11CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 11UL), /*!< Configures ADC to generate interrupt
+ when trigger 11 completion. */
+ kLPADC_Trigger12CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 12UL), /*!< Configures ADC to generate interrupt
+ when trigger 12 completion. */
+ kLPADC_Trigger13CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 13UL), /*!< Configures ADC to generate interrupt
+ when trigger 13 completion. */
+ kLPADC_Trigger14CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 14UL), /*!< Configures ADC to generate interrupt
+ when trigger 14 completion. */
+ kLPADC_Trigger15CompletionInterruptEnable = ADC_IE_TCOMP_IE(1UL << 15UL), /*!< Configures ADC to generate interrupt
+ when trigger 15 completion. */
+#endif /* FSL_FEATURE_LPADC_HAS_TSTAT */
+};
+#else
+/*!
+ * @brief Define hardware flags of the module.
+ */
+enum _lpadc_status_flags
+{
+ kLPADC_ResultFIFOOverflowFlag = ADC_STAT_FOF_MASK, /*!< Indicates that more data has been written to the Result FIFO
+ than it can hold. */
+ kLPADC_ResultFIFOReadyFlag = ADC_STAT_RDY_MASK, /*!< Indicates when the number of valid datawords in the result FIFO
+ is greater than the setting watermark level. */
+};
+
+/*!
+ * @brief Define interrupt switchers of the module.
+ */
+enum _lpadc_interrupt_enable
+{
+ kLPADC_ResultFIFOOverflowInterruptEnable = ADC_IE_FOFIE_MASK, /*!< Configures ADC to generate overflow interrupt
+ requests when FOF flag is asserted. */
+ kLPADC_FIFOWatermarkInterruptEnable = ADC_IE_FWMIE_MASK, /*!< Configures ADC to generate watermark interrupt
+ requests when RDY flag is asserted. */
+};
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+#if (defined(FSL_FEATURE_LPADC_HAS_TSTAT) && FSL_FEATURE_LPADC_HAS_TSTAT)
+/*!
+ * @brief The enumerator of lpadc trigger status flags, including interrupted flags and completed flags.
+ */
+enum _lpadc_trigger_status_flags
+{
+ kLPADC_Trigger0InterruptedFlag = 1UL << 0UL, /*!< Trigger 0 is interrupted by a high priority exception. */
+ kLPADC_Trigger1InterruptedFlag = 1UL << 1UL, /*!< Trigger 1 is interrupted by a high priority exception. */
+ kLPADC_Trigger2InterruptedFlag = 1UL << 2UL, /*!< Trigger 2 is interrupted by a high priority exception. */
+ kLPADC_Trigger3InterruptedFlag = 1UL << 3UL, /*!< Trigger 3 is interrupted by a high priority exception. */
+ kLPADC_Trigger4InterruptedFlag = 1UL << 4UL, /*!< Trigger 4 is interrupted by a high priority exception. */
+ kLPADC_Trigger5InterruptedFlag = 1UL << 5UL, /*!< Trigger 5 is interrupted by a high priority exception. */
+ kLPADC_Trigger6InterruptedFlag = 1UL << 6UL, /*!< Trigger 6 is interrupted by a high priority exception. */
+ kLPADC_Trigger7InterruptedFlag = 1UL << 7UL, /*!< Trigger 7 is interrupted by a high priority exception. */
+ kLPADC_Trigger8InterruptedFlag = 1UL << 8UL, /*!< Trigger 8 is interrupted by a high priority exception. */
+ kLPADC_Trigger9InterruptedFlag = 1UL << 9UL, /*!< Trigger 9 is interrupted by a high priority exception. */
+ kLPADC_Trigger10InterruptedFlag = 1UL << 10UL, /*!< Trigger 10 is interrupted by a high priority exception. */
+ kLPADC_Trigger11InterruptedFlag = 1UL << 11UL, /*!< Trigger 11 is interrupted by a high priority exception. */
+ kLPADC_Trigger12InterruptedFlag = 1UL << 12UL, /*!< Trigger 12 is interrupted by a high priority exception. */
+ kLPADC_Trigger13InterruptedFlag = 1UL << 13UL, /*!< Trigger 13 is interrupted by a high priority exception. */
+ kLPADC_Trigger14InterruptedFlag = 1UL << 14UL, /*!< Trigger 14 is interrupted by a high priority exception. */
+ kLPADC_Trigger15InterruptedFlag = 1UL << 15UL, /*!< Trigger 15 is interrupted by a high priority exception. */
+
+ kLPADC_Trigger0CompletedFlag = 1UL << 16UL, /*!< Trigger 0 is completed and
+ trigger 0 has enabled completion interrupts. */
+ kLPADC_Trigger1CompletedFlag = 1UL << 17UL, /*!< Trigger 1 is completed and
+ trigger 1 has enabled completion interrupts. */
+ kLPADC_Trigger2CompletedFlag = 1UL << 18UL, /*!< Trigger 2 is completed and
+ trigger 2 has enabled completion interrupts. */
+ kLPADC_Trigger3CompletedFlag = 1UL << 19UL, /*!< Trigger 3 is completed and
+ trigger 3 has enabled completion interrupts. */
+ kLPADC_Trigger4CompletedFlag = 1UL << 20UL, /*!< Trigger 4 is completed and
+ trigger 4 has enabled completion interrupts. */
+ kLPADC_Trigger5CompletedFlag = 1UL << 21UL, /*!< Trigger 5 is completed and
+ trigger 5 has enabled completion interrupts. */
+ kLPADC_Trigger6CompletedFlag = 1UL << 22UL, /*!< Trigger 6 is completed and
+ trigger 6 has enabled completion interrupts. */
+ kLPADC_Trigger7CompletedFlag = 1UL << 23UL, /*!< Trigger 7 is completed and
+ trigger 7 has enabled completion interrupts. */
+ kLPADC_Trigger8CompletedFlag = 1UL << 24UL, /*!< Trigger 8 is completed and
+ trigger 8 has enabled completion interrupts. */
+ kLPADC_Trigger9CompletedFlag = 1UL << 25UL, /*!< Trigger 9 is completed and
+ trigger 9 has enabled completion interrupts. */
+ kLPADC_Trigger10CompletedFlag = 1UL << 26UL, /*!< Trigger 10 is completed and
+ trigger 10 has enabled completion interrupts. */
+ kLPADC_Trigger11CompletedFlag = 1UL << 27UL, /*!< Trigger 11 is completed and
+ trigger 11 has enabled completion interrupts. */
+ kLPADC_Trigger12CompletedFlag = 1UL << 28UL, /*!< Trigger 12 is completed and
+ trigger 12 has enabled completion interrupts. */
+ kLPADC_Trigger13CompletedFlag = 1UL << 29UL, /*!< Trigger 13 is completed and
+ trigger 13 has enabled completion interrupts. */
+ kLPADC_Trigger14CompletedFlag = 1UL << 30UL, /*!< Trigger 14 is completed and
+ trigger 14 has enabled completion interrupts. */
+ kLPADC_Trigger15CompletedFlag = 1UL << 31UL, /*!< Trigger 15 is completed and
+ trigger 15 has enabled completion interrupts. */
+};
+#endif /* FSL_FEATURE_LPADC_HAS_TSTAT */
+
+/*!
+ * @brief Define enumeration of sample scale mode.
+ *
+ * The sample scale mode is used to reduce the selected ADC analog channel input voltage level by a factor. The maximum
+ * possible voltage on the ADC channel input should be considered when selecting a scale mode to ensure that the
+ * reducing factor always results voltage level at or below the VREFH reference. This reducing capability allows
+ * conversion of analog inputs higher than VREFH. A-side and B-side channel inputs are both scaled using the scale mode.
+ */
+typedef enum _lpadc_sample_scale_mode
+{
+ kLPADC_SamplePartScale =
+ 0U, /*!< Use divided input voltage signal. (For scale select,please refer to the reference manual). */
+ kLPADC_SampleFullScale = 1U, /*!< Full scale (Factor of 1). */
+} lpadc_sample_scale_mode_t;
+
+/*!
+ * @brief Define enumeration of channel sample mode.
+ *
+ * The channel sample mode configures the channel with single-end/differential/dual-single-end, side A/B.
+ */
+typedef enum _lpadc_sample_channel_mode
+{
+ kLPADC_SampleChannelSingleEndSideA = 0U, /*!< Single end mode, using side A. */
+ kLPADC_SampleChannelSingleEndSideB = 1U, /*!< Single end mode, using side B. */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
+ kLPADC_SampleChannelDiffBothSideAB = 2U, /*!< Differential mode, using A as plus side and B as minus side. */
+ kLPADC_SampleChannelDiffBothSideBA = 3U, /*!< Differential mode, using B as plus side and A as minus side. */
+#elif defined(FSL_FEATURE_LPADC_HAS_CMDL_CTYPE) && FSL_FEATURE_LPADC_HAS_CMDL_CTYPE
+ kLPADC_SampleChannelDiffBothSide = 2U, /*!< Differential mode, using A and B. */
+ kLPADC_SampleChannelDualSingleEndBothSide =
+ 3U, /*!< Dual-Single-Ended Mode. Both A side and B side channels are converted independently. */
+#endif
+} lpadc_sample_channel_mode_t;
+
+/*!
+ * @brief Define enumeration of hardware average selection.
+ *
+ * It Selects how many ADC conversions are averaged to create the ADC result. An internal storage buffer is used to
+ * capture temporary results while the averaging iterations are executed.
+ */
+typedef enum _lpadc_hardware_average_mode
+{
+ kLPADC_HardwareAverageCount1 = 0U, /*!< Single conversion. */
+ kLPADC_HardwareAverageCount2 = 1U, /*!< 2 conversions averaged. */
+ kLPADC_HardwareAverageCount4 = 2U, /*!< 4 conversions averaged. */
+ kLPADC_HardwareAverageCount8 = 3U, /*!< 8 conversions averaged. */
+ kLPADC_HardwareAverageCount16 = 4U, /*!< 16 conversions averaged. */
+ kLPADC_HardwareAverageCount32 = 5U, /*!< 32 conversions averaged. */
+ kLPADC_HardwareAverageCount64 = 6U, /*!< 64 conversions averaged. */
+ kLPADC_HardwareAverageCount128 = 7U, /*!< 128 conversions averaged. */
+#if (defined(FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH) && \
+ (FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH == 4))
+ kLPADC_HardwareAverageCount256 = 8U, /*!< 256 conversions averaged. */
+ kLPADC_HardwareAverageCount512 = 9U, /*!< 512 conversions averaged. */
+ kLPADC_HardwareAverageCount1024 = 10U, /*!< 1024 conversions averaged. */
+#endif /* FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH */
+} lpadc_hardware_average_mode_t;
+
+/*!
+ * @brief Define enumeration of sample time selection.
+ *
+ * The shortest sample time maximizes conversion speed for lower impedance inputs. Extending sample time allows higher
+ * impedance inputs to be accurately sampled. Longer sample times can also be used to lower overall power consumption
+ * when command looping and sequencing is configured and high conversion rates are not required.
+ */
+typedef enum _lpadc_sample_time_mode
+{
+ kLPADC_SampleTimeADCK3 = 0U, /*!< 3 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK5 = 1U, /*!< 5 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK7 = 2U, /*!< 7 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK11 = 3U, /*!< 11 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK19 = 4U, /*!< 19 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK35 = 5U, /*!< 35 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK67 = 6U, /*!< 69 ADCK cycles total sample time. */
+ kLPADC_SampleTimeADCK131 = 7U, /*!< 131 ADCK cycles total sample time. */
+} lpadc_sample_time_mode_t;
+
+/*!
+ * @brief Define enumeration of hardware compare mode.
+ *
+ * After an ADC channel input is sampled and converted and any averaging iterations are performed, this mode setting
+ * guides operation of the automatic compare function to optionally only store when the compare operation is true.
+ * When compare is enabled, the conversion result is compared to the compare values.
+ */
+typedef enum _lpadc_hardware_compare_mode
+{
+ kLPADC_HardwareCompareDisabled = 0U, /*!< Compare disabled. */
+ kLPADC_HardwareCompareStoreOnTrue = 2U, /*!< Compare enabled. Store on true. */
+ kLPADC_HardwareCompareRepeatUntilTrue = 3U, /*!< Compare enabled. Repeat channel acquisition until true. */
+} lpadc_hardware_compare_mode_t;
+
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) && FSL_FEATURE_LPADC_HAS_CMDL_MODE
+/*!
+ * @brief Define enumeration of conversion resolution mode.
+ *
+ * Configure the resolution bit in specific conversion type. For detailed resolution accuracy, see to
+ * #lpadc_sample_channel_mode_t
+ */
+typedef enum _lpadc_conversion_resolution_mode
+{
+ kLPADC_ConversionResolutionStandard = 0U, /*!< Standard resolution. Single-ended 12-bit conversion, Differential
+ 13-bit conversion with 2's complement output. */
+ kLPADC_ConversionResolutionHigh = 1U, /*!< High resolution. Single-ended 16-bit conversion; Differential 16-bit
+ conversion with 2's complement output. */
+} lpadc_conversion_resolution_mode_t;
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_MODE */
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
+/*!
+ * @brief Define enumeration of conversion averages mode.
+ *
+ * Configure the converion average number for auto-calibration.
+ */
+typedef enum _lpadc_conversion_average_mode
+{
+ kLPADC_ConversionAverage1 = 0U, /*!< Single conversion. */
+ kLPADC_ConversionAverage2 = 1U, /*!< 2 conversions averaged. */
+ kLPADC_ConversionAverage4 = 2U, /*!< 4 conversions averaged. */
+ kLPADC_ConversionAverage8 = 3U, /*!< 8 conversions averaged. */
+ kLPADC_ConversionAverage16 = 4U, /*!< 16 conversions averaged. */
+ kLPADC_ConversionAverage32 = 5U, /*!< 32 conversions averaged. */
+ kLPADC_ConversionAverage64 = 6U, /*!< 64 conversions averaged. */
+ kLPADC_ConversionAverage128 = 7U, /*!< 128 conversions averaged. */
+#if (defined(FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH) && \
+ (FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH == 4))
+ kLPADC_ConversionAverage256 = 8U, /*!< 256 conversions averaged. */
+ kLPADC_ConversionAverage512 = 9U, /*!< 512 conversions averaged. */
+ kLPADC_ConversionAverage1024 = 10U, /*!< 1024 conversions averaged. */
+#endif /* FSL_FEATURE_LPADC_CONVERSIONS_AVERAGED_BITFIELD_WIDTH */
+} lpadc_conversion_average_mode_t;
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
+
+/*!
+ * @brief Define enumeration of reference voltage source.
+ *
+ * For detail information, need to check the SoC's specification.
+ */
+typedef enum _lpadc_reference_voltage_mode
+{
+ kLPADC_ReferenceVoltageAlt1 = 0U, /*!< Option 1 setting. */
+ kLPADC_ReferenceVoltageAlt2 = 1U, /*!< Option 2 setting. */
+ kLPADC_ReferenceVoltageAlt3 = 2U, /*!< Option 3 setting. */
+} lpadc_reference_voltage_source_t;
+
+/*!
+ * @brief Define enumeration of power configuration.
+ *
+ * Configures the ADC for power and performance. In the highest power setting the highest conversion rates will be
+ * possible. Refer to the device data sheet for power and performance capabilities for each setting.
+ */
+typedef enum _lpadc_power_level_mode
+{
+ kLPADC_PowerLevelAlt1 = 0U, /*!< Lowest power setting. */
+ kLPADC_PowerLevelAlt2 = 1U, /*!< Next lowest power setting. */
+ kLPADC_PowerLevelAlt3 = 2U, /*!< ... */
+ kLPADC_PowerLevelAlt4 = 3U, /*!< Highest power setting. */
+} lpadc_power_level_mode_t;
+
+#if (defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE)
+/*!
+ * @brief Define enumeration of offset calibration mode.
+ *
+ */
+typedef enum _lpadc_offset_calibration_mode
+{
+ kLPADC_OffsetCalibration12bitMode = 0U, /*!< 12 bit offset calibration mode. */
+ kLPADC_OffsetCalibration16bitMode = 1U, /*!< 16 bit offset calibration mode. */
+} lpadc_offset_calibration_mode_t;
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+
+/*!
+ * @brief Define enumeration of trigger priority policy.
+ *
+ * This selection controls how higher priority triggers are handled.
+ */
+typedef enum _lpadc_trigger_priority_policy
+{
+ kLPADC_TriggerPriorityPreemptImmediately = 0U, /*!< If a higher priority trigger is detected during command
+ processing, the current conversion is aborted and the new
+ command specified by the trigger is started. */
+ kLPADC_TriggerPriorityPreemptSoftly = 1U, /*!< If a higher priority trigger is received during command processing,
+ the current conversion is completed (including averaging iterations
+ and compare function if enabled) and stored to the result FIFO
+ before the higher priority trigger/command is initiated. */
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_SUBSEQUENT_PRIORITY) && FSL_FEATURE_LPADC_HAS_CFG_SUBSEQUENT_PRIORITY
+ kLPADC_TriggerPriorityPreemptSubsequently = 2U, /*!< If a higher priority trigger is received during command
+ processing, the current command will be completed (averaging,
+ looping, compare) before servicing the higher priority trigger. */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_SUBSEQUENT_PRIORITY */
+} lpadc_trigger_priority_policy_t;
+
+/*!
+ * @brief LPADC global configuration.
+ *
+ * This structure would used to keep the settings for initialization.
+ */
+typedef struct
+{
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
+ bool enableInternalClock; /*!< Enables the internally generated clock source. The clock source is used in clock
+ selection logic at the chip level and is optionally used for the ADC clock source. */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
+ bool enableVref1LowVoltage; /*!< If voltage reference option1 input is below 1.8V, it should be "true".
+ If voltage reference option1 input is above 1.8V, it should be "false". */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
+ bool enableInDozeMode; /*!< Control system transition to Stop and Wait power modes while ADC is converting. When
+ enabled in Doze mode, immediate entries to Wait or Stop are allowed. When disabled, the
+ ADC will wait for the current averaging iteration/FIFO storage to complete before
+ acknowledging stop or wait mode entry. */
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
+ lpadc_conversion_average_mode_t conversionAverageMode; /*!< Auto-Calibration Averages. */
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
+ bool enableAnalogPreliminary; /*!< ADC analog circuits are pre-enabled and ready to execute conversions without
+ startup delays(at the cost of higher DC current consumption). */
+ uint32_t powerUpDelay; /*!< When the analog circuits are not pre-enabled, the ADC analog circuits are only powered
+ while the ADC is active and there is a counted delay defined by this field after an
+ initial trigger transitions the ADC from its Idle state to allow time for the analog
+ circuits to stabilize. The startup delay count of (powerUpDelay * 4) ADCK cycles must
+ result in a longer delay than the analog startup time. */
+ lpadc_reference_voltage_source_t referenceVoltageSource; /*!< Selects the voltage reference high used for
+ conversions.*/
+
+#if !(defined(FSL_FEATURE_LPADC_HAS_CFG_PWRSEL) && (FSL_FEATURE_LPADC_HAS_CFG_PWRSEL == 0))
+ lpadc_power_level_mode_t powerLevelMode; /*!< Power Configuration Selection. */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_PWRSEL */
+ lpadc_trigger_priority_policy_t triggerPriorityPolicy; /*!< Control how higher priority triggers are handled, see to
+ lpadc_trigger_priority_policy_t. */
+ bool enableConvPause; /*!< Enables the ADC pausing function. When enabled, a programmable delay is inserted during
+ command execution sequencing between LOOP iterations, between commands in a sequence, and
+ between conversions when command is executing in "Compare Until True" configuration. */
+ uint32_t convPauseDelay; /*!< Controls the duration of pausing during command execution sequencing. The pause delay
+ is a count of (convPauseDelay*4) ADCK cycles. Only available when ADC pausing
+ function is enabled. The available value range is in 9-bit. */
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ /* for FIFO0. */
+ uint32_t FIFO0Watermark; /*!< FIFO0Watermark is a programmable threshold setting. When the number of datawords
+ stored in the ADC Result FIFO0 is greater than the value in this field, the ready flag
+ would be asserted to indicate stored data has reached the programmable threshold. */
+ /* for FIFO1. */
+ uint32_t FIFO1Watermark; /*!< FIFO1Watermark is a programmable threshold setting. When the number of datawords
+ stored in the ADC Result FIFO1 is greater than the value in this field, the ready flag
+ would be asserted to indicate stored data has reached the programmable threshold. */
+#else
+ /* for FIFO. */
+ uint32_t FIFOWatermark; /*!< FIFOWatermark is a programmable threshold setting. When the number of datawords stored
+ in the ADC Result FIFO is greater than the value in this field, the ready flag would be
+ asserted to indicate stored data has reached the programmable threshold. */
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+} lpadc_config_t;
+
+/*!
+ * @brief Define structure to keep the configuration for conversion command.
+ */
+typedef struct
+{
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
+ lpadc_sample_scale_mode_t sampleScaleMode; /*!< Sample scale mode. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE
+ lpadc_sample_scale_mode_t channelBScaleMode; /*!< Alternate channe B Scale mode. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTB_CSCALE */
+ lpadc_sample_channel_mode_t sampleChannelMode; /*!< Channel sample mode. */
+ uint32_t channelNumber; /*!< Channel number, select the channel or channel pair. */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH) && FSL_FEATURE_LPADC_HAS_CMDL_ALTB_ADCH
+ uint32_t channelBNumber; /*!< Alternate Channel B number, select the channel. */
+#endif
+ uint32_t chainedNextCommandNumber; /*!< Selects the next command to be executed after this command completes.
+ 1-15 is available, 0 is to terminate the chain after this command. */
+ bool enableAutoChannelIncrement; /*!< Loop with increment: when disabled, the "loopCount" field selects the number
+ of times the selected channel is converted consecutively; when enabled, the
+ "loopCount" field defines how many consecutive channels are converted as part
+ of the command execution. */
+ uint32_t loopCount; /*!< Selects how many times this command executes before finish and transition to the next
+ command or Idle state. Command executes LOOP+1 times. 0-15 is available. */
+ lpadc_hardware_average_mode_t hardwareAverageMode; /*!< Hardware average selection. */
+ lpadc_sample_time_mode_t sampleTimeMode; /*!< Sample time selection. */
+
+ lpadc_hardware_compare_mode_t hardwareCompareMode; /*!< Hardware compare selection. */
+ uint32_t hardwareCompareValueHigh; /*!< Compare Value High. The available value range is in 16-bit. */
+ uint32_t hardwareCompareValueLow; /*!< Compare Value Low. The available value range is in 16-bit. */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) && FSL_FEATURE_LPADC_HAS_CMDL_MODE
+ lpadc_conversion_resolution_mode_t conversionResolutionMode; /*!< Conversion resolution mode. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_MODE */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG) && FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG
+ bool enableWaitTrigger; /*!< Wait for trigger assertion before execution: when disabled, this command will be
+ automatically executed; when enabled, the active trigger must be asserted again before
+ executing this command. */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDH_WAIT_TRIG */
+#if defined(FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN) && FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN
+ bool enableChannelB; /*! Enable alternate Channel B */
+#endif /* FSL_FEATURE_LPADC_HAS_CMDL_ALTBEN */
+} lpadc_conv_command_config_t;
+
+/*!
+ * @brief Define structure to keep the configuration for conversion trigger.
+ */
+typedef struct
+{
+ uint32_t targetCommandId; /*!< Select the command from command buffer to execute upon detect of the associated
+ trigger event. */
+ uint32_t delayPower; /*!< Select the trigger delay duration to wait at the start of servicing a trigger event.
+ When this field is clear, then no delay is incurred. When this field is set to a non-zero
+ value, the duration for the delay is 2^delayPower ADCK cycles. The available value range
+ is 4-bit. */
+ uint32_t priority; /*!< Sets the priority of the associated trigger source. If two or more triggers have the same
+ priority level setting, the lower order trigger event has the higher priority. The lower
+ value for this field is for the higher priority, the available value range is 1-bit. */
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+ uint8_t channelAFIFOSelect; /* SAR Result Destination For Channel A. */
+ uint8_t channelBFIFOSelect; /* SAR Result Destination For Channel B. */
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+ bool enableHardwareTrigger; /*!< Enable hardware trigger source to initiate conversion on the rising edge of the
+ input trigger source or not. THe software trigger is always available. */
+} lpadc_conv_trigger_config_t;
+
+/*!
+ * @brief Define the structure to keep the conversion result.
+ */
+typedef struct
+{
+ uint32_t commandIdSource; /*!< Indicate the command buffer being executed that generated this result. */
+ uint32_t loopCountIndex; /*!< Indicate the loop count value during command execution that generated this result. */
+ uint32_t triggerIdSource; /*!< Indicate the trigger source that initiated a conversion and generated this result. */
+ uint16_t convValue; /*!< Data result. */
+} lpadc_conv_result_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+/*!
+ * @name Initialization & de-initialization.
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LPADC module.
+ *
+ * @param base LPADC peripheral base address.
+ * @param config Pointer to configuration structure. See "lpadc_config_t".
+ */
+void LPADC_Init(ADC_Type *base, const lpadc_config_t *config);
+
+/*!
+ * @brief Gets an available pre-defined settings for initial configuration.
+ *
+ * This function initializes the converter configuration structure with an available settings. The default values are:
+ * @code
+ * config->enableInDozeMode = true;
+ * config->enableAnalogPreliminary = false;
+ * config->powerUpDelay = 0x80;
+ * config->referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
+ * config->powerLevelMode = kLPADC_PowerLevelAlt1;
+ * config->triggerPriorityPolicy = kLPADC_TriggerPriorityPreemptImmediately;
+ * config->enableConvPause = false;
+ * config->convPauseDelay = 0U;
+ * config->FIFOWatermark = 0U;
+ * @endcode
+ * @param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConfig(lpadc_config_t *config);
+
+/*!
+ * @brief De-initializes the LPADC module.
+ *
+ * @param base LPADC peripheral base address.
+ */
+void LPADC_Deinit(ADC_Type *base);
+
+/*!
+ * @brief Switch on/off the LPADC module.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable switcher to the module.
+ */
+static inline void LPADC_Enable(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= ADC_CTRL_ADCEN_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~ADC_CTRL_ADCEN_MASK;
+ }
+}
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+/*!
+ * @brief Do reset the conversion FIFO0.
+ *
+ * @param base LPADC peripheral base address.
+ */
+static inline void LPADC_DoResetFIFO0(ADC_Type *base)
+{
+ base->CTRL |= ADC_CTRL_RSTFIFO0_MASK;
+}
+
+/*!
+ * @brief Do reset the conversion FIFO1.
+ *
+ * @param base LPADC peripheral base address.
+ */
+static inline void LPADC_DoResetFIFO1(ADC_Type *base)
+{
+ base->CTRL |= ADC_CTRL_RSTFIFO1_MASK;
+}
+#else
+/*!
+ * @brief Do reset the conversion FIFO.
+ *
+ * @param base LPADC peripheral base address.
+ */
+static inline void LPADC_DoResetFIFO(ADC_Type *base)
+{
+ base->CTRL |= ADC_CTRL_RSTFIFO_MASK;
+}
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+/*!
+ * @brief Do reset the module's configuration.
+ *
+ * Reset all ADC internal logic and registers, except the Control Register (ADCx_CTRL).
+ *
+ * @param base LPADC peripheral base address.
+ */
+static inline void LPADC_DoResetConfig(ADC_Type *base)
+{
+ base->CTRL |= ADC_CTRL_RST_MASK;
+ base->CTRL &= ~ADC_CTRL_RST_MASK;
+}
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Get status flags.
+ *
+ * @param base LPADC peripheral base address.
+ * @return status flags' mask. See to #_lpadc_status_flags.
+ */
+static inline uint32_t LPADC_GetStatusFlags(ADC_Type *base)
+{
+ return base->STAT;
+}
+
+/*!
+ * @brief Clear status flags.
+ *
+ * Only the flags can be cleared by writing ADCx_STATUS register would be cleared by this API.
+ *
+ * @param base LPADC peripheral base address.
+ * @param mask Mask value for flags to be cleared. See to #_lpadc_status_flags.
+ */
+static inline void LPADC_ClearStatusFlags(ADC_Type *base, uint32_t mask)
+{
+ base->STAT = mask;
+}
+
+#if (defined(FSL_FEATURE_LPADC_HAS_TSTAT) && FSL_FEATURE_LPADC_HAS_TSTAT)
+/*!
+ * @brief Get trigger status flags to indicate which trigger sequences have been completed or interrupted by a high
+ * priority trigger exception.
+ *
+ * @param base LPADC peripheral base address.
+ * @return The OR'ed value of @ref _lpadc_trigger_status_flags.
+ */
+static inline uint32_t LPADC_GetTriggerStatusFlags(ADC_Type *base)
+{
+ return base->TSTAT;
+}
+
+/*!
+ * @brief Clear trigger status flags.
+ *
+ * @param base LPADC peripheral base address.
+ * @param mask The mask of trigger status flags to be cleared, should be the
+ * OR'ed value of @ref _lpadc_trigger_status_flags.
+ */
+static inline void LPADC_ClearTriggerStatusFlags(ADC_Type *base, uint32_t mask)
+{
+ base->TSTAT = mask;
+}
+#endif /* FSL_FEATURE_LPADC_HAS_TSTAT */
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enable interrupts.
+ *
+ * @param base LPADC peripheral base address.
+ * @param mask Mask value for interrupt events. See to #_lpadc_interrupt_enable.
+ */
+static inline void LPADC_EnableInterrupts(ADC_Type *base, uint32_t mask)
+{
+ base->IE |= mask;
+}
+
+/*!
+ * @brief Disable interrupts.
+ *
+ * @param base LPADC peripheral base address.
+ * @param mask Mask value for interrupt events. See to #_lpadc_interrupt_enable.
+ */
+static inline void LPADC_DisableInterrupts(ADC_Type *base, uint32_t mask)
+{
+ base->IE &= ~mask;
+}
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+/*!
+ * @brief Switch on/off the DMA trigger for FIFO0 watermark event.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable Switcher to the event.
+ */
+static inline void LPADC_EnableFIFO0WatermarkDMA(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DE |= ADC_DE_FWMDE0_MASK;
+ }
+ else
+ {
+ base->DE &= ~ADC_DE_FWMDE0_MASK;
+ }
+}
+
+/*!
+ * @brief Switch on/off the DMA trigger for FIFO1 watermark event.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable Switcher to the event.
+ */
+static inline void LPADC_EnableFIFO1WatermarkDMA(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DE |= ADC_DE_FWMDE1_MASK;
+ }
+ else
+ {
+ base->DE &= ~ADC_DE_FWMDE1_MASK;
+ }
+}
+#else
+/*!
+ * @brief Switch on/off the DMA trigger for FIFO watermark event.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable Switcher to the event.
+ */
+static inline void LPADC_EnableFIFOWatermarkDMA(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DE |= ADC_DE_FWMDE_MASK;
+ }
+ else
+ {
+ base->DE &= ~ADC_DE_FWMDE_MASK;
+ }
+}
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+ /* @} */
+
+/*!
+ * @name Trigger and conversion with FIFO.
+ * @{
+ */
+
+#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2))
+/*!
+ * @brief Get the count of result kept in conversion FIFOn.
+ *
+ * @param base LPADC peripheral base address.
+ * @param index Result FIFO index.
+ * @return The count of result kept in conversion FIFOn.
+ */
+static inline uint32_t LPADC_GetConvResultCount(ADC_Type *base, uint8_t index)
+{
+ return (ADC_FCTRL_FCOUNT_MASK & base->FCTRL[index]) >> ADC_FCTRL_FCOUNT_SHIFT;
+}
+
+/*!
+ * brief Get the result in conversion FIFOn.
+ *
+ * param base LPADC peripheral base address.
+ * param result Pointer to structure variable that keeps the conversion result in conversion FIFOn.
+ * param index Result FIFO index.
+ *
+ * return Status whether FIFOn entry is valid.
+ */
+bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result, uint8_t index);
+#else
+/*!
+ * @brief Get the count of result kept in conversion FIFO.
+ *
+ * @param base LPADC peripheral base address.
+ * @return The count of result kept in conversion FIFO.
+ */
+static inline uint32_t LPADC_GetConvResultCount(ADC_Type *base)
+{
+ return (ADC_FCTRL_FCOUNT_MASK & base->FCTRL) >> ADC_FCTRL_FCOUNT_SHIFT;
+}
+
+/*!
+ * @brief Get the result in conversion FIFO.
+ *
+ * @param base LPADC peripheral base address.
+ * @param result Pointer to structure variable that keeps the conversion result in conversion FIFO.
+ *
+ * @return Status whether FIFO entry is valid.
+ */
+bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result);
+#endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
+
+/*!
+ * @brief Configure the conversion trigger source.
+ *
+ * Each programmable trigger can launch the conversion command in command buffer.
+ *
+ * @param base LPADC peripheral base address.
+ * @param triggerId ID for each trigger. Typically, the available value range is from 0.
+ * @param config Pointer to configuration structure. See to #lpadc_conv_trigger_config_t.
+ */
+void LPADC_SetConvTriggerConfig(ADC_Type *base, uint32_t triggerId, const lpadc_conv_trigger_config_t *config);
+
+/*!
+ * @brief Gets an available pre-defined settings for trigger's configuration.
+ *
+ * This function initializes the trigger's configuration structure with an available settings. The default values are:
+ * @code
+ * config->commandIdSource = 0U;
+ * config->loopCountIndex = 0U;
+ * config->triggerIdSource = 0U;
+ * config->enableHardwareTrigger = false;
+ * @endcode
+ * @param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t *config);
+
+/*!
+ * @brief Do software trigger to conversion command.
+ *
+ * @param base LPADC peripheral base address.
+ * @param triggerIdMask Mask value for software trigger indexes, which count from zero.
+ */
+static inline void LPADC_DoSoftwareTrigger(ADC_Type *base, uint32_t triggerIdMask)
+{
+ /* Writes to ADCx_SWTRIG register are ignored while ADCx_CTRL[ADCEN] is clear. */
+ base->SWTRIG = triggerIdMask;
+}
+
+#if defined(FSL_FEATURE_LPADC_HAS_TCTRL_CMD_SEL) && FSL_FEATURE_LPADC_HAS_TCTRL_CMD_SEL
+/*!
+ * @brief Enable hardware trigger command selection.
+ *
+ * This function will use the hardware trigger command from ADC_ETC.The trigger command is then defined
+ * by ADC hardware trigger command selection field in ADC_ETC- >TRIGx_CHAINy_z_n[CSEL].
+ *
+ * @param base LPADC peripheral base address.
+ * @param triggerId ID for each trigger. Typically, the available value range is from 0.
+ * @param enable True to enable or flase to disable.
+ */
+static inline void LPADC_EnableHardwareTriggerCommandSelection(ADC_Type *base, uint32_t triggerId, bool enable)
+{
+ if (enable)
+ {
+ base->TCTRL[triggerId] |= ADC_TCTRL_CMD_SEL_MASK;
+ }
+ else
+ {
+ base->TCTRL[triggerId] &= ~ADC_TCTRL_CMD_SEL_MASK;
+ }
+}
+#endif /* FSL_FEATURE_LPADC_HAS_TCTRL_CMD_SEL*/
+
+/*!
+ * @brief Configure conversion command.
+ *
+ * @param base LPADC peripheral base address.
+ * @param commandId ID for command in command buffer. Typically, the available value range is 1 - 15.
+ * @param config Pointer to configuration structure. See to #lpadc_conv_command_config_t.
+ */
+void LPADC_SetConvCommandConfig(ADC_Type *base, uint32_t commandId, const lpadc_conv_command_config_t *config);
+
+/*!
+ * @brief Gets an available pre-defined settings for conversion command's configuration.
+ *
+ * This function initializes the conversion command's configuration structure with an available settings. The default
+ * values are:
+ * @code
+ * config->sampleScaleMode = kLPADC_SampleFullScale;
+ * config->channelBScaleMode = kLPADC_SampleFullScale;
+ * config->channelSampleMode = kLPADC_SampleChannelSingleEndSideA;
+ * config->channelNumber = 0U;
+ * config->chainedNextCmdNumber = 0U;
+ * config->enableAutoChannelIncrement = false;
+ * config->loopCount = 0U;
+ * config->hardwareAverageMode = kLPADC_HardwareAverageCount1;
+ * config->sampleTimeMode = kLPADC_SampleTimeADCK3;
+ * config->hardwareCompareMode = kLPADC_HardwareCompareDisabled;
+ * config->hardwareCompareValueHigh = 0U;
+ * config->hardwareCompareValueLow = 0U;
+ * config->conversionResolutionMode = kLPADC_ConversionResolutionStandard;
+ * config->enableWaitTrigger = false;
+ * config->enableChannelB = false;
+ * @endcode
+ * @param config Pointer to configuration structure.
+ */
+void LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t *config);
+
+#if defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS
+/*!
+ * @brief Enable the calibration function.
+ *
+ * When CALOFS is set, the ADC is configured to perform a calibration function anytime the ADC executes
+ * a conversion. Any channel selected is ignored and the value returned in the RESFIFO is a signed value
+ * between -31 and 31. -32 is not a valid and is never a returned value. Software should copy the lower 6-
+ * bits of the conversion result stored in the RESFIFO after a completed calibration conversion to the
+ * OFSTRIM field. The OFSTRIM field is used in normal operation for offset correction.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable switcher to the calibration function.
+ */
+void LPADC_EnableCalibration(ADC_Type *base, bool enable);
+#if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
+/*!
+ * @brief Set proper offset value to trim ADC.
+ *
+ * To minimize the offset during normal operation, software should read the conversion result from
+ * the RESFIFO calibration operation and write the lower 6 bits to the OFSTRIM register.
+ *
+ * @param base LPADC peripheral base address.
+ * @param value Setting offset value.
+ */
+static inline void LPADC_SetOffsetValue(ADC_Type *base, uint32_t value)
+{
+ base->OFSTRIM = (value & ADC_OFSTRIM_OFSTRIM_MASK) >> ADC_OFSTRIM_OFSTRIM_SHIFT;
+}
+
+/*!
+ * @brief Do auto calibration.
+ *
+ * Calibration function should be executed before using converter in application. It used the software trigger and a
+ * dummy conversion, get the offset and write them into the OFSTRIM register. It called some of functional API
+ * including: -LPADC_EnableCalibration(...) -LPADC_LPADC_SetOffsetValue(...) -LPADC_SetConvCommandConfig(...)
+ * -LPADC_SetConvTriggerConfig(...)
+ *
+ * @param base LPADC peripheral base address.
+ */
+void LPADC_DoAutoCalibration(ADC_Type *base);
+#endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
+#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS
+#if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
+/*!
+ * @brief Set proper offset value to trim ADC.
+ *
+ * Set the offset trim value for offset calibration manually.
+ *
+ * @param base LPADC peripheral base address.
+ * @param valueA Setting offset value A.
+ * @param valueB Setting offset value B.
+ * @note In normal adc sequence, the values are automatically calculated by LPADC_EnableOffsetCalibration.
+ */
+static inline void LPADC_SetOffsetValue(ADC_Type *base, uint32_t valueA, uint32_t valueB)
+{
+ base->OFSTRIM = ADC_OFSTRIM_OFSTRIM_A(valueA) | ADC_OFSTRIM_OFSTRIM_B(valueB);
+}
+#else
+/*!
+ * @brief Set proper offset value to trim 12 bit ADC conversion.
+ *
+ * Set the offset trim value for offset calibration manually.
+ *
+ * @param base LPADC peripheral base address.
+ * @param valueA Setting offset value A.
+ * @param valueB Setting offset value B.
+ * @note In normal adc sequence, the values are automatically calculated by LPADC_EnableOffsetCalibration.
+ */
+static inline void LPADC_SetOffset12BitValue(ADC_Type *base, uint32_t valueA, uint32_t valueB)
+{
+ base->OFSTRIM12 = ADC_OFSTRIM12_OFSTRIM_A(valueA) | ADC_OFSTRIM12_OFSTRIM_A(valueB);
+}
+
+/*!
+ * @brief Set proper offset value to trim 16 bit ADC conversion.
+ *
+ * Set the offset trim value for offset calibration manually.
+ *
+ * @param base LPADC peripheral base address.
+ * @param valueA Setting offset value A.
+ * @param valueB Setting offset value B.
+ * @note In normal adc sequence, the values are automatically calculated by LPADC_EnableOffsetCalibration.
+ */
+static inline void LPADC_SetOffset16BitValue(ADC_Type *base, uint32_t valueA, uint32_t valueB)
+{
+ base->OFSTRIM16 = ADC_OFSTRIM16_OFSTRIM_A(valueA) | ADC_OFSTRIM16_OFSTRIM_B(valueB);
+}
+#endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
+
+/*!
+ * @brief Enable the offset calibration function.
+ *
+ * @param base LPADC peripheral base address.
+ * @param enable switcher to the calibration function.
+ */
+static inline void LPADC_EnableOffsetCalibration(ADC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= ADC_CTRL_CALOFS_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~ADC_CTRL_CALOFS_MASK;
+ }
+}
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
+/*!
+ * @brief Set offset calibration mode.
+ *
+ * @param base LPADC peripheral base address.
+ * @param mode set offset calibration mode.see to #lpadc_offset_calibration_mode_t .
+ */
+static inline void LPADC_SetOffsetCalibrationMode(ADC_Type *base, lpadc_offset_calibration_mode_t mode)
+{
+ base->CTRL = (base->CTRL & ~ADC_CTRL_CALOFSMODE_MASK) | ADC_CTRL_CALOFSMODE(mode);
+}
+
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */
+
+/*!
+ * @brief Do offset calibration.
+ *
+ * @param base LPADC peripheral base address.
+ */
+void LPADC_DoOffsetCalibration(ADC_Type *base);
+
+#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ
+/*!
+ * brief Do auto calibration.
+ *
+ * param base LPADC peripheral base address.
+ */
+void LPADC_DoAutoCalibration(ADC_Type *base);
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ */
+#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFS */
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_LPADC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c
new file mode 100644
index 0000000000..bdf4659050
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c
@@ -0,0 +1,2608 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c"
+#endif
+
+/* ! @brief LPI2C master fifo commands. */
+enum
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*!
+ * @brief Default watermark values.
+ *
+ * The default watermarks are set to zero.
+ */
+enum
+{
+ kDefaultTxWatermark = 0,
+ kDefaultRxWatermark = 0,
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*
+ * <! Structure definition for variables that passed as parameters in LPI2C_RunTransferStateMachine.
+ * The structure is private.
+ */
+typedef struct _lpi2c_state_machine_param
+{
+ bool state_complete;
+ size_t rxCount;
+ size_t txCount;
+ uint32_t status;
+} lpi2c_state_machine_param_t;
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static uint32_t LPI2C_GetCyclesForWidth(
+ uint32_t sourceClock_Hz, uint32_t width_ns, uint32_t minCycles, uint32_t maxCycles, uint32_t prescaler);
+
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base);
+
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone);
+
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle);
+
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags);
+
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineSendCommandState.
+ * This function was deal with Send Command State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param variable_set Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineSendCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineIssueReadCommandState.
+ * This function was deal with Issue Read Command State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineReadCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineTransferDataState.
+ * This function was deal with init Transfer Data State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineTransferData(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineStopState.
+ * This function was deal with Stop State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ * @param[out] isDone Set to true if the transfer has completed.
+ */
+static void LPI2C_TransferStateMachineStopState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineWaitState.
+ * This function was deal with Wait For Completion State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ * @param[out] isDone Set to true if the transfer has completed.
+ */
+static void LPI2C_TransferStateMachineWaitState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map LPI2C instance number to base pointer. */
+static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS;
+
+/*! @brief Array to map LPI2C instance number to IRQ number, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map LPI2C instance number to clock gate enum. */
+static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS;
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */
+static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to master IRQ handler for each instance, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+lpi2c_master_isr_t s_lpi2cMasterIsr;
+
+/*! @brief Pointers to master handles for each instance, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+void *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static lpi2c_slave_isr_t s_lpi2cSlaveIsr;
+
+/*! @brief Pointers to slave handles for each instance. */
+static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * param base The LPI2C peripheral base address.
+ * return LPI2C instance number starting from 0.
+ */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base)
+{
+ uint32_t instance;
+ for (instance = 0U; instance < ARRAY_SIZE(kLpi2cBases); ++instance)
+ {
+ if (kLpi2cBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(kLpi2cBases));
+ return instance;
+}
+
+/*!
+ * @brief Computes a cycle count for a given time in nanoseconds.
+ * @param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * @param width_ns Desired with in nanoseconds.
+ * @param minCycles Minimum cycle count.
+ * @param maxCycles Maximum cycle count.
+ * @param prescaler LPI2C prescaler setting. If the cycle period is not affected by the prescaler value, set it to 0.
+ */
+static uint32_t LPI2C_GetCyclesForWidth(
+ uint32_t sourceClock_Hz, uint32_t width_ns, uint32_t minCycles, uint32_t maxCycles, uint32_t prescaler)
+{
+ assert(sourceClock_Hz > 0U);
+
+ uint32_t divider = 1U;
+
+ while (prescaler != 0U)
+ {
+ divider *= 2U;
+ prescaler--;
+ }
+
+ uint32_t busCycle_ns = 1000000U / (sourceClock_Hz / divider / 1000U);
+ /* Calculate the cycle count, round up the calculated value. */
+ uint32_t cycles = (width_ns * 10U / busCycle_ns + 5U) / 10U;
+
+ /* If the calculated value is smaller than the minimum value, use the minimum value */
+ if (cycles < minCycles)
+ {
+ cycles = minCycles;
+ }
+ /* If the calculated value is larger than the maximum value, use the maxmum value */
+ if (cycles > maxCycles)
+ {
+ cycles = maxCycles;
+ }
+
+ return cycles;
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check for error. These errors cause a stop to automatically be sent. We must */
+ /* clear the errors before a new transfer can start. */
+ status &= (uint32_t)kLPI2C_MasterErrorFlags;
+ if (0U != status)
+ {
+ /* Select the correct error code. Ordered by severity, with bus issues first. */
+ if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
+ {
+ result = kStatus_LPI2C_PinLowTimeout;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
+ {
+ result = kStatus_LPI2C_ArbitrationLost;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
+ {
+ result = kStatus_LPI2C_Nak;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the flags. */
+ LPI2C_MasterClearStatusFlags(base, status);
+
+ /* Reset fifos. These flags clear automatically. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Wait until there is room in the tx fifo.
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base)
+{
+ status_t result = kStatus_Success;
+ uint32_t status;
+ size_t txCount;
+ size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+ do
+ {
+ /* Get the number of words in the tx fifo and compute empty slots. */
+ LPI2C_MasterGetFifoCounts(base, NULL, &txCount);
+ txCount = txFifoSize - txCount;
+
+ /* Check for error flags. */
+ status = LPI2C_MasterGetStatusFlags(base);
+ result = LPI2C_MasterCheckAndClearError(base, status);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == txCount) && (0U != waitTimes));
+
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == txCount);
+#endif
+
+ return result;
+}
+
+/*!
+ * @brief Make sure the bus isn't already busy.
+ *
+ * A busy bus is allowed if we are the one driving it.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_Busy
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_CheckForBusyBus(LPI2C_Type *base)
+{
+ status_t ret = kStatus_Success;
+
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_MasterBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_MasterBusyFlag)))
+ {
+ ret = kStatus_LPI2C_Busy;
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C master peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C master peripheral:
+ * code
+ * masterConfig->enableMaster = true;
+ * masterConfig->debugEnable = false;
+ * masterConfig->ignoreAck = false;
+ * masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ * masterConfig->baudRate_Hz = 100000U;
+ * masterConfig->busIdleTimeout_ns = 0U;
+ * masterConfig->pinLowTimeout_ns = 0U;
+ * masterConfig->sdaGlitchFilterWidth_ns = 0U;
+ * masterConfig->sclGlitchFilterWidth_ns = 0U;
+ * masterConfig->hostRequest.enable = false;
+ * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+ * endcode
+ *
+ * After calling this function, you can override any settings in order to customize the configuration,
+ * prior to initializing the master driver with LPI2C_MasterInit().
+ *
+ * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t.
+ */
+void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->debugEnable = false;
+ masterConfig->enableDoze = true;
+ masterConfig->ignoreAck = false;
+ masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ masterConfig->baudRate_Hz = 100000U;
+ masterConfig->busIdleTimeout_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->pinLowTimeout_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->sdaGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->sclGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->hostRequest.enable = false;
+ masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+}
+
+/*!
+ * brief Initializes the LPI2C master peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user
+ * provided configuration. A software reset is performed prior to configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of
+ * defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors,
+ * filter widths, and timeout periods.
+ */
+void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t prescaler;
+ uint32_t cycles;
+ uint32_t cfgr2;
+ uint32_t value;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ (void)CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset peripheral before configuring it. */
+ LPI2C_MasterReset(base);
+
+ /* Doze bit: 0 is enable, 1 is disable */
+ base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze));
+
+ /* host request */
+ value = base->MCFGR0;
+ value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK));
+ value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) |
+ LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) |
+ LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source);
+ base->MCFGR0 = value;
+
+ /* pin config and ignore ack */
+ value = base->MCFGR1;
+ value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
+ value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig);
+ value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck);
+ base->MCFGR1 = value;
+
+ LPI2C_MasterSetWatermarks(base, (size_t)kDefaultTxWatermark, (size_t)kDefaultRxWatermark);
+
+ /* Configure glitch filters. */
+ cfgr2 = base->MCFGR2;
+ if (0U != (masterConfig->sdaGlitchFilterWidth_ns))
+ {
+ /* Calculate SDA filter width. The width is equal to FILTSDA cycles of functional clock.
+ And set FILTSDA to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns, 1U,
+ (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 0U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles);
+ }
+ if (0U != masterConfig->sclGlitchFilterWidth_ns)
+ {
+ /* Calculate SDL filter width. The width is equal to FILTSCL cycles of functional clock.
+ And set FILTSCL to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns, 1U,
+ (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 0U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles);
+ }
+ base->MCFGR2 = cfgr2;
+
+ /* Configure baudrate after the SDA/SCL glitch filter setting,
+ since the baudrate calculation needs them as parameter. */
+ LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz);
+
+ /* Configure bus idle and pin low timeouts after baudrate setting,
+ since the timeout calculation needs prescaler as parameter. */
+ prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT;
+
+ if (0U != (masterConfig->busIdleTimeout_ns))
+ {
+ /* Calculate bus idle timeout value. The value is equal to BUSIDLE cycles of functional clock divided by
+ prescaler. And set BUSIDLE to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns, 1U,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ base->MCFGR2 = (base->MCFGR2 & (~LPI2C_MCFGR2_BUSIDLE_MASK)) | LPI2C_MCFGR2_BUSIDLE(cycles);
+ }
+ if (0U != masterConfig->pinLowTimeout_ns)
+ {
+ /* Calculate bus pin low timeout value. The value is equal to PINLOW cycles of functional clock divided by
+ prescaler. And set PINLOW to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256U, 1U,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles);
+ }
+
+ LPI2C_MasterEnable(base, masterConfig->enableMaster);
+}
+
+/*!
+ * brief Deinitializes the LPI2C master peripheral.
+ *
+ * This function disables the LPI2C master peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_MasterDeinit(LPI2C_Type *base)
+{
+ /* Restore to reset state. */
+ LPI2C_MasterReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate clock. */
+ (void)CLOCK_DisableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures LPI2C master data match feature.
+ *
+ * param base The LPI2C peripheral base address.
+ * param matchConfig Settings for the data match feature.
+ */
+void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *matchConfig)
+{
+ /* Disable master mode. */
+ bool wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(matchConfig->matchMode);
+ base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(matchConfig->rxDataMatchOnly);
+ base->MDMR = LPI2C_MDMR_MATCH0(matchConfig->match0) | LPI2C_MDMR_MATCH1(matchConfig->match1);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sets the I2C bus frequency for master transactions.
+ *
+ * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud
+ * rate. Do not call this function during a transfer, or the transfer is aborted.
+ *
+ * note Please note that the second parameter is the clock frequency of LPI2C module, the third
+ * parameter means user configured bus baudrate, this implementation is different from other I2C drivers
+ * which use baudrate configuration as second parameter and source clock frequency as third parameter.
+ *
+ * param base The LPI2C peripheral base address.
+ * param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * param baudRate_Hz Requested bus frequency in Hertz.
+ */
+void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz)
+{
+ bool wasEnabled;
+ uint8_t filtScl = (uint8_t)((base->MCFGR2 & LPI2C_MCFGR2_FILTSCL_MASK) >> LPI2C_MCFGR2_FILTSCL_SHIFT);
+
+ uint8_t divider = 1U;
+ uint8_t bestDivider = 1U;
+ uint8_t prescale = 0U;
+ uint8_t bestPre = 0U;
+
+ uint8_t clkCycle;
+ uint8_t bestclkCycle = 0U;
+
+ uint32_t absError = 0U;
+ uint32_t bestError = 0xffffffffu;
+ uint32_t computedRate;
+
+ uint32_t tmpReg = 0U;
+
+ /* Disable master mode. */
+ wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ /* Baud rate = (sourceClock_Hz / 2 ^ prescale) / (CLKLO + 1 + CLKHI + 1 + SCL_LATENCY)
+ * SCL_LATENCY = ROUNDDOWN((2 + FILTSCL) / (2 ^ prescale))
+ */
+ for (prescale = 0U; prescale <= 7U; prescale++)
+ {
+ /* Calculate the clkCycle, clkCycle = CLKLO + CLKHI, divider = 2 ^ prescale */
+ clkCycle = (uint8_t)((10U * sourceClock_Hz / divider / baudRate_Hz + 5U) / 10U - (2U + filtScl) / divider - 2U);
+ /* According to register description, The max value for CLKLO and CLKHI is 63.
+ however to meet the I2C specification of tBUF, CLKHI should be less than
+ clkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / divider + 1U. Refer to the comment of the tmpHigh's
+ calculation for details. So we have:
+ CLKHI < clkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / divider + 1U,
+ clkCycle = CLKHI + CLKLO and
+ sourceClock_Hz / baudRate_Hz / divider = clkCycle + 2 + ROUNDDOWN((2 + FILTSCL) / divider),
+ we can come up with: CLKHI < 0.92 x CLKLO - ROUNDDOWN(2 + FILTSCL) / divider
+ so the max boundary of CLKHI should be 0.92 x 63 - ROUNDDOWN(2 + FILTSCL) / divider,
+ and the max boundary of clkCycle is 1.92 x 63 - ROUNDDOWN(2 + FILTSCL) / divider. */
+ if (clkCycle > (120U - (2U + filtScl) / divider))
+ {
+ divider *= 2U;
+ continue;
+ }
+ /* Calculate the computed baudrate and compare it with the desired baudrate */
+ computedRate = (sourceClock_Hz / (uint32_t)divider) /
+ ((uint32_t)clkCycle + 2U + (2U + (uint32_t)filtScl) / (uint32_t)divider);
+ absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz;
+ if (absError < bestError)
+ {
+ bestPre = prescale;
+ bestDivider = divider;
+ bestclkCycle = clkCycle;
+ bestError = absError;
+
+ /* If the error is 0, then we can stop searching because we won't find a better match. */
+ if (absError == 0U)
+ {
+ break;
+ }
+ }
+ divider *= 2U;
+ }
+
+ /* SCL low time tLO should be larger than or equal to SCL high time tHI:
+ tLO = ((CLKLO + 1) x (2 ^ PRESCALE)) >= tHI = ((CLKHI + 1 + SCL_LATENCY) x (2 ^ PRESCALE)),
+ which is CLKLO >= CLKHI + (2U + filtScl) / bestDivider.
+ Also since bestclkCycle = CLKLO + CLKHI, bestDivider = 2 ^ PRESCALE
+ which makes CLKHI <= (bestclkCycle - (2U + filtScl) / bestDivider) / 2U.
+
+ The max tBUF should be at least 0.52 times of the SCL clock cycle:
+ tBUF = ((CLKLO + 1) x (2 ^ PRESCALE) / sourceClock_Hz) > (0.52 / baudRate_Hz),
+ plus bestDivider = 2 ^ PRESCALE, bestclkCycle = CLKLO + CLKHI we can come up with
+ CLKHI <= (bestclkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / bestDivider + 1U).
+ In this case to get a safe CLKHI calculation, we can assume:
+ */
+ uint8_t tmpHigh = (bestclkCycle - (2U + filtScl) / bestDivider) / 2U;
+ while (tmpHigh > (bestclkCycle - 52U * sourceClock_Hz / baudRate_Hz / bestDivider / 100U + 1U))
+ {
+ tmpHigh = tmpHigh - 1U;
+ }
+
+ /* Calculate DATAVD and SETHOLD.
+ To meet the timing requirement of I2C spec for standard mode, fast mode and fast mode plus: */
+ /* The min tHD:STA/tSU:STA/tSU:STO should be at least 0.4 times of the SCL clock cycle, use 0.5 to be safe:
+ tHD:STA = ((SETHOLD + 1) x (2 ^ PRESCALE) / sourceClock_Hz) > (0.5 / baudRate_Hz), bestDivider = 2 ^ PRESCALE */
+ uint8_t tmpHold = (uint8_t)(sourceClock_Hz / baudRate_Hz / bestDivider / 2U) - 1U;
+
+ /* The max tVD:DAT/tVD:ACK/tHD:DAT should be at most 0.345 times of the SCL clock cycle, use 0.25 to be safe:
+ tVD:DAT = ((DATAVD + 1) x (2 ^ PRESCALE) / sourceClock_Hz) < (0.25 / baudRate_Hz), bestDivider = 2 ^ PRESCALE */
+ uint8_t tmpDataVd = (uint8_t)(sourceClock_Hz / baudRate_Hz / bestDivider / 4U) - 1U;
+
+ /* The min tSU:DAT should be at least 0.05 times of the SCL clock cycle:
+ tSU:DAT = ((2 + FILTSDA + 2 ^ PRESCALE) / sourceClock_Hz) >= (0.05 / baud),
+ plus bestDivider = 2 ^ PRESCALE, we can come up with:
+ FILTSDA >= (0.05 x sourceClock_Hz / baudRate_Hz - bestDivider - 2) */
+ if ((sourceClock_Hz / baudRate_Hz / 20U) > (bestDivider + 2U))
+ {
+ /* Read out the FILTSDA configuration, if it is smaller than expected, change the setting. */
+ uint8_t filtSda = (uint8_t)((base->MCFGR2 & LPI2C_MCFGR2_FILTSDA_MASK) >> LPI2C_MCFGR2_FILTSDA_SHIFT);
+ if (filtSda < (sourceClock_Hz / baudRate_Hz / 20U - bestDivider - 2U))
+ {
+ filtSda = (uint8_t)(sourceClock_Hz / baudRate_Hz / 20U) - bestDivider - 2U;
+ }
+ base->MCFGR2 = (base->MCFGR2 & ~LPI2C_MCFGR2_FILTSDA_MASK) | LPI2C_MCFGR2_FILTSDA(filtSda);
+ }
+
+ /* Set CLKHI, CLKLO, SETHOLD, DATAVD value. */
+ tmpReg = LPI2C_MCCR0_CLKHI((uint32_t)tmpHigh) |
+ LPI2C_MCCR0_CLKLO((uint32_t)((uint32_t)bestclkCycle - (uint32_t)tmpHigh)) |
+ LPI2C_MCCR0_SETHOLD((uint32_t)tmpHold) | LPI2C_MCCR0_DATAVD((uint32_t)tmpDataVd);
+ base->MCCR0 = tmpReg;
+
+ /* Set PRESCALE value. */
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sends a START signal and slave address on the I2C bus.
+ *
+ * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
+ * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
+ * 7-bit address specified in the a address parameter. Note that this function does not actually wait
+ * until the START and address are successfully sent on the bus before returning.
+ *
+ * param base The LPI2C peripheral base address.
+ * param address 7-bit slave device address, in bits [6:0].
+ * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir)
+{
+ /* Return an error if the bus is already in use not by us. */
+ status_t result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success == result)
+ {
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Wait until there is room in the fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Issue start command. */
+ base->MTDR = (uint32_t)kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Sends a STOP signal on the I2C bus.
+ *
+ * This function does not return until the STOP signal is seen on the bus, or an error occurs.
+ *
+ * param base The LPI2C peripheral base address.
+ * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterStop(LPI2C_Type *base)
+{
+ /* Wait until there is room in the fifo. */
+ status_t result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Send the STOP signal */
+ base->MTDR = (uint32_t)kStopCmd;
+
+ /* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */
+ /* Also check for errors while waiting. */
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+#if I2C_RETRY_TIMES != 0U
+ while ((result == kStatus_Success) && (0U != waitTimes))
+ {
+ waitTimes--;
+#else
+ while (result == kStatus_Success)
+ {
+#endif
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+
+ /* Check for error flags. */
+ result = LPI2C_MasterCheckAndClearError(base, status);
+
+ /* Check if the stop was sent successfully. */
+ if ((0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag)) &&
+ (0U != (status & (uint32_t)kLPI2C_MasterTxReadyFlag)))
+ {
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterStopDetectFlag);
+ break;
+ }
+ }
+
+#if I2C_RETRY_TIMES != 0U
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#endif
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize)
+{
+ assert(NULL != rxBuff);
+
+ status_t result = kStatus_Success;
+ uint8_t *buf;
+ size_t tmpRxSize = rxSize;
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes;
+#endif
+
+ /* Check transfer data size. */
+ if (rxSize > ((size_t)256 * (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Handle empty read. */
+ if (rxSize != 0U)
+ {
+ /* Wait until there is room in the command fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Issue command to receive data. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data
+ at most, so when the rxSize is larger than 0x100U, push multiple read commands to MTDR until rxSize is
+ reached. */
+ while (tmpRxSize != 0U)
+ {
+ if (tmpRxSize > 256U)
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+
+ /* Receive data */
+ buf = (uint8_t *)rxBuff;
+ while (0U != (rxSize--))
+ {
+#if I2C_RETRY_TIMES != 0U
+ waitTimes = I2C_RETRY_TIMES;
+#endif
+ /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */
+ /* the FIFO is empty, so we can both get the data and check if we need to keep reading */
+ /* using a single register read. */
+ uint32_t value = 0U;
+ do
+ {
+ /* Check for errors. */
+ result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base));
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ value = base->MRDR;
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U != (value & LPI2C_MRDR_RXEMPTY_MASK)) && (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U != (value & LPI2C_MRDR_RXEMPTY_MASK));
+#endif
+ if ((status_t)kStatus_Success != result)
+ {
+ break;
+ }
+
+ *buf++ = (uint8_t)(value & LPI2C_MRDR_DATA_MASK);
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may
+ * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
+ * function returns #kStatus_LPI2C_Nak.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was sent successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or over run.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)txBuff;
+
+ assert(NULL != txBuff);
+
+ /* Send data buffer */
+ while (0U != (txSize--))
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = *buf++;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a master polling transfer on the I2C bus.
+ *
+ * note The API does not return until the transfer succeeds or fails due
+ * to error happens during transfer.
+ *
+ * param base The LPI2C peripheral base address.
+ * param transfer Pointer to the transfer structure.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer)
+{
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ status_t result = kStatus_Success;
+ uint16_t commandBuffer[7];
+ uint32_t cmdCount = 0U;
+
+ /* Check transfer data size in read operation. */
+ if ((transfer->direction == kLPI2C_Read) &&
+ (transfer->dataSize > ((size_t)256 * (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base))))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success == result)
+ {
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ lpi2c_direction_t direction = (0U != transfer->subaddressSize) ? kLPI2C_Write : transfer->direction;
+ if (0U == (transfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction);
+ }
+
+ /* Subaddress, MSB first. */
+ if (0U != transfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = transfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)((transfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ commandBuffer[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != transfer->dataSize) && (transfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+ }
+
+ /* Send command buffer */
+ uint32_t index = 0U;
+ while (0U != cmdCount--)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = commandBuffer[index];
+ index++;
+ }
+
+ if (kStatus_Success == result)
+ {
+ /* Transmit data. */
+ if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0U))
+ {
+ /* Send Data. */
+ result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize);
+ }
+
+ /* Receive Data. */
+ if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0U))
+ {
+ result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize);
+ }
+
+ if (kStatus_Success == result)
+ {
+ if ((transfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ result = LPI2C_MasterStop(base);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C master non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called.
+ *
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cMasterHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
+ In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable
+ INTMUX IRQ in application code. */
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+}
+
+static void LPI2C_TransferStateMachineSendCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+ uint16_t sendval;
+
+ /* Make sure there is room in the tx fifo for the next command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */
+ sendval = ((uint16_t)handle->buf[0]) | (((uint16_t)handle->buf[1]) << 8U);
+ base->MTDR = sendval;
+ handle->buf++;
+ handle->buf++;
+
+ /* Count down until all commands are sent. */
+ if (--handle->remainingBytes == 0U)
+ {
+ /* Choose next state and set up buffer pointer and count. */
+ if (0U != handle->transfer.dataSize)
+ {
+ /* Either a send or receive transfer is next. */
+ handle->state = (uint8_t)kTransferDataState;
+ handle->buf = (uint8_t *)handle->transfer.data;
+ handle->remainingBytes = (uint16_t)handle->transfer.dataSize;
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ /* Issue command to receive data. A single write to MTDR can issue read operation of
+ 0xFFU + 1 byte of data at most, so when the dataSize is larger than 0x100U, push
+ multiple read commands to MTDR until dataSize is reached. */
+ size_t tmpRxSize = handle->transfer.dataSize;
+ while (tmpRxSize != 0U)
+ {
+ LPI2C_MasterGetFifoCounts(base, NULL, &stateParams->txCount);
+ while ((size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base) == stateParams->txCount)
+ {
+ LPI2C_MasterGetFifoCounts(base, NULL, &stateParams->txCount);
+ }
+
+ if (tmpRxSize > 256U)
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No transfer, so move to stop state. */
+ handle->state = (uint8_t)kStopState;
+ }
+ }
+}
+
+static void LPI2C_TransferStateMachineReadCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+
+ /* Make sure there is room in the tx fifo for the read command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ base->MTDR = (uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(handle->transfer.dataSize - 1U);
+
+ /* Move to transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ }
+}
+
+static void LPI2C_TransferStateMachineTransferData(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ /* Make sure there is room in the tx fifo. */
+ if (0U == stateParams->txCount--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Put byte to send in fifo. */
+ base->MTDR = *(handle->buf)++;
+ }
+ else
+ {
+ /* XXX handle receive sizes > 256, use kIssueReadCommandState */
+ /* Make sure there is data in the rx fifo. */
+ if (0U == stateParams->rxCount--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Read byte from fifo. */
+ *(handle->buf)++ = (uint8_t)(base->MRDR & LPI2C_MRDR_DATA_MASK);
+ }
+
+ /* Move to stop when the transfer is done. */
+ if (--handle->remainingBytes == 0U)
+ {
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ stateParams->state_complete = true;
+ }
+ handle->state = (uint8_t)kStopState;
+ }
+}
+
+static void LPI2C_TransferStateMachineStopState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone)
+{
+ assert(stateParams != NULL);
+
+ /* Only issue a stop transition if the caller requested it. */
+ if ((handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ /* Make sure there is room in the tx fifo for the stop command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+ else
+ {
+ /* If all data is read and no stop flag is required to send, we are done. */
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ *isDone = true;
+ }
+ stateParams->state_complete = true;
+ }
+ handle->state = (uint8_t)kWaitForCompletionState;
+}
+
+static void LPI2C_TransferStateMachineWaitState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone)
+{
+ assert(stateParams != NULL);
+
+ if ((handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ /* We stay in this state until the stop state is detected. */
+ if (0U != ((stateParams->status) & (uint32_t)kLPI2C_MasterStopDetectFlag))
+ {
+ *isDone = true;
+ }
+ }
+ else
+ {
+ /* If all data is pushed to FIFO and no stop flag is required to send, we need to make sure they
+ are all send out to bus. */
+ if ((handle->transfer.direction == kLPI2C_Write) && ((base->MFSR & LPI2C_MFSR_TXCOUNT_MASK) == 0U))
+ {
+ /* We stay in this state until the data is sent out to bus. */
+ *isDone = true;
+ }
+ }
+ stateParams->state_complete = true;
+}
+
+/*!
+ * @brief Execute states until FIFOs are exhausted.
+ * @param handle Master nonblocking driver handle.
+ * @param[out] isDone Set to true if the transfer has completed.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone)
+{
+ assert(NULL != base && NULL != handle && NULL != isDone);
+
+ status_t result = kStatus_Success;
+ lpi2c_state_machine_param_t stateParams;
+ (void)memset(&stateParams, 0, sizeof(stateParams));
+
+ stateParams.state_complete = false;
+
+ /* Set default isDone return value. */
+ *isDone = false;
+
+ /* Check for errors. */
+ stateParams.status = LPI2C_MasterGetStatusFlags(base);
+
+ /* Get fifo counts. */
+ LPI2C_MasterGetFifoCounts(base, &stateParams.rxCount, &stateParams.txCount);
+
+ /* For the last byte, nack flag is expected.
+ Do not check and clear kLPI2C_MasterNackDetectFlag for the last byte,
+ in case FIFO is emptied when stop command has not been sent. */
+ if (handle->remainingBytes == 0U)
+ {
+ /* When data size is not zero which means it is not only one byte of address is sent, and */
+ /* when the txfifo is empty, or have one byte which is the stop command, then the nack status can be ignored. */
+ if (((handle->transfer).dataSize != 0U) &&
+ ((stateParams.txCount == 0U) ||
+ (((stateParams.txCount) == 1U) && (handle->state == (uint8_t)kWaitForCompletionState) &&
+ (((handle->transfer).flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U))))
+ {
+ (stateParams.status) &= ~(uint32_t)kLPI2C_MasterNackDetectFlag;
+ }
+ }
+
+ result = LPI2C_MasterCheckAndClearError(base, stateParams.status);
+
+ if (kStatus_Success == result)
+ {
+ /* Compute room in tx fifo */
+ stateParams.txCount = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base) - stateParams.txCount;
+
+ while (!stateParams.state_complete)
+ {
+ /* Execute the state. */
+ switch (handle->state)
+ {
+ case (uint8_t)kSendCommandState:
+ LPI2C_TransferStateMachineSendCommand(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kIssueReadCommandState:
+ LPI2C_TransferStateMachineReadCommand(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kTransferDataState:
+ LPI2C_TransferStateMachineTransferData(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kStopState:
+ LPI2C_TransferStateMachineStopState(base, handle, &stateParams, isDone);
+ break;
+
+ case (uint8_t)kWaitForCompletionState:
+ LPI2C_TransferStateMachineWaitState(base, handle, &stateParams, isDone);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * @brief Prepares the transfer state machine and fills in the command buffer.
+ * @param handle Master nonblocking driver handle.
+ */
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+
+ /* Handle no start option. */
+ if (0U != (xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ handle->state = (uint8_t)kIssueReadCommandState;
+ }
+ else
+ {
+ /* Start immediately in the data transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ }
+
+ handle->buf = (uint8_t *)xfer->data;
+ handle->remainingBytes = (uint16_t)xfer->dataSize;
+ }
+ else
+ {
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0U;
+
+ /* Initial direction depends on whether a subaddress was provided, and of course the actual */
+ /* data transfer direction. */
+ lpi2c_direction_t direction = (0U != xfer->subaddressSize) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (0U != xfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != (subaddressRemaining--))
+ {
+ uint8_t subaddressByte = (uint8_t)((xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != xfer->dataSize) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+ }
+
+ /* Set up state machine for transferring the commands. */
+ handle->state = (uint8_t)kSendCommandState;
+ handle->remainingBytes = (uint16_t)cmdCount;
+ handle->buf = (uint8_t *)&handle->commandBuffer;
+ }
+}
+
+/*!
+ * brief Performs a non-blocking transaction on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ assert(NULL != handle);
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ status_t result;
+
+ /* Check transfer data size in read operation. */
+ if ((transfer->direction == kLPI2C_Read) &&
+ (transfer->dataSize > (256U * (uint32_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base))))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ else
+ {
+ result = LPI2C_CheckForBusyBus(base);
+ }
+
+ if ((status_t)kStatus_Success == result)
+ {
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Reset FIFO in case there are data. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ LPI2C_InitTransferStateMachine(handle);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_MasterEnableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count)
+{
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+
+ if (NULL == count)
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ else if (handle->state == (uint8_t)kIdleState)
+ {
+ *count = 0;
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ uint8_t state;
+ uint16_t remainingBytes;
+ uint32_t dataSize;
+
+ /* Cache some fields with IRQs disabled. This ensures all field values */
+ /* are synchronized with each other during an ongoing transfer. */
+ uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base);
+ LPI2C_MasterDisableInterrupts(base, irqs);
+ state = handle->state;
+ remainingBytes = handle->remainingBytes;
+ dataSize = handle->transfer.dataSize;
+ LPI2C_MasterEnableInterrupts(base, irqs);
+
+ /* Get transfer count based on current transfer state. */
+ switch (state)
+ {
+ case (uint8_t)kIdleState:
+ case (uint8_t)kSendCommandState:
+ case (uint8_t)
+ kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */
+ *count = 0;
+ break;
+
+ case (uint8_t)kTransferDataState:
+ *count = dataSize - remainingBytes;
+ break;
+
+ case (uint8_t)kStopState:
+ case (uint8_t)kWaitForCompletionState:
+ default:
+ *count = dataSize;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * LPI2C peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress.
+ */
+void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle)
+{
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* If master is still busy and has not send out stop signal yet. */
+ if ((LPI2C_MasterGetStatusFlags(base) & ((uint32_t)kLPI2C_MasterStopDetectFlag |
+ (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Reset handle. */
+ handle->state = (uint8_t)kIdleState;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle master interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * nonblocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param lpi2cMasterHandle Pointer to the LPI2C master driver handle.
+ */
+void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, void *lpi2cMasterHandle)
+{
+ assert(lpi2cMasterHandle != NULL);
+
+ lpi2c_master_handle_t *handle = (lpi2c_master_handle_t *)lpi2cMasterHandle;
+ bool isDone = false;
+ status_t result;
+
+ /* Don't do anything if we don't have a valid handle. */
+ if (NULL != handle)
+ {
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ result = LPI2C_RunTransferStateMachine(base, handle, &isDone);
+
+ if ((result != kStatus_Success) || isDone)
+ {
+ /* Handle error, terminate xfer */
+ if (result != kStatus_Success)
+ {
+ LPI2C_MasterTransferAbort(base, handle);
+ }
+
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Set handle to idle state. */
+ handle->state = (uint8_t)kIdleState;
+
+ /* Invoke callback. */
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C slave peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C slave peripheral:
+ * code
+ * slaveConfig->enableSlave = true;
+ * slaveConfig->address0 = 0U;
+ * slaveConfig->address1 = 0U;
+ * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ * slaveConfig->filterDozeEnable = true;
+ * slaveConfig->filterEnable = true;
+ * slaveConfig->enableGeneralCall = false;
+ * slaveConfig->sclStall.enableAck = false;
+ * slaveConfig->sclStall.enableTx = true;
+ * slaveConfig->sclStall.enableRx = true;
+ * slaveConfig->sclStall.enableAddress = true;
+ * slaveConfig->ignoreAck = false;
+ * slaveConfig->enableReceivedAddressRead = false;
+ * slaveConfig->sdaGlitchFilterWidth_ns = 0;
+ * slaveConfig->sclGlitchFilterWidth_ns = 0;
+ * slaveConfig->dataValidDelay_ns = 0;
+ * slaveConfig->clockHoldTime_ns = 0;
+ * endcode
+ *
+ * After calling this function, override any settings to customize the configuration,
+ * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a
+ * address0 member of the configuration structure with the desired slave address.
+ *
+ * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to
+ * #lpi2c_slave_config_t.
+ */
+void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->enableSlave = true;
+ slaveConfig->address0 = 0U;
+ slaveConfig->address1 = 0U;
+ slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ slaveConfig->filterDozeEnable = true;
+ slaveConfig->filterEnable = true;
+ slaveConfig->enableGeneralCall = false;
+ slaveConfig->sclStall.enableAck = false;
+ slaveConfig->sclStall.enableTx = true;
+ slaveConfig->sclStall.enableRx = true;
+ slaveConfig->sclStall.enableAddress = false;
+ slaveConfig->ignoreAck = false;
+ slaveConfig->enableReceivedAddressRead = false;
+ slaveConfig->sdaGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ slaveConfig->sclGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ slaveConfig->dataValidDelay_ns = 0U;
+ /* When enabling the slave tx SCL stall, set the default clock hold time to 250ns according
+ to I2C spec for standard mode baudrate(100k). User can manually change it to 100ns or 50ns
+ for fast-mode(400k) or fast-mode+(1m). */
+ slaveConfig->clockHoldTime_ns = 250U;
+}
+
+/*!
+ * brief Initializes the LPI2C slave peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user
+ * provided configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths,
+ * data valid delay, and clock hold time.
+ */
+void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t tmpReg;
+ uint32_t tmpCycle;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ (void)CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Restore to reset conditions. */
+ LPI2C_SlaveReset(base);
+
+ /* Configure peripheral. */
+ base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1);
+
+ base->SCFGR1 =
+ LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) |
+ LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) |
+ LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) |
+ LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) |
+ LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress);
+
+ /* Calculate SDA filter width. The width is equal to FILTSDA+3 cycles of functional clock.
+ And set FILTSDA to 0 disables the fileter, so the min value is 4. */
+ tmpReg = LPI2C_SCFGR2_FILTSDA(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns, 4U,
+ (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT) + 3U, 0U) -
+ 3U);
+
+ /* Calculate SDL filter width. The width is equal to FILTSCL+3 cycles of functional clock.
+ And set FILTSCL to 0 disables the fileter, so the min value is 4. */
+ tmpCycle = LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns, 4U,
+ (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT) + 3U, 0U);
+ tmpReg |= LPI2C_SCFGR2_FILTSCL(tmpCycle - 3U);
+
+ /* Calculate data valid time. The time is equal to FILTSCL+DATAVD+3 cycles of functional clock.
+ So the min value is FILTSCL+3. */
+ tmpReg |= LPI2C_SCFGR2_DATAVD(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->dataValidDelay_ns, tmpCycle,
+ tmpCycle + (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 0U) -
+ tmpCycle);
+
+ /* Calculate clock hold time. The time is equal to CLKHOLD+3 cycles of functional clock.
+ So the min value is 3. */
+ base->SCFGR2 =
+ tmpReg | LPI2C_SCFGR2_CLKHOLD(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->clockHoldTime_ns, 3U,
+ (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT) + 3U, 0U) -
+ 3U);
+
+ /* Save SCR to last so we don't enable slave until it is configured */
+ base->SCR = LPI2C_SCR_FILTDZ(!slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) |
+ LPI2C_SCR_SEN(slaveConfig->enableSlave);
+}
+
+/*!
+ * brief Deinitializes the LPI2C slave peripheral.
+ *
+ * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_SlaveDeinit(LPI2C_Type *base)
+{
+ LPI2C_SlaveReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate the clock. */
+ (void)CLOCK_DisableClock(kLpi2cClocks[instance]);
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_BitError
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags)
+{
+ status_t result = kStatus_Success;
+
+ flags &= (uint32_t)kLPI2C_SlaveErrorFlags;
+ if (0U != flags)
+ {
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveBitErrFlag))
+ {
+ result = kStatus_LPI2C_BitError;
+ }
+ else if (0U != (flags & (uint32_t)kLPI2C_SlaveFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the errors. */
+ LPI2C_SlaveClearStatusFlags(base, flags);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * param[out] actualTxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)txBuff;
+ size_t remaining = txSize;
+
+ assert(NULL != txBuff);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+
+ /* Wait until we can transmit. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Send a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ base->STDR = *buf++;
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart in transfer*/
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * param[out] actualRxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)rxBuff;
+ size_t remaining = rxSize;
+
+ assert(NULL != rxBuff);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+
+ /* Wait until we can receive. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ if ((status_t)kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Receive a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ *buf++ = (uint8_t)(base->SRDR & LPI2C_SRDR_DATA_MASK);
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart */
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C slave non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called.
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C slave driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_slave_handle_t *handle,
+ lpi2c_slave_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cSlaveHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+}
+
+/*!
+ * brief Starts accepting slave transfers.
+ *
+ * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing
+ * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
+ * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked
+ * from the interrupt context.
+ *
+ * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to
+ * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive.
+ * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need
+ * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
+ * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as
+ * a convenient way to enable all events.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify
+ * which events to send to the callback. Other accepted values are 0 to get a default set of
+ * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events.
+ *
+ * retval #kStatus_Success Slave transfers were successfully started.
+ * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle.
+ */
+status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask)
+{
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ else
+ {
+ /* Enable the slave function and disable the master function. */
+ LPI2C_MasterEnable(base, false);
+ LPI2C_SlaveEnable(base, true);
+ /* Return an error if the bus is already in use not by us. */
+ uint32_t status = LPI2C_SlaveGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_SlaveBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_SlaveBusyFlag)))
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ }
+
+ if ((status_t)kStatus_Success == result)
+ {
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+
+ /* Clear transfer in handle. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* Record that we're busy. */
+ handle->isBusy = true;
+
+ /* Set up event mask. tx and rx are always enabled. */
+ handle->eventMask = eventMask | (uint32_t)kLPI2C_SlaveTransmitEvent | (uint32_t)kLPI2C_SlaveReceiveEvent;
+
+ /* Ack by default. */
+ base->STAR = 0U;
+
+ /* Clear all flags. */
+ LPI2C_SlaveClearStatusFlags(base, (uint32_t)kLPI2C_SlaveClearFlags);
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_SlaveEnableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Gets the slave transfer status during a non-blocking transfer.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to i2c_slave_handle_t structure.
+ * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
+ * required.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress
+ */
+status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count)
+{
+ status_t status = kStatus_Success;
+
+ assert(NULL != handle);
+
+ if (count == NULL)
+ {
+ status = kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ else if (!handle->isBusy)
+ {
+ *count = 0;
+ status = kStatus_NoTransferInProgress;
+ }
+
+ /* For an active transfer, just return the count from the handle. */
+ else
+ {
+ *count = handle->transferredCount;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the slave non-blocking transfers.
+ * note This API could be called at any time to stop slave for handling the bus events.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * retval #kStatus_Success
+ * retval #kStatus_LPI2C_Idle
+ */
+void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Return idle if no transaction is in progress. */
+ if (handle->isBusy)
+ {
+ /* Disable LPI2C IRQ sources. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+
+ /* Reset transfer info. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* We're no longer busy. */
+ handle->isBusy = false;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle slave interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * non blocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ */
+void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ uint32_t flags;
+ lpi2c_slave_transfer_t *xfer;
+
+ /* Check for a valid handle in case of a spurious interrupt. */
+ if (NULL != handle)
+ {
+ xfer = &handle->transfer;
+
+ /* Get status flags. */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+
+ if (0U != (flags & ((uint32_t)kLPI2C_SlaveBitErrFlag | (uint32_t)kLPI2C_SlaveFifoErrFlag)))
+ {
+ xfer->event = kLPI2C_SlaveCompletionEvent;
+ xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags);
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveCompletionEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ else
+ {
+ if (0U !=
+ (flags & (((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag) | ((uint32_t)kLPI2C_SlaveStopDetectFlag))))
+ {
+ xfer->event = (0U != (flags & (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)) ?
+ kLPI2C_SlaveRepeatedStartEvent :
+ kLPI2C_SlaveCompletionEvent;
+ xfer->receivedAddress = 0U;
+ xfer->completionStatus = kStatus_Success;
+ xfer->transferredCount = handle->transferredCount;
+
+ if (xfer->event == kLPI2C_SlaveCompletionEvent)
+ {
+ handle->isBusy = false;
+ }
+
+ if (handle->wasTransmit)
+ {
+ /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */
+ /* tx flag before it sees the nack from the master-receiver, thus causing one more */
+ /* count that the master actually receives. */
+ --xfer->transferredCount;
+ handle->wasTransmit = false;
+ }
+
+ /* Clear the flag. */
+ LPI2C_SlaveClearStatusFlags(base, flags & ((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag |
+ (uint32_t)kLPI2C_SlaveStopDetectFlag));
+
+ /* Revert to sending an Ack by default, in case we sent a Nack for receive. */
+ base->STAR = 0U;
+
+ if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveStopDetectFlag))
+ {
+ /* Clean up transfer info on completion, after the callback has been invoked. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveAddressValidFlag))
+ {
+ xfer->event = kLPI2C_SlaveAddressMatchEvent;
+ xfer->receivedAddress = (uint8_t)(base->SASR & LPI2C_SASR_RADDR_MASK);
+
+ /* Update handle status to busy because slave is addressed. */
+ handle->isBusy = true;
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTransmitAckFlag))
+ {
+ xfer->event = kLPI2C_SlaveTransmitAckEvent;
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveTransmitAckEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+
+ /* Handle transmit and receive. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ handle->wasTransmit = true;
+
+ /* If we're out of data, invoke callback to get more. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveTransmitEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Transmit a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ base->STDR = *xfer->data++;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ /* If we're out of room in the buffer, invoke callback to get another. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveReceiveEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Receive a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ *xfer->data++ = (uint8_t)base->SRDR;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ else
+ {
+ /* We don't have any room to receive more data, so send a nack. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+ }
+ }
+ }
+ }
+}
+
+#if !(defined(FSL_FEATURE_I2C_HAS_NO_IRQ) && FSL_FEATURE_I2C_HAS_NO_IRQ)
+/*!
+ * @brief Shared IRQ handler that can call both master and slave ISRs.
+ *
+ * The master and slave ISRs are called through function pointers in order to decouple
+ * this code from the ISR functions. Without this, the linker would always pull in both
+ * ISRs and every function they call, even if only the functional API was used.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param instance The LPI2C peripheral instance number.
+ */
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance)
+{
+ /* Check for master IRQ. */
+ if ((0U != (base->MCR & LPI2C_MCR_MEN_MASK)) && (NULL != s_lpi2cMasterIsr))
+ {
+ /* Master mode. */
+ s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]);
+ }
+
+ /* Check for slave IRQ. */
+ if ((0U != (base->SCR & LPI2C_SCR_SEN_MASK)) && (NULL != s_lpi2cSlaveIsr))
+ {
+ /* Slave mode. */
+ s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(LPI2C0)
+/* Implementation of LPI2C0 handler named in startup code. */
+void LPI2C0_DriverIRQHandler(void);
+void LPI2C0_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C0, 0U);
+}
+#endif
+
+#if defined(LPI2C1)
+/* Implementation of LPI2C1 handler named in startup code. */
+void LPI2C1_DriverIRQHandler(void);
+void LPI2C1_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C1, 1U);
+}
+#endif
+
+#if defined(LPI2C2)
+/* Implementation of LPI2C2 handler named in startup code. */
+void LPI2C2_DriverIRQHandler(void);
+void LPI2C2_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C2, 2U);
+}
+#endif
+
+#if defined(LPI2C3)
+/* Implementation of LPI2C3 handler named in startup code. */
+void LPI2C3_DriverIRQHandler(void);
+void LPI2C3_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C3, 3U);
+}
+#endif
+
+#if defined(LPI2C4)
+/* Implementation of LPI2C4 handler named in startup code. */
+void LPI2C4_DriverIRQHandler(void);
+void LPI2C4_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C4, 4U);
+}
+#endif
+
+#if defined(LPI2C5)
+/* Implementation of LPI2C5 handler named in startup code. */
+void LPI2C5_DriverIRQHandler(void);
+void LPI2C5_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C5, 5U);
+}
+#endif
+
+#if defined(LPI2C6)
+/* Implementation of LPI2C6 handler named in startup code. */
+void LPI2C6_DriverIRQHandler(void);
+void LPI2C6_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C6, 6U);
+}
+#endif
+
+#if defined(CM4_0__LPI2C)
+/* Implementation of CM4_0__LPI2C handler named in startup code. */
+void M4_0_LPI2C_DriverIRQHandler(void);
+void M4_0_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C));
+}
+#endif
+
+#if defined(CM4__LPI2C)
+/* Implementation of CM4__LPI2C handler named in startup code. */
+void M4_LPI2C_DriverIRQHandler(void);
+void M4_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C));
+}
+#endif
+
+#if defined(CM4_1__LPI2C)
+/* Implementation of CM4_1__LPI2C handler named in startup code. */
+void M4_1_LPI2C_DriverIRQHandler(void);
+void M4_1_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C));
+}
+#endif
+
+#if defined(DMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void DMA_I2C0_INT_DriverIRQHandler(void);
+void DMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0));
+}
+#endif
+
+#if defined(DMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void DMA_I2C1_INT_DriverIRQHandler(void);
+void DMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1));
+}
+#endif
+
+#if defined(DMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void DMA_I2C2_INT_DriverIRQHandler(void);
+void DMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2));
+}
+#endif
+
+#if defined(DMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C3_INT_DriverIRQHandler(void);
+void DMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3));
+}
+#endif
+
+#if defined(DMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C4_INT_DriverIRQHandler(void);
+void DMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4));
+}
+#endif
+
+#if defined(ADMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void ADMA_I2C0_INT_DriverIRQHandler(void);
+void ADMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0));
+}
+#endif
+
+#if defined(ADMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void ADMA_I2C1_INT_DriverIRQHandler(void);
+void ADMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1));
+}
+#endif
+
+#if defined(ADMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void ADMA_I2C2_INT_DriverIRQHandler(void);
+void ADMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2));
+}
+#endif
+
+#if defined(ADMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C3_INT_DriverIRQHandler(void);
+void ADMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3));
+}
+#endif
+
+#if defined(ADMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C4_INT_DriverIRQHandler(void);
+void ADMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4));
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h
new file mode 100644
index 0000000000..d61a6eb5cf
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h
@@ -0,0 +1,1320 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPI2C_H_
+#define _FSL_LPI2C_H_
+
+#include <stddef.h>
+#include "fsl_device_registers.h"
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*!
+ * @addtogroup lpi2c
+ * @{
+ */
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C driver version. */
+#define FSL_LPI2C_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef I2C_RETRY_TIMES
+#define I2C_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief LPI2C status return codes. */
+enum
+{
+ kStatus_LPI2C_Busy = MAKE_STATUS(kStatusGroup_LPI2C, 0), /*!< The master is already performing a transfer. */
+ kStatus_LPI2C_Idle = MAKE_STATUS(kStatusGroup_LPI2C, 1), /*!< The slave driver is idle. */
+ kStatus_LPI2C_Nak = MAKE_STATUS(kStatusGroup_LPI2C, 2), /*!< The slave device sent a NAK in response to a byte. */
+ kStatus_LPI2C_FifoError = MAKE_STATUS(kStatusGroup_LPI2C, 3), /*!< FIFO under run or overrun. */
+ kStatus_LPI2C_BitError = MAKE_STATUS(kStatusGroup_LPI2C, 4), /*!< Transferred bit was not seen on the bus. */
+ kStatus_LPI2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_LPI2C, 5), /*!< Arbitration lost error. */
+ kStatus_LPI2C_PinLowTimeout =
+ MAKE_STATUS(kStatusGroup_LPI2C, 6), /*!< SCL or SDA were held low longer than the timeout. */
+ kStatus_LPI2C_NoTransferInProgress =
+ MAKE_STATUS(kStatusGroup_LPI2C, 7), /*!< Attempt to abort a transfer when one is not in progress. */
+ kStatus_LPI2C_DmaRequestFail = MAKE_STATUS(kStatusGroup_LPI2C, 8), /*!< DMA request failed. */
+ kStatus_LPI2C_Timeout = MAKE_STATUS(kStatusGroup_LPI2C, 9), /*!< Timeout polling status flags. */
+};
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_master_driver
+ * @{
+ */
+
+/*!
+ * @brief LPI2C master peripheral flags.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_MasterEndOfPacketFlag
+ * - #kLPI2C_MasterStopDetectFlag
+ * - #kLPI2C_MasterNackDetectFlag
+ * - #kLPI2C_MasterArbitrationLostFlag
+ * - #kLPI2C_MasterFifoErrFlag
+ * - #kLPI2C_MasterPinLowTimeoutFlag
+ * - #kLPI2C_MasterDataMatchFlag
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @note These enums are meant to be OR'd together to form a bit mask.
+ */
+enum _lpi2c_master_flags
+{
+ kLPI2C_MasterTxReadyFlag = LPI2C_MSR_TDF_MASK, /*!< Transmit data flag */
+ kLPI2C_MasterRxReadyFlag = LPI2C_MSR_RDF_MASK, /*!< Receive data flag */
+ kLPI2C_MasterEndOfPacketFlag = LPI2C_MSR_EPF_MASK, /*!< End Packet flag */
+ kLPI2C_MasterStopDetectFlag = LPI2C_MSR_SDF_MASK, /*!< Stop detect flag */
+ kLPI2C_MasterNackDetectFlag = LPI2C_MSR_NDF_MASK, /*!< NACK detect flag */
+ kLPI2C_MasterArbitrationLostFlag = LPI2C_MSR_ALF_MASK, /*!< Arbitration lost flag */
+ kLPI2C_MasterFifoErrFlag = LPI2C_MSR_FEF_MASK, /*!< FIFO error flag */
+ kLPI2C_MasterPinLowTimeoutFlag = LPI2C_MSR_PLTF_MASK, /*!< Pin low timeout flag */
+ kLPI2C_MasterDataMatchFlag = LPI2C_MSR_DMF_MASK, /*!< Data match flag */
+ kLPI2C_MasterBusyFlag = LPI2C_MSR_MBF_MASK, /*!< Master busy flag */
+ kLPI2C_MasterBusBusyFlag = LPI2C_MSR_BBF_MASK, /*!< Bus busy flag */
+
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kLPI2C_MasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
+ kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
+ kLPI2C_MasterPinLowTimeoutFlag | kLPI2C_MasterDataMatchFlag,
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kLPI2C_MasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
+ kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterFifoErrFlag,
+ /*! Errors to check for. */
+ kLPI2C_MasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag |
+ kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag
+};
+
+/*! @brief Direction of master and slave transfers. */
+typedef enum _lpi2c_direction
+{
+ kLPI2C_Write = 0U, /*!< Master transmit. */
+ kLPI2C_Read = 1U /*!< Master receive. */
+} lpi2c_direction_t;
+
+/*! @brief LPI2C pin configuration. */
+typedef enum _lpi2c_master_pin_config
+{
+ kLPI2C_2PinOpenDrain = 0x0U, /*!< LPI2C Configured for 2-pin open drain mode */
+ kLPI2C_2PinOutputOnly = 0x1U, /*!< LPI2C Configured for 2-pin output only mode (ultra-fast mode) */
+ kLPI2C_2PinPushPull = 0x2U, /*!< LPI2C Configured for 2-pin push-pull mode */
+ kLPI2C_4PinPushPull = 0x3U, /*!< LPI2C Configured for 4-pin push-pull mode */
+ kLPI2C_2PinOpenDrainWithSeparateSlave =
+ 0x4U, /*!< LPI2C Configured for 2-pin open drain mode with separate LPI2C slave */
+ kLPI2C_2PinOutputOnlyWithSeparateSlave =
+ 0x5U, /*!< LPI2C Configured for 2-pin output only mode(ultra-fast mode) with separate LPI2C slave */
+ kLPI2C_2PinPushPullWithSeparateSlave =
+ 0x6U, /*!< LPI2C Configured for 2-pin push-pull mode with separate LPI2C slave */
+ kLPI2C_4PinPushPullWithInvertedOutput = 0x7U /*!< LPI2C Configured for 4-pin push-pull mode(inverted outputs) */
+} lpi2c_master_pin_config_t;
+
+/*! @brief LPI2C master host request selection. */
+typedef enum _lpi2c_host_request_source
+{
+ kLPI2C_HostRequestExternalPin = 0x0U, /*!< Select the LPI2C_HREQ pin as the host request input */
+ kLPI2C_HostRequestInputTrigger = 0x1U, /*!< Select the input trigger as the host request input */
+} lpi2c_host_request_source_t;
+
+/*! @brief LPI2C master host request pin polarity configuration. */
+typedef enum _lpi2c_host_request_polarity
+{
+ kLPI2C_HostRequestPinActiveLow = 0x0U, /*!< Configure the LPI2C_HREQ pin active low */
+ kLPI2C_HostRequestPinActiveHigh = 0x1U /*!< Configure the LPI2C_HREQ pin active high */
+} lpi2c_host_request_polarity_t;
+
+/*!
+ * @brief Structure with settings to initialize the LPI2C master module.
+ *
+ * This structure holds configuration settings for the LPI2C peripheral. To initialize this
+ * structure to reasonable defaults, call the LPI2C_MasterGetDefaultConfig() function and
+ * pass a pointer to your configuration structure instance.
+ *
+ * The configuration structure can be made constant so it resides in flash.
+ */
+typedef struct _lpi2c_master_config
+{
+ bool enableMaster; /*!< Whether to enable master mode. */
+ bool enableDoze; /*!< Whether master is enabled in doze mode. */
+ bool debugEnable; /*!< Enable transfers to continue when halted in debug mode. */
+ bool ignoreAck; /*!< Whether to ignore ACK/NACK. */
+ lpi2c_master_pin_config_t pinConfig; /*!< The pin configuration option. */
+ uint32_t baudRate_Hz; /*!< Desired baud rate in Hertz. */
+ uint32_t busIdleTimeout_ns; /*!< Bus idle timeout in nanoseconds. Set to 0 to disable. */
+ uint32_t pinLowTimeout_ns; /*!< Pin low timeout in nanoseconds. Set to 0 to disable. */
+ uint8_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SDA pin. Set to 0 to disable. */
+ uint8_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SCL pin. Set to 0 to disable. */
+ struct
+ {
+ bool enable; /*!< Enable host request. */
+ lpi2c_host_request_source_t source; /*!< Host request source. */
+ lpi2c_host_request_polarity_t polarity; /*!< Host request pin polarity. */
+ } hostRequest; /*!< Host request options. */
+} lpi2c_master_config_t;
+
+/*! @brief LPI2C master data match configuration modes. */
+typedef enum _lpi2c_data_match_config_mode
+{
+ kLPI2C_MatchDisabled = 0x0U, /*!< LPI2C Match Disabled */
+ kLPI2C_1stWordEqualsM0OrM1 = 0x2U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0 OR MATCH1 */
+ kLPI2C_AnyWordEqualsM0OrM1 = 0x3U, /*!< LPI2C Match Enabled and any data word equals MATCH0 OR MATCH1 */
+ kLPI2C_1stWordEqualsM0And2ndWordEqualsM1 =
+ 0x4U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0, 2nd data equals MATCH1 */
+ kLPI2C_AnyWordEqualsM0AndNextWordEqualsM1 =
+ 0x5U, /*!< LPI2C Match Enabled and any data word equals MATCH0, next data equals MATCH1 */
+ kLPI2C_1stWordAndM1EqualsM0AndM1 =
+ 0x6U, /*!< LPI2C Match Enabled and 1st data word and MATCH0 equals MATCH0 and MATCH1 */
+ kLPI2C_AnyWordAndM1EqualsM0AndM1 =
+ 0x7U /*!< LPI2C Match Enabled and any data word and MATCH0 equals MATCH0 and MATCH1 */
+} lpi2c_data_match_config_mode_t;
+
+/*! @brief LPI2C master data match configuration structure. */
+typedef struct _lpi2c_match_config
+{
+ lpi2c_data_match_config_mode_t matchMode; /*!< Data match configuration setting. */
+ bool rxDataMatchOnly; /*!< When set to true, received data is ignored until a successful match. */
+ uint32_t match0; /*!< Match value 0. */
+ uint32_t match1; /*!< Match value 1. */
+} lpi2c_data_match_config_t;
+
+/* Forward declaration of the transfer descriptor and handle typedefs. */
+typedef struct _lpi2c_master_transfer lpi2c_master_transfer_t;
+typedef struct _lpi2c_master_handle lpi2c_master_handle_t;
+
+/*!
+ * @brief Master completion callback function pointer type.
+ *
+ * This callback is used only for the non-blocking master transfer API. Specify the callback you wish to use
+ * in the call to LPI2C_MasterTransferCreateHandle().
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param completionStatus Either kStatus_Success or an error code describing how the transfer completed.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_master_transfer_callback_t)(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ status_t completionStatus,
+ void *userData);
+
+/*!
+ * @brief Transfer option flags.
+ *
+ * @note These enumerations are intended to be OR'd together to form a bit mask of options for
+ * the #_lpi2c_master_transfer::flags field.
+ */
+enum _lpi2c_master_transfer_flags
+{
+ kLPI2C_TransferDefaultFlag = 0x00U, /*!< Transfer starts with a start signal, stops with a stop signal. */
+ kLPI2C_TransferNoStartFlag = 0x01U, /*!< Don't send a start condition, address, and sub address */
+ kLPI2C_TransferRepeatedStartFlag = 0x02U, /*!< Send a repeated start condition */
+ kLPI2C_TransferNoStopFlag = 0x04U, /*!< Don't send a stop condition. */
+};
+
+/*!
+ * @brief Non-blocking transfer descriptor structure.
+ *
+ * This structure is used to pass transaction parameters to the LPI2C_MasterTransferNonBlocking() API.
+ */
+struct _lpi2c_master_transfer
+{
+ uint32_t flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for
+ available options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */
+ uint16_t slaveAddress; /*!< The 7-bit slave address. */
+ lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. */
+ uint32_t subaddress; /*!< Sub address. Transferred MSB first. */
+ size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */
+ void *data; /*!< Pointer to data to transfer. */
+ size_t dataSize; /*!< Number of bytes to transfer. */
+};
+
+/*!
+ * @brief Driver handle for master non-blocking APIs.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_master_handle
+{
+ uint8_t state; /*!< Transfer state machine current state. */
+ uint16_t remainingBytes; /*!< Remaining byte count in current state. */
+ uint8_t *buf; /*!< Buffer pointer for current state. */
+ uint16_t commandBuffer[6]; /*!< LPI2C command sequence. When all 6 command words are used:
+ Start&addr&write[1 word] + subaddr[4 words] + restart&addr&read[1 word] */
+ lpi2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */
+ lpi2c_master_transfer_callback_t completionCallback; /*!< Callback function pointer. */
+ void *userData; /*!< Application data passed to callback. */
+};
+
+/*! @brief Typedef for master interrupt handler, used internally for LPI2C master interrupt and EDMA transactional APIs.
+ */
+typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, void *handle);
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_slave_driver
+ * @{
+ */
+
+/*!
+ * @brief LPI2C slave peripheral flags.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_SlaveRepeatedStartDetectFlag
+ * - #kLPI2C_SlaveStopDetectFlag
+ * - #kLPI2C_SlaveBitErrFlag
+ * - #kLPI2C_SlaveFifoErrFlag
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @note These enumerations are meant to be OR'd together to form a bit mask.
+ */
+enum _lpi2c_slave_flags
+{
+ kLPI2C_SlaveTxReadyFlag = LPI2C_SSR_TDF_MASK, /*!< Transmit data flag */
+ kLPI2C_SlaveRxReadyFlag = LPI2C_SSR_RDF_MASK, /*!< Receive data flag */
+ kLPI2C_SlaveAddressValidFlag = LPI2C_SSR_AVF_MASK, /*!< Address valid flag */
+ kLPI2C_SlaveTransmitAckFlag = LPI2C_SSR_TAF_MASK, /*!< Transmit ACK flag */
+ kLPI2C_SlaveRepeatedStartDetectFlag = LPI2C_SSR_RSF_MASK, /*!< Repeated start detect flag */
+ kLPI2C_SlaveStopDetectFlag = LPI2C_SSR_SDF_MASK, /*!< Stop detect flag */
+ kLPI2C_SlaveBitErrFlag = LPI2C_SSR_BEF_MASK, /*!< Bit error flag */
+ kLPI2C_SlaveFifoErrFlag = LPI2C_SSR_FEF_MASK, /*!< FIFO error flag */
+ kLPI2C_SlaveAddressMatch0Flag = LPI2C_SSR_AM0F_MASK, /*!< Address match 0 flag */
+ kLPI2C_SlaveAddressMatch1Flag = LPI2C_SSR_AM1F_MASK, /*!< Address match 1 flag */
+ kLPI2C_SlaveGeneralCallFlag = LPI2C_SSR_GCF_MASK, /*!< General call flag */
+ kLPI2C_SlaveBusyFlag = LPI2C_SSR_SBF_MASK, /*!< Master busy flag */
+ kLPI2C_SlaveBusBusyFlag = LPI2C_SSR_BBF_MASK, /*!< Bus busy flag */
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kLPI2C_SlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveFifoErrFlag,
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kLPI2C_SlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
+ kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
+ /*! Errors to check for. */
+ kLPI2C_SlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag
+};
+
+/*! @brief LPI2C slave address match options. */
+typedef enum _lpi2c_slave_address_match
+{
+ kLPI2C_MatchAddress0 = 0U, /*!< Match only address 0. */
+ kLPI2C_MatchAddress0OrAddress1 = 2U, /*!< Match either address 0 or address 1. */
+ kLPI2C_MatchAddress0ThroughAddress1 = 6U, /*!< Match a range of slave addresses from address 0 through address 1. */
+} lpi2c_slave_address_match_t;
+
+/*!
+ * @brief Structure with settings to initialize the LPI2C slave module.
+ *
+ * This structure holds configuration settings for the LPI2C slave peripheral. To initialize this
+ * structure to reasonable defaults, call the LPI2C_SlaveGetDefaultConfig() function and
+ * pass a pointer to your configuration structure instance.
+ *
+ * The configuration structure can be made constant so it resides in flash.
+ */
+typedef struct _lpi2c_slave_config
+{
+ bool enableSlave; /*!< Enable slave mode. */
+ uint8_t address0; /*!< Slave's 7-bit address. */
+ uint8_t address1; /*!< Alternate slave 7-bit address. */
+ lpi2c_slave_address_match_t addressMatchMode; /*!< Address matching options. */
+ bool filterDozeEnable; /*!< Enable digital glitch filter in doze mode. */
+ bool filterEnable; /*!< Enable digital glitch filter. */
+ bool enableGeneralCall; /*!< Enable general call address matching. */
+ struct
+ {
+ bool enableAck; /*!< Enables SCL clock stretching during slave-transmit address byte(s)
+ and slave-receiver address and data byte(s) to allow software to
+ write the Transmit ACK Register before the ACK or NACK is transmitted.
+ Clock stretching occurs when transmitting the 9th bit. When
+ enableAckSCLStall is enabled, there is no need to set either
+ enableRxDataSCLStall or enableAddressSCLStall. */
+ bool enableTx; /*!< Enables SCL clock stretching when the transmit data flag is set
+ during a slave-transmit transfer. */
+ bool enableRx; /*!< Enables SCL clock stretching when receive data flag is set during
+ a slave-receive transfer. */
+ bool enableAddress; /*!< Enables SCL clock stretching when the address valid flag is asserted. */
+ } sclStall;
+ bool ignoreAck; /*!< Continue transfers after a NACK is detected. */
+ bool enableReceivedAddressRead; /*!< Enable reading the address received address as the first byte of data. */
+ uint32_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SDA signal. Set to 0 to
+ disable. */
+ uint32_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SCL signal. Set to 0 to
+ disable. */
+ uint32_t dataValidDelay_ns; /*!< Width in nanoseconds of the data valid delay. */
+ uint32_t clockHoldTime_ns; /*!< Width in nanoseconds of the clock hold time. */
+} lpi2c_slave_config_t;
+
+/*!
+ * @brief Set of events sent to the callback for non blocking slave transfers.
+ *
+ * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together
+ * events is passed to LPI2C_SlaveTransferNonBlocking() in order to specify which events to enable.
+ * Then, when the slave callback is invoked, it is passed the current event through its @a transfer
+ * parameter.
+ *
+ * @note These enumerations are meant to be OR'd together to form a bit mask of events.
+ */
+typedef enum _lpi2c_slave_transfer_event
+{
+ kLPI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */
+ kLPI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit
+ (slave-transmitter role). */
+ kLPI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received
+ data (slave-receiver role). */
+ kLPI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */
+ kLPI2C_SlaveRepeatedStartEvent = 0x10U, /*!< A repeated start was detected. */
+ kLPI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected, completing the transfer. */
+
+ /*! Bit mask of all available events. */
+ kLPI2C_SlaveAllEvents = kLPI2C_SlaveAddressMatchEvent | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent |
+ kLPI2C_SlaveTransmitAckEvent | kLPI2C_SlaveRepeatedStartEvent | kLPI2C_SlaveCompletionEvent,
+} lpi2c_slave_transfer_event_t;
+
+/*! @brief LPI2C slave transfer structure */
+typedef struct _lpi2c_slave_transfer
+{
+ lpi2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */
+ uint8_t receivedAddress; /*!< Matching address send by master. */
+ uint8_t *data; /*!< Transfer buffer */
+ size_t dataSize; /*!< Transfer size */
+ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for
+ #kLPI2C_SlaveCompletionEvent. */
+ size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */
+} lpi2c_slave_transfer_t;
+
+/* Forward declaration. */
+typedef struct _lpi2c_slave_handle lpi2c_slave_handle_t;
+
+/*!
+ * @brief Slave event callback function pointer type.
+ *
+ * This callback is used only for the slave non-blocking transfer API. To install a callback,
+ * use the LPI2C_SlaveSetCallback() function after you have created a handle.
+ *
+ * @param base Base address for the LPI2C instance on which the event occurred.
+ * @param transfer Pointer to transfer descriptor containing values passed to and/or from the callback.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_slave_transfer_callback_t)(LPI2C_Type *base, lpi2c_slave_transfer_t *transfer, void *userData);
+
+/*!
+ * @brief LPI2C slave handle structure.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_slave_handle
+{
+ lpi2c_slave_transfer_t transfer; /*!< LPI2C slave transfer copy. */
+ bool isBusy; /*!< Whether transfer is busy. */
+ bool wasTransmit; /*!< Whether the last transfer was a transmit. */
+ uint32_t eventMask; /*!< Mask of enabled events. */
+ uint32_t transferredCount; /*!< Count of bytes transferred. */
+ lpi2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */
+ void *userData; /*!< Callback parameter passed to callback. */
+};
+
+/*! @} */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! Array to map LPI2C instance number to IRQ number, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern IRQn_Type const kLpi2cIrqs[];
+
+/*! Pointer to master IRQ handler for each instance, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern lpi2c_master_isr_t s_lpi2cMasterIsr;
+
+/*! Pointers to master handles for each instance, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern void *s_lpi2cMasterHandle[];
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return LPI2C instance number starting from 0.
+ */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base);
+
+/*!
+ * @addtogroup lpi2c_master_driver
+ * @{
+ */
+
+/*! @name Initialization and deinitialization */
+/*@{*/
+
+/*!
+ * @brief Provides a default configuration for the LPI2C master peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C master peripheral:
+ * @code
+ * masterConfig->enableMaster = true;
+ * masterConfig->debugEnable = false;
+ * masterConfig->ignoreAck = false;
+ * masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ * masterConfig->baudRate_Hz = 100000U;
+ * masterConfig->busIdleTimeout_ns = 0;
+ * masterConfig->pinLowTimeout_ns = 0;
+ * masterConfig->sdaGlitchFilterWidth_ns = 0;
+ * masterConfig->sclGlitchFilterWidth_ns = 0;
+ * masterConfig->hostRequest.enable = false;
+ * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+ * @endcode
+ *
+ * After calling this function, you can override any settings in order to customize the configuration,
+ * prior to initializing the master driver with LPI2C_MasterInit().
+ *
+ * @param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t.
+ */
+void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig);
+
+/*!
+ * @brief Initializes the LPI2C master peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user
+ * provided configuration. A software reset is performed prior to configuration.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of
+ * defaults
+ * that you can override.
+ * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors,
+ * filter widths, and timeout periods.
+ */
+void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C master peripheral.
+ *
+ * This function disables the LPI2C master peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+void LPI2C_MasterDeinit(LPI2C_Type *base);
+
+/*!
+ * @brief Configures LPI2C master data match feature.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param matchConfig Settings for the data match feature.
+ */
+void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *matchConfig);
+
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status);
+
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_CheckForBusyBus(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a software reset.
+ *
+ * Restores the LPI2C master peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+static inline void LPI2C_MasterReset(LPI2C_Type *base)
+{
+ base->MCR = LPI2C_MCR_RST_MASK;
+ base->MCR = 0;
+}
+
+/*!
+ * @brief Enables or disables the LPI2C module as master.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enable Pass true to enable or false to disable the specified LPI2C as master.
+ */
+static inline void LPI2C_MasterEnable(LPI2C_Type *base, bool enable)
+{
+ base->MCR = (base->MCR & ~LPI2C_MCR_MEN_MASK) | LPI2C_MCR_MEN(enable);
+}
+
+/*@}*/
+
+/*! @name Status */
+/*@{*/
+
+/*!
+ * @brief Gets the LPI2C master status flags.
+ *
+ * A bit mask with the state of all LPI2C master status flags is returned. For each flag, the corresponding bit
+ * in the return value is set if the flag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return State of the status flags:
+ * - 1: related status flag is set.
+ * - 0: related status flag is not set.
+ * @see _lpi2c_master_flags
+ */
+static inline uint32_t LPI2C_MasterGetStatusFlags(LPI2C_Type *base)
+{
+ return base->MSR;
+}
+
+/*!
+ * @brief Clears the LPI2C master status flag state.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_MasterEndOfPacketFlag
+ * - #kLPI2C_MasterStopDetectFlag
+ * - #kLPI2C_MasterNackDetectFlag
+ * - #kLPI2C_MasterArbitrationLostFlag
+ * - #kLPI2C_MasterFifoErrFlag
+ * - #kLPI2C_MasterPinLowTimeoutFlag
+ * - #kLPI2C_MasterDataMatchFlag
+ *
+ * Attempts to clear other flags has no effect.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of
+ * _lpi2c_master_flags enumerators OR'd together. You may pass the result of a previous call to
+ * LPI2C_MasterGetStatusFlags().
+ * @see _lpi2c_master_flags.
+ */
+static inline void LPI2C_MasterClearStatusFlags(LPI2C_Type *base, uint32_t statusMask)
+{
+ base->MSR = statusMask;
+}
+
+/*@}*/
+
+/*! @name Interrupts */
+/*@{*/
+
+/*!
+ * @brief Enables the LPI2C master interrupt requests.
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to enable. See _lpi2c_master_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_MasterEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->MIER |= interruptMask;
+}
+
+/*!
+ * @brief Disables the LPI2C master interrupt requests.
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to disable. See _lpi2c_master_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_MasterDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->MIER &= ~interruptMask;
+}
+
+/*!
+ * @brief Returns the set of currently enabled LPI2C master interrupt requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return A bitmask composed of _lpi2c_master_flags enumerators OR'd together to indicate the
+ * set of enabled interrupts.
+ */
+static inline uint32_t LPI2C_MasterGetEnabledInterrupts(LPI2C_Type *base)
+{
+ return base->MIER;
+}
+
+/*@}*/
+
+/*! @name DMA control */
+/*@{*/
+
+/*!
+ * @brief Enables or disables LPI2C master DMA requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enableTx Enable flag for transmit DMA request. Pass true for enable, false for disable.
+ * @param enableRx Enable flag for receive DMA request. Pass true for enable, false for disable.
+ */
+static inline void LPI2C_MasterEnableDMA(LPI2C_Type *base, bool enableTx, bool enableRx)
+{
+ base->MDER = LPI2C_MDER_TDDE(enableTx) | LPI2C_MDER_RDDE(enableRx);
+}
+
+/*!
+ * @brief Gets LPI2C master transmit data register address for DMA transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The LPI2C Master Transmit Data Register address.
+ */
+static inline uint32_t LPI2C_MasterGetTxFifoAddress(LPI2C_Type *base)
+{
+ return (uint32_t)&base->MTDR;
+}
+
+/*!
+ * @brief Gets LPI2C master receive data register address for DMA transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The LPI2C Master Receive Data Register address.
+ */
+static inline uint32_t LPI2C_MasterGetRxFifoAddress(LPI2C_Type *base)
+{
+ return (uint32_t)&base->MRDR;
+}
+
+/*@}*/
+
+/*! @name FIFO control */
+/*@{*/
+
+/*!
+ * @brief Sets the watermarks for LPI2C master FIFOs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txWords Transmit FIFO watermark value in words. The #kLPI2C_MasterTxReadyFlag flag is set whenever
+ * the number of words in the transmit FIFO is equal or less than @a txWords. Writing a value equal or
+ * greater than the FIFO size is truncated.
+ * @param rxWords Receive FIFO watermark value in words. The #kLPI2C_MasterRxReadyFlag flag is set whenever
+ * the number of words in the receive FIFO is greater than @a rxWords. Writing a value equal or greater
+ * than the FIFO size is truncated.
+ */
+static inline void LPI2C_MasterSetWatermarks(LPI2C_Type *base, size_t txWords, size_t rxWords)
+{
+ base->MFCR = LPI2C_MFCR_TXWATER(txWords) | LPI2C_MFCR_RXWATER(rxWords);
+}
+
+/*!
+ * @brief Gets the current number of words in the LPI2C master FIFOs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] txCount Pointer through which the current number of words in the transmit FIFO is returned.
+ * Pass NULL if this value is not required.
+ * @param[out] rxCount Pointer through which the current number of words in the receive FIFO is returned.
+ * Pass NULL if this value is not required.
+ */
+static inline void LPI2C_MasterGetFifoCounts(LPI2C_Type *base, size_t *rxCount, size_t *txCount)
+{
+ if (NULL != txCount)
+ {
+ *txCount = (base->MFSR & LPI2C_MFSR_TXCOUNT_MASK) >> LPI2C_MFSR_TXCOUNT_SHIFT;
+ }
+ if (NULL != rxCount)
+ {
+ *rxCount = (base->MFSR & LPI2C_MFSR_RXCOUNT_MASK) >> LPI2C_MFSR_RXCOUNT_SHIFT;
+ }
+}
+
+/*@}*/
+
+/*! @name Bus operations */
+/*@{*/
+
+/*!
+ * @brief Sets the I2C bus frequency for master transactions.
+ *
+ * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud
+ * rate. Do not call this function during a transfer, or the transfer is aborted.
+ *
+ * @note Please note that the second parameter is the clock frequency of LPI2C module, the third
+ * parameter means user configured bus baudrate, this implementation is different from other I2C drivers
+ * which use baudrate configuration as second parameter and source clock frequency as third parameter.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * @param baudRate_Hz Requested bus frequency in Hertz.
+ */
+void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz);
+
+/*!
+ * @brief Returns whether the bus is idle.
+ *
+ * Requires the master mode to be enabled.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval true Bus is busy.
+ * @retval false Bus is idle.
+ */
+static inline bool LPI2C_MasterGetBusIdleState(LPI2C_Type *base)
+{
+ return ((base->MSR & LPI2C_MSR_BBF_MASK) >> LPI2C_MSR_BBF_SHIFT) == 1U ? true : false;
+}
+
+/*!
+ * @brief Sends a START signal and slave address on the I2C bus.
+ *
+ * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
+ * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
+ * 7-bit address specified in the @a address parameter. Note that this function does not actually wait
+ * until the START and address are successfully sent on the bus before returning.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param address 7-bit slave device address, in bits [6:0].
+ * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * @retval kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir);
+
+/*!
+ * @brief Sends a repeated START signal and slave address on the I2C bus.
+ *
+ * This function is used to send a Repeated START signal when a transfer is already in progress. Like
+ * LPI2C_MasterStart(), it also sends the specified 7-bit address.
+ *
+ * @note This function exists primarily to maintain compatible APIs between LPI2C and I2C drivers,
+ * as well as to better document the intent of code that uses these APIs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param address 7-bit slave device address, in bits [6:0].
+ * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * @retval kStatus_Success Repeated START signal and address were successfully enqueued in the transmit FIFO.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+static inline status_t LPI2C_MasterRepeatedStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir)
+{
+ return LPI2C_MasterStart(base, address, dir);
+}
+
+/*!
+ * @brief Performs a polling send transfer on the I2C bus.
+ *
+ * Sends up to @a txSize number of bytes to the previously addressed slave device. The slave may
+ * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
+ * function returns #kStatus_LPI2C_Nak.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txBuff The pointer to the data to be transferred.
+ * @param txSize The length in bytes of the data to be transferred.
+ * @retval kStatus_Success Data was sent successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or over run.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize);
+
+/*!
+ * @brief Performs a polling receive transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param rxBuff The pointer to the data to be transferred.
+ * @param rxSize The length in bytes of the data to be transferred.
+ * @retval kStatus_Success Data was received successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize);
+
+/*!
+ * @brief Sends a STOP signal on the I2C bus.
+ *
+ * This function does not return until the STOP signal is seen on the bus, or an error occurs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterStop(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a master polling transfer on the I2C bus.
+ *
+ * @note The API does not return until the transfer succeeds or fails due
+ * to error happens during transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param transfer Pointer to the transfer structure.
+ * @retval kStatus_Success Data was received successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer);
+
+/*@}*/
+
+/*! @name Non-blocking */
+/*@{*/
+
+/*!
+ * @brief Creates a new handle for the LPI2C master non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called.
+ *
+ *
+ * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C master driver handle.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a non-blocking transaction on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param transfer The pointer to the transfer descriptor.
+ * @retval kStatus_Success The transaction was started successfully.
+ * @retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @brief Returns number of bytes transferred so far.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * @note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * LPI2C peripheral's IRQ priority.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @retval kStatus_Success A transaction was successfully aborted.
+ * @retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress.
+ */
+void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle);
+
+/*@}*/
+
+/*! @name IRQ handler */
+/*@{*/
+
+/*!
+ * @brief Reusable routine to handle master interrupts.
+ * @note This function does not need to be called unless you are reimplementing the
+ * nonblocking API's interrupt handler routines to add special functionality.
+ * @param base The LPI2C peripheral base address.
+ * @param lpi2cMasterHandle Pointer to the LPI2C master driver handle.
+ */
+void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, void *lpi2cMasterHandle);
+
+/*@}*/
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_slave_driver
+ * @{
+ */
+
+/*! @name Slave initialization and deinitialization */
+/*@{*/
+
+/*!
+ * @brief Provides a default configuration for the LPI2C slave peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C slave peripheral:
+ * @code
+ * slaveConfig->enableSlave = true;
+ * slaveConfig->address0 = 0U;
+ * slaveConfig->address1 = 0U;
+ * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ * slaveConfig->filterDozeEnable = true;
+ * slaveConfig->filterEnable = true;
+ * slaveConfig->enableGeneralCall = false;
+ * slaveConfig->sclStall.enableAck = false;
+ * slaveConfig->sclStall.enableTx = true;
+ * slaveConfig->sclStall.enableRx = true;
+ * slaveConfig->sclStall.enableAddress = true;
+ * slaveConfig->ignoreAck = false;
+ * slaveConfig->enableReceivedAddressRead = false;
+ * slaveConfig->sdaGlitchFilterWidth_ns = 0;
+ * slaveConfig->sclGlitchFilterWidth_ns = 0;
+ * slaveConfig->dataValidDelay_ns = 0;
+ * slaveConfig->clockHoldTime_ns = 0;
+ * @endcode
+ *
+ * After calling this function, override any settings to customize the configuration,
+ * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the @a
+ * address0 member of the configuration structure with the desired slave address.
+ *
+ * @param[out] slaveConfig User provided configuration structure that is set to default values. Refer to
+ * #lpi2c_slave_config_t.
+ */
+void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig);
+
+/*!
+ * @brief Initializes the LPI2C slave peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user
+ * provided configuration.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults
+ * that you can override.
+ * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths,
+ * data valid delay, and clock hold time.
+ */
+void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C slave peripheral.
+ *
+ * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+void LPI2C_SlaveDeinit(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a software reset of the LPI2C slave peripheral.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+static inline void LPI2C_SlaveReset(LPI2C_Type *base)
+{
+ base->SCR = LPI2C_SCR_RST_MASK;
+ base->SCR = 0;
+}
+
+/*!
+ * @brief Enables or disables the LPI2C module as slave.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enable Pass true to enable or false to disable the specified LPI2C as slave.
+ */
+static inline void LPI2C_SlaveEnable(LPI2C_Type *base, bool enable)
+{
+ base->SCR = (base->SCR & ~LPI2C_SCR_SEN_MASK) | LPI2C_SCR_SEN(enable);
+}
+
+/*@}*/
+
+/*! @name Slave status */
+/*@{*/
+
+/*!
+ * @brief Gets the LPI2C slave status flags.
+ *
+ * A bit mask with the state of all LPI2C slave status flags is returned. For each flag, the corresponding bit
+ * in the return value is set if the flag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return State of the status flags:
+ * - 1: related status flag is set.
+ * - 0: related status flag is not set.
+ * @see _lpi2c_slave_flags
+ */
+static inline uint32_t LPI2C_SlaveGetStatusFlags(LPI2C_Type *base)
+{
+ return base->SSR;
+}
+
+/*!
+ * @brief Clears the LPI2C status flag state.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_SlaveRepeatedStartDetectFlag
+ * - #kLPI2C_SlaveStopDetectFlag
+ * - #kLPI2C_SlaveBitErrFlag
+ * - #kLPI2C_SlaveFifoErrFlag
+ *
+ * Attempts to clear other flags has no effect.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of
+ * #_lpi2c_slave_flags enumerators OR'd together. You may pass the result of a previous call to
+ * LPI2C_SlaveGetStatusFlags().
+ * @see _lpi2c_slave_flags.
+ */
+static inline void LPI2C_SlaveClearStatusFlags(LPI2C_Type *base, uint32_t statusMask)
+{
+ base->SSR = statusMask;
+}
+
+/*@}*/
+
+/*! @name Slave interrupts */
+/*@{*/
+
+/*!
+ * @brief Enables the LPI2C slave interrupt requests.
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to enable. See #_lpi2c_slave_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_SlaveEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->SIER |= interruptMask;
+}
+
+/*!
+ * @brief Disables the LPI2C slave interrupt requests.
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to disable. See #_lpi2c_slave_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_SlaveDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->SIER &= ~interruptMask;
+}
+
+/*!
+ * @brief Returns the set of currently enabled LPI2C slave interrupt requests.
+ * @param base The LPI2C peripheral base address.
+ * @return A bitmask composed of #_lpi2c_slave_flags enumerators OR'd together to indicate the
+ * set of enabled interrupts.
+ */
+static inline uint32_t LPI2C_SlaveGetEnabledInterrupts(LPI2C_Type *base)
+{
+ return base->SIER;
+}
+
+/*@}*/
+
+/*! @name Slave DMA control */
+/*@{*/
+
+/*!
+ * @brief Enables or disables the LPI2C slave peripheral DMA requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enableAddressValid Enable flag for the address valid DMA request. Pass true for enable, false for disable.
+ * The address valid DMA request is shared with the receive data DMA request.
+ * @param enableRx Enable flag for the receive data DMA request. Pass true for enable, false for disable.
+ * @param enableTx Enable flag for the transmit data DMA request. Pass true for enable, false for disable.
+ */
+static inline void LPI2C_SlaveEnableDMA(LPI2C_Type *base, bool enableAddressValid, bool enableRx, bool enableTx)
+{
+ base->SDER = (base->SDER & ~(LPI2C_SDER_AVDE_MASK | LPI2C_SDER_RDDE_MASK | LPI2C_SDER_TDDE_MASK)) |
+ LPI2C_SDER_AVDE(enableAddressValid) | LPI2C_SDER_RDDE(enableRx) | LPI2C_SDER_TDDE(enableTx);
+}
+
+/*@}*/
+
+/*! @name Slave bus operations */
+/*@{*/
+
+/*!
+ * @brief Returns whether the bus is idle.
+ *
+ * Requires the slave mode to be enabled.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval true Bus is busy.
+ * @retval false Bus is idle.
+ */
+static inline bool LPI2C_SlaveGetBusIdleState(LPI2C_Type *base)
+{
+ return ((base->SSR & LPI2C_SSR_BBF_MASK) >> LPI2C_SSR_BBF_SHIFT) == 1U ? true : false;
+}
+
+/*!
+ * @brief Transmits either an ACK or NAK on the I2C bus in response to a byte from the master.
+ *
+ * Use this function to send an ACK or NAK when the #kLPI2C_SlaveTransmitAckFlag is asserted. This
+ * only happens if you enable the sclStall.enableAck field of the ::lpi2c_slave_config_t configuration
+ * structure used to initialize the slave peripheral.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param ackOrNack Pass true for an ACK or false for a NAK.
+ */
+static inline void LPI2C_SlaveTransmitAck(LPI2C_Type *base, bool ackOrNack)
+{
+ base->STAR = LPI2C_STAR_TXNACK(!ackOrNack);
+}
+
+/*!
+ * @brief Returns the slave address sent by the I2C master.
+ *
+ * This function should only be called if the #kLPI2C_SlaveAddressValidFlag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The 8-bit address matched by the LPI2C slave. Bit 0 contains the R/w direction bit, and
+ * the 7-bit slave address is in the upper 7 bits.
+ */
+static inline uint32_t LPI2C_SlaveGetReceivedAddress(LPI2C_Type *base)
+{
+ return base->SASR & LPI2C_SASR_RADDR_MASK;
+}
+
+/*!
+ * @brief Performs a polling send transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txBuff The pointer to the data to be transferred.
+ * @param txSize The length in bytes of the data to be transferred.
+ * @param[out] actualTxSize
+ * @return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize);
+
+/*!
+ * @brief Performs a polling receive transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param rxBuff The pointer to the data to be transferred.
+ * @param rxSize The length in bytes of the data to be transferred.
+ * @param[out] actualRxSize
+ * @return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize);
+
+/*@}*/
+
+/*! @name Slave non-blocking */
+/*@{*/
+
+/*!
+ * @brief Creates a new handle for the LPI2C slave non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called.
+ *
+ * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C slave driver handle.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_slave_handle_t *handle,
+ lpi2c_slave_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Starts accepting slave transfers.
+ *
+ * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing
+ * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
+ * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked
+ * from the interrupt context.
+ *
+ * The set of events received by the callback is customizable. To do so, set the @a eventMask parameter to
+ * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive.
+ * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need
+ * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
+ * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as
+ * a convenient way to enable all events.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ * @param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify
+ * which events to send to the callback. Other accepted values are 0 to get a default set of
+ * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events.
+ *
+ * @retval kStatus_Success Slave transfers were successfully started.
+ * @retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle.
+ */
+status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask);
+
+/*!
+ * @brief Gets the slave transfer status during a non-blocking transfer.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to i2c_slave_handle_t structure.
+ * @param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
+ * required.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress
+ */
+status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the slave non-blocking transfers.
+ * @note This API could be called at any time to stop slave for handling the bus events.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ * @retval kStatus_Success
+ * @retval #kStatus_LPI2C_Idle
+ */
+void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*@}*/
+
+/*! @name Slave IRQ handler */
+/*@{*/
+
+/*!
+ * @brief Reusable routine to handle slave interrupts.
+ * @note This function does not need to be called unless you are reimplementing the
+ * non blocking API's interrupt handler routines to add special functionality.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ */
+void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*@}*/
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _FSL_LPI2C_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c
new file mode 100644
index 0000000000..7e28c7e693
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c
@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c_edma.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
+#endif
+
+/* @brief Mask to align an address to 32 bytes. */
+#define ALIGN_32_MASK (0x1fU)
+
+/* ! @brief LPI2C master fifo commands. */
+enum _lpi2c_master_fifo_cmd
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum _lpi2c_transfer_states
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
+ * @param handle Master DMA driver handle.
+ * @return Number of command words.
+ */
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
+
+/*!
+ * @brief DMA completion callback.
+ * @param dmaHandle DMA channel handle for the channel that completed.
+ * @param userData User data associated with the channel handle. For this callback, the user data is the
+ * LPI2C DMA driver handle.
+ * @param isTransferDone Whether the DMA transfer has completed.
+ * @param tcds Number of TCDs that completed.
+ */
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
+
+/*!
+ * @brief LPI2C master edma transfer IRQ handle routine.
+ *
+ * This API handles the LPI2C bus error status and invoke callback if needed.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param lpi2cMasterEdmaHandle Pointer to the LPI2C master edma handle.
+ */
+static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+static uint32_t lpi2c_edma_RecSetting = 0x02;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Create a new handle for the LPI2C master DMA APIs.
+ *
+ * The creation of a handle is for use with the DMA APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
+ *
+ * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
+ * parameter is ignored and may be set to NULL.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
+ * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ edma_handle_t *rxDmaHandle,
+ edma_handle_t *txDmaHandle,
+ lpi2c_master_edma_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+ assert(rxDmaHandle != NULL);
+ assert(txDmaHandle != NULL);
+
+ /* Look up instance number */
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
+ /* in order to make the transfer API code simpler. */
+ handle->base = base;
+ handle->completionCallback = callback;
+ handle->userData = userData;
+ handle->rx = rxDmaHandle;
+ handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_lpi2cMasterHandle[instance] = handle;
+
+ /* Set LPI2C_MasterTransferEdmaHandleIRQ as LPI2C DMA IRQ handler */
+ s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+
+ /* Set DMA channel completion callbacks. */
+ EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
+ }
+}
+
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0;
+
+ /* Handle no start option. */
+ if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
+ }
+ }
+ else
+ {
+ /*
+ * Initial direction depends on whether a subaddress was provided, and of course the actual
+ * data transfer direction.
+ */
+ lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (xfer->subaddressSize != 0U)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
+ if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+
+ /* Read command. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when
+ the dataSize is larger than 0x100U, push multiple read commands to MTDR until dataSize is reached. */
+ size_t tmpRxSize = xfer->dataSize;
+ while (tmpRxSize != 0U)
+ {
+ if (tmpRxSize > 256U)
+ {
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+ }
+ }
+
+ return cmdCount;
+}
+
+/*!
+ * brief Performs a non-blocking DMA-based transaction on the I2C bus.
+ *
+ * The callback specified when the a handle was created is invoked when the transaction has
+ * completed.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ status_t result;
+
+ assert(handle != NULL);
+ assert(transfer != NULL);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ /* Check transfer data size in read operation. */
+ /* A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when the dataSize is larger
+ than 0x100U, push multiple read commands to MTDR until dataSize is reached. LPI2C edma transfer uses linked
+ descriptor to transfer command and data, the command buffer is stored in handle. Allocate 4 command words to
+ carry read command which can cover nearly all use cases. */
+ if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* We're now busy. */
+ handle->isBusy = true;
+
+ /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+ LPI2C_MasterEnableDMA(base, false, false);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ uint32_t commandCount = LPI2C_GenerateCommands(handle);
+
+ /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
+ if ((0U == commandCount) && (transfer->dataSize == 0U))
+ {
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, kStatus_Success, handle->userData);
+ }
+ return kStatus_Success;
+ }
+
+ /* Reset DMA channels. */
+ EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
+ }
+
+ /* Get a 32-byte aligned TCD pointer. */
+ edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
+
+ bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
+ bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
+
+ edma_transfer_config_t transferConfig = {0};
+ edma_tcd_t *linkTcd = NULL;
+
+ /* Set up data transmit. */
+ if (hasSendData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ transferConfig.srcAddr = (uint32_t)srcAddr;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if (commandCount != 0U)
+ {
+ /* Create a software TCD, which will be chained after the commands. */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+ linkTcd = tcd;
+ }
+ else
+ {
+ /* User is only transmitting data with no required commands, so this transfer can stand alone. */
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ }
+ else if (hasReceiveData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ /* Set up data receive. */
+ transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
+ transferConfig.destAddr = (uint32_t)srcAddr;
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
+ {
+ /* We can put this receive transfer on its own DMA channel. */
+ EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ else
+ {
+ /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
+ enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
+ and create another software TCD of transfering data and chain it onto the last TCD.
+ Notice that in this situation assume tx/rx uses same channel */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+
+ transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
+ transferConfig.destAddr = (uint32_t) & (base->MDER);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t);
+ transferConfig.majorLoopCounts = 1;
+
+ edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
+
+ EDMA_TcdReset(tcdSetRxClearTxDMA);
+ EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
+ linkTcd = tcdSetRxClearTxDMA;
+ }
+ }
+ else
+ {
+ /* No data to send */
+ }
+
+ /* Set up commands transfer. */
+ if (commandCount != 0U)
+ {
+ transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = commandCount;
+
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
+ }
+
+ /* Start DMA transfer. */
+ if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
+ {
+ EDMA_StartTransfer(handle->rx);
+ }
+
+ if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
+ {
+ EDMA_StartTransfer(handle->tx);
+ }
+
+ /* Enable DMA in both directions. This actually kicks of the transfer. */
+ LPI2C_MasterEnableDMA(base, true, true);
+
+ /* Enable all LPI2C master interrupts */
+ LPI2C_MasterEnableInterrupts(base,
+ (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
+ (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ uint32_t remaining = handle->transfer.dataSize;
+
+ /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
+ /* we do nothing and return the number of transferred bytes as zero. */
+ if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
+ {
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
+ }
+ else
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
+ }
+ }
+
+ *count = handle->transfer.dataSize - remaining;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * eDMA peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
+{
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ return kStatus_LPI2C_Idle;
+ }
+
+ /* Terminate DMA transfers. */
+ EDMA_AbortTransfer(handle->rx);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_AbortTransfer(handle->tx);
+ }
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Disable LPI2C interrupts. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* If master is still busy and has not send out stop signal yet. */
+ if ((LPI2C_MasterGetStatusFlags(base) &
+ ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Reset handle. */
+ handle->isBusy = false;
+
+ return kStatus_Success;
+}
+
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
+{
+ lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
+
+ if (NULL == handle)
+ {
+ return;
+ }
+
+ /* Check for errors. */
+ status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
+
+ /* Done with this transaction. */
+ handle->isBusy = false;
+
+ if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
+ {
+ /* Send a stop command to finalize the transfer. */
+ handle->base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Invoke callback. */
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(handle->base, handle, result, handle->userData);
+ }
+}
+
+static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
+{
+ assert(lpi2cMasterEdmaHandle != NULL);
+
+ lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+ status_t result = kStatus_Success;
+
+ /* Terminate DMA transfers. */
+ EDMA_AbortTransfer(handle->rx);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_AbortTransfer(handle->tx);
+ }
+
+ /* Done with this transaction. */
+ handle->isBusy = false;
+
+ /* Disable LPI2C interrupts. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Check error status */
+ if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
+ {
+ result = kStatus_LPI2C_PinLowTimeout;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
+ {
+ result = kStatus_LPI2C_ArbitrationLost;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
+ {
+ result = kStatus_LPI2C_Nak;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear error status. */
+ (void)LPI2C_MasterCheckAndClearError(base, status);
+
+ /* Send stop flag if needed */
+ if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
+ {
+ status = LPI2C_MasterGetStatusFlags(base);
+ /* If bus is still busy and the master has not generate stop flag */
+ if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
+ (uint32_t)kLPI2C_MasterBusBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ handle->base->MTDR = (uint32_t)kStopCmd;
+ }
+ }
+
+ /* Invoke callback. */
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h
new file mode 100644
index 0000000000..f579086af2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPI2C_EDMA_H_
+#define _FSL_LPI2C_EDMA_H_
+
+#include "fsl_lpi2c.h"
+#include "fsl_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C EDMA driver version. */
+#define FSL_LPI2C_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/*!
+ * @addtogroup lpi2c_master_edma_driver
+ * @{
+ */
+
+/* Forward declaration of the transfer descriptor and handle typedefs. */
+typedef struct _lpi2c_master_edma_handle lpi2c_master_edma_handle_t;
+
+/*!
+ * @brief Master DMA completion callback function pointer type.
+ *
+ * This callback is used only for the non-blocking master transfer API. Specify the callback you wish to use
+ * in the call to LPI2C_MasterCreateEDMAHandle().
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Handle associated with the completed transfer.
+ * @param completionStatus Either kStatus_Success or an error code describing how the transfer completed.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_master_edma_transfer_callback_t)(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ status_t completionStatus,
+ void *userData);
+
+/*!
+ * @brief Driver handle for master DMA APIs.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_master_edma_handle
+{
+ LPI2C_Type *base; /*!< LPI2C base pointer. */
+ bool isBusy; /*!< Transfer state machine current state. */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint16_t commandBuffer[10]; /*!< LPI2C command sequence. When all 10 command words are used:
+ Start&addr&write[1 word] + subaddr[4 words] + restart&addr&read[1 word] + receive&Size[4 words] */
+ lpi2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */
+ lpi2c_master_edma_transfer_callback_t completionCallback; /*!< Callback function pointer. */
+ void *userData; /*!< Application data passed to callback. */
+ edma_handle_t *rx; /*!< Handle for receive DMA channel. */
+ edma_handle_t *tx; /*!< Handle for transmit DMA channel. */
+ edma_tcd_t tcds[3]; /*!< Software TCD. Three are allocated to provide enough room to align to 32-bytes. */
+};
+
+/*! @} */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @addtogroup lpi2c_master_edma_driver
+ * @{
+ */
+
+/*! @name Master DMA */
+/*@{*/
+
+/*!
+ * @brief Create a new handle for the LPI2C master DMA APIs.
+ *
+ * The creation of a handle is for use with the DMA APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
+ *
+ * For devices where the LPI2C send and receive DMA requests are OR'd together, the @a txDmaHandle
+ * parameter is ignored and may be set to NULL.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C master driver handle.
+ * @param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
+ * @param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ edma_handle_t *rxDmaHandle,
+ edma_handle_t *txDmaHandle,
+ lpi2c_master_edma_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a non-blocking DMA-based transaction on the I2C bus.
+ *
+ * The callback specified when the @a handle was created is invoked when the transaction has
+ * completed.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param transfer The pointer to the transfer descriptor.
+ * @retval kStatus_Success The transaction was started successfully.
+ * @retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @brief Returns number of bytes transferred so far.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * @note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * eDMA peripheral's IRQ priority.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @retval kStatus_Success A transaction was successfully aborted.
+ * @retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle);
+
+/*@}*/
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _FSL_LPI2C_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h
new file mode 100644
index 0000000000..1b989326e2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __FSL_LPI2C_FREERTOS_H__
+#define __FSL_LPI2C_FREERTOS_H__
+
+#include "FreeRTOS.h"
+#include "portable.h"
+#include "semphr.h"
+
+#include "fsl_lpi2c.h"
+
+/*!
+ * @addtogroup lpi2c_freertos_driver LPI2C FreeRTOS Driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C FreeRTOS driver version. */
+#define FSL_LPI2C_FREERTOS_DRIVER_VERSION (MAKE_VERSION(2, 3, 2))
+/*@}*/
+
+/*!
+ * @cond RTOS_PRIVATE
+ * @brief LPI2C FreeRTOS handle
+ */
+typedef struct _lpi2c_rtos_handle
+{
+ LPI2C_Type *base; /*!< LPI2C base address */
+ lpi2c_master_handle_t drv_handle; /*!< Handle of the underlying driver, treated as opaque by the RTOS layer */
+ status_t async_status;
+ SemaphoreHandle_t mutex; /*!< Mutex to lock the handle during a trasfer */
+ SemaphoreHandle_t semaphore; /*!< Semaphore to notify and unblock task when transfer ends */
+} lpi2c_rtos_handle_t;
+/*! \endcond */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name LPI2C RTOS Operation
+ * @{
+ */
+
+/*!
+ * @brief Initializes LPI2C.
+ *
+ * This function initializes the LPI2C module and related RTOS context.
+ *
+ * @param handle The RTOS LPI2C handle, the pointer to an allocated space for RTOS context.
+ * @param base The pointer base address of the LPI2C instance to initialize.
+ * @param masterConfig Configuration structure to set-up LPI2C in master mode.
+ * @param srcClock_Hz Frequency of input clock of the LPI2C module.
+ * @return status of the operation.
+ */
+status_t LPI2C_RTOS_Init(lpi2c_rtos_handle_t *handle,
+ LPI2C_Type *base,
+ const lpi2c_master_config_t *masterConfig,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C.
+ *
+ * This function deinitializes the LPI2C module and related RTOS context.
+ *
+ * @param handle The RTOS LPI2C handle.
+ */
+status_t LPI2C_RTOS_Deinit(lpi2c_rtos_handle_t *handle);
+
+/*!
+ * @brief Performs I2C transfer.
+ *
+ * This function performs an I2C transfer using LPI2C module according to data given in the transfer structure.
+ *
+ * @param handle The RTOS LPI2C handle.
+ * @param transfer Structure specifying the transfer parameters.
+ * @return status of the operation.
+ */
+status_t LPI2C_RTOS_Transfer(lpi2c_rtos_handle_t *handle, lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* __FSL_LPI2C_FREERTOS_H__ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c
new file mode 100644
index 0000000000..fd28621951
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c
@@ -0,0 +1,2421 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpspi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpspi"
+#endif
+
+/*!
+ * @brief Default watermark values.
+ *
+ * The default watermarks are set to zero.
+ */
+enum _lpspi_default_watermarks
+{
+ kLpspiDefaultTxWatermark = 0,
+ kLpspiDefaultRxWatermark = 0,
+};
+
+/*
+ * <! Structure definition for variables that passed as parameters in LPSPI_MasterTransferBlocking.
+ * The structure is private.
+ */
+typedef struct _lpspi_transfer_blocking_param
+{
+ bool isTxMask;
+ bool isPcsContinuous;
+ uint8_t bytesEachWrite;
+ uint8_t bytesEachRead;
+ uint32_t rxRemainingByteCount;
+} lpspi_transfer_blocking_param_t;
+
+/*! @brief Typedef for master interrupt handler. */
+typedef void (*lpspi_master_isr_t)(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*lpspi_slave_isr_t)(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Configures the LPSPI peripheral chip select polarity.
+ *
+ * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and
+ * configures the Pcs signal to operate with the desired characteristic.
+ *
+ * @param base LPSPI peripheral address.
+ * @param pcs The particular peripheral chip select (parameter value is of type lpspi_which_pcs_t) for which we wish to
+ * apply the active high or active low characteristic.
+ * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of
+ * type lpspi_pcs_polarity_config_t.
+ */
+static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
+ lpspi_which_pcs_t pcs,
+ lpspi_pcs_polarity_config_t activeLowOrHigh);
+
+/*!
+ * @brief Combine the write data for 1 byte to 4 bytes.
+ * This is not a public API.
+ */
+static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap);
+
+/*!
+ * @brief Separate the read data for 1 byte to 4 bytes.
+ * This is not a public API.
+ */
+static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap);
+
+/*!
+ * @brief Wait for tx FIFO to be empty.
+ * This is not a public API.
+ * @param base LPSPI peripheral address.
+ * @return true for the tx FIFO is ready, false is not.
+ */
+static bool LPSPI_TxFifoReady(LPSPI_Type *base);
+
+/*!
+ * @brief Master fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief Master finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief Slave fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ * @brief Slave finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ * @brief LPSPI common interrupt handler.
+ *
+ * @param handle pointer to s_lpspiHandle which stores the transfer state.
+ */
+static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param);
+
+/*!
+ * @brief introduce function static bool LPSPI_MasterTransferWriteAllTxData.
+ * This function was deal with write all Txdata.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferWriteAllTxData(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferClearTCR.
+ * This function was deal with clear TCR.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferClearTCR(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferReadDataInFifo.
+ * This function was deal with read data in fifo.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferReadDataInFifo(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferReadDataInFifoNoBuf.
+ * This function was deal with no buf in fifo.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferReadDataInFifoNoBuf(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/
+static const uint8_t s_baudratePrescaler[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+/*! @brief Pointers to lpspi bases for each instance. */
+static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
+
+/*! @brief Pointers to lpspi IRQ number for each instance. */
+static const IRQn_Type s_lpspiIRQ[] = LPSPI_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to lpspi clocks for each instance. */
+static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS;
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+static const clock_ip_name_t s_LpspiPeriphClocks[] = LPSPI_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to lpspi handles for each instance. */
+static void *s_lpspiHandle[ARRAY_SIZE(s_lpspiBases)];
+
+/*! @brief Pointer to master IRQ handler for each instance. */
+static lpspi_master_isr_t s_lpspiMasterIsr;
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static lpspi_slave_isr_t s_lpspiSlaveIsr;
+/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
+volatile uint8_t g_lpspiDummyData[ARRAY_SIZE(s_lpspiBases)] = {0};
+
+/**********************************************************************************************************************
+ * Code
+ *********************************************************************************************************************/
+
+/*!
+ * brief Get the LPSPI instance from peripheral base address.
+ *
+ * param base LPSPI peripheral base address.
+ * return LPSPI instance.
+ */
+uint32_t LPSPI_GetInstance(LPSPI_Type *base)
+{
+ uint8_t instance = 0;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lpspiBases); instance++)
+ {
+ if (s_lpspiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lpspiBases));
+
+ return instance;
+}
+
+/*!
+ * brief Set up the dummy data.
+ *
+ * param base LPSPI peripheral address.
+ * param dummyData Data to be transferred when tx buffer is NULL.
+ * Note:
+ * This API has no effect when LPSPI in slave interrupt mode, because driver
+ * will set the TXMSK bit to 1 if txData is NULL, no data is loaded from transmit
+ * FIFO and output pin is tristated.
+ */
+void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData)
+{
+ uint32_t instance = LPSPI_GetInstance(base);
+ g_lpspiDummyData[instance] = dummyData;
+}
+
+/*!
+ * brief Initializes the LPSPI master.
+ *
+ * param base LPSPI peripheral address.
+ * param masterConfig Pointer to structure lpspi_master_config_t.
+ * param srcClock_Hz Module source input clock in Hertz
+ */
+void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(masterConfig != NULL);
+
+ uint32_t tcrPrescaleValue = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_EnableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Set LPSPI to master */
+ LPSPI_SetMasterSlaveMode(base, kLPSPI_Master);
+
+ /* Set specific PCS to active high or low */
+ LPSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow);
+
+ /* Set Configuration Register 1 related setting.*/
+ base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL_MASK |
+ LPSPI_CFGR1_SAMPLE_MASK)) |
+ LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) |
+ LPSPI_CFGR1_NOSTALL(0) | LPSPI_CFGR1_SAMPLE((uint32_t)masterConfig->enableInputDelay);
+
+ /* Set baudrate and delay times*/
+ (void)LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue);
+
+ /* Set default watermarks */
+ LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark);
+
+ /* Set Transmit Command Register*/
+ base->TCR = LPSPI_TCR_CPOL(masterConfig->cpol) | LPSPI_TCR_CPHA(masterConfig->cpha) |
+ LPSPI_TCR_LSBF(masterConfig->direction) | LPSPI_TCR_FRAMESZ(masterConfig->bitsPerFrame - 1U) |
+ LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs);
+
+ LPSPI_Enable(base, true);
+
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz);
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz);
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->betweenTransferDelayInNanoSec, kLPSPI_BetweenTransfer,
+ srcClock_Hz);
+
+ LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
+}
+
+/*!
+ * brief Sets the lpspi_master_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_MasterInit().
+ * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified
+ * before calling the LPSPI_MasterInit().
+ * Example:
+ * code
+ * lpspi_master_config_t masterConfig;
+ * LPSPI_MasterGetDefaultConfig(&masterConfig);
+ * endcode
+ * param masterConfig pointer to lpspi_master_config_t structure
+ */
+void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig)
+{
+ assert(masterConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->baudRate = 500000;
+ masterConfig->bitsPerFrame = 8;
+ masterConfig->cpol = kLPSPI_ClockPolarityActiveHigh;
+ masterConfig->cpha = kLPSPI_ClockPhaseFirstEdge;
+ masterConfig->direction = kLPSPI_MsbFirst;
+
+ masterConfig->pcsToSckDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+ masterConfig->lastSckToPcsDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+ masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+
+ masterConfig->whichPcs = kLPSPI_Pcs0;
+ masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow;
+
+ masterConfig->pinCfg = kLPSPI_SdiInSdoOut;
+ masterConfig->dataOutConfig = kLpspiDataOutRetained;
+
+ masterConfig->enableInputDelay = false;
+}
+
+/*!
+ * brief LPSPI slave configuration.
+ *
+ * param base LPSPI peripheral address.
+ * param slaveConfig Pointer to a structure lpspi_slave_config_t.
+ */
+void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig != NULL);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_EnableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ LPSPI_SetMasterSlaveMode(base, kLPSPI_Slave);
+
+ LPSPI_SetOnePcsPolarity(base, slaveConfig->whichPcs, slaveConfig->pcsActiveHighOrLow);
+
+ base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK)) |
+ LPSPI_CFGR1_OUTCFG(slaveConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(slaveConfig->pinCfg);
+
+ LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark);
+
+ base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) |
+ LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1U);
+
+ /* This operation will set the dummy data for edma transfer, no effect in interrupt way. */
+ LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
+
+ LPSPI_Enable(base, true);
+}
+
+/*!
+ * brief Sets the lpspi_slave_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_SlaveInit().
+ * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified
+ * before calling the LPSPI_SlaveInit().
+ * Example:
+ * code
+ * lpspi_slave_config_t slaveConfig;
+ * LPSPI_SlaveGetDefaultConfig(&slaveConfig);
+ * endcode
+ * param slaveConfig pointer to lpspi_slave_config_t structure.
+ */
+void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->bitsPerFrame = 8; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ slaveConfig->cpol = kLPSPI_ClockPolarityActiveHigh; /*!< Clock polarity. */
+ slaveConfig->cpha = kLPSPI_ClockPhaseFirstEdge; /*!< Clock phase. */
+ slaveConfig->direction = kLPSPI_MsbFirst; /*!< MSB or LSB data shift direction. */
+
+ slaveConfig->whichPcs = kLPSPI_Pcs0; /*!< Desired Peripheral Chip Select (pcs) */
+ slaveConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; /*!< Desired PCS active high or low */
+
+ slaveConfig->pinCfg = kLPSPI_SdiInSdoOut;
+ slaveConfig->dataOutConfig = kLpspiDataOutRetained;
+}
+
+/*!
+ * brief Restores the LPSPI peripheral to reset state. Note that this function
+ * sets all registers to reset state. As a result, the LPSPI module can't work after calling
+ * this API.
+ * param base LPSPI peripheral address.
+ */
+void LPSPI_Reset(LPSPI_Type *base)
+{
+ /* Reset all internal logic and registers, except the Control Register. Remains set until cleared by software.*/
+ base->CR |= LPSPI_CR_RST_MASK;
+
+ /* Software reset doesn't reset the CR, so manual reset the FIFOs */
+ base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK;
+
+ /* Master logic is not reset and module is disabled.*/
+ base->CR = 0x00U;
+}
+
+/*!
+ * brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock.
+ * param base LPSPI peripheral address.
+ */
+void LPSPI_Deinit(LPSPI_Type *base)
+{
+ /* Reset to default value */
+ LPSPI_Reset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_DisableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_DisableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
+ lpspi_which_pcs_t pcs,
+ lpspi_pcs_polarity_config_t activeLowOrHigh)
+{
+ uint32_t cfgr1Value = 0;
+ /* Clear the PCS polarity bit */
+ cfgr1Value = base->CFGR1 & ~(1UL << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs));
+
+ /* Configure the PCS polarity bit according to the activeLowOrHigh setting */
+ base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs));
+}
+
+/*!
+ * brief Sets the LPSPI baud rate in bits per second.
+ *
+ * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest
+ * possible baud rate without exceeding the desired baud rate and returns the
+ * calculated baud rate in bits-per-second. It requires the caller to provide
+ * the frequency of the module source clock (in Hertz). Note that the baud rate
+ * does not go into effect until the Transmit Control Register (TCR) is programmed
+ * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue
+ * parameter for later programming in the TCR. The higher level
+ * peripheral driver should alert the user of an out of range baud rate input.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * param base LPSPI peripheral address.
+ * param baudRate_Bps The desired baud rate in bits per second.
+ * param srcClock_Hz Module source input clock in Hertz.
+ * param tcrPrescaleValue The TCR prescale value needed to program the TCR.
+ * return The actual calculated baud rate. This function may also return a "0" if the
+ * LPSPI is not configured for master mode or if the LPSPI module is not disabled.
+ */
+
+uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base,
+ uint32_t baudRate_Bps,
+ uint32_t srcClock_Hz,
+ uint32_t *tcrPrescaleValue)
+{
+ assert(tcrPrescaleValue != NULL);
+
+ /* For master mode configuration only, if slave mode detected, return 0.
+ * Also, the LPSPI module needs to be disabled first, if enabled, return 0
+ */
+ if ((!LPSPI_IsMaster(base)) || ((base->CR & LPSPI_CR_MEN_MASK) != 0U))
+ {
+ return 0U;
+ }
+
+ uint32_t prescaler, bestPrescaler;
+ uint32_t scaler, bestScaler;
+ uint32_t realBaudrate, bestBaudrate;
+ uint32_t diff, min_diff;
+ uint32_t desiredBaudrate = baudRate_Bps;
+
+ /* find combination of prescaler and scaler resulting in baudrate closest to the
+ * requested value
+ */
+ min_diff = 0xFFFFFFFFU;
+
+ /* Set to maximum divisor value bit settings so that if baud rate passed in is less
+ * than the minimum possible baud rate, then the SPI will be configured to the lowest
+ * possible baud rate
+ */
+ bestPrescaler = 7;
+ bestScaler = 255;
+
+ bestBaudrate = 0; /* required to avoid compilation warning */
+
+ /* In all for loops, if min_diff = 0, the exit for loop*/
+ for (prescaler = 0U; prescaler < 8U; prescaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ for (scaler = 0U; scaler < 256U; scaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ realBaudrate = (srcClock_Hz / (s_baudratePrescaler[prescaler] * (scaler + 2U)));
+
+ /* calculate the baud rate difference based on the conditional statement
+ * that states that the calculated baud rate must not exceed the desired baud rate
+ */
+ if (desiredBaudrate >= realBaudrate)
+ {
+ diff = desiredBaudrate - realBaudrate;
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestPrescaler = prescaler;
+ bestScaler = scaler;
+ bestBaudrate = realBaudrate;
+ }
+ }
+ }
+ }
+
+ /* Write the best baud rate scalar to the CCR.
+ * Note, no need to check for error since we've already checked to make sure the module is
+ * disabled and in master mode. Also, there is a limit on the maximum divider so we will not
+ * exceed this.
+ */
+#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1
+ /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0
+ The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET]
+ So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */
+ base->CCR = base->CCR | LPSPI_CCR_DBT((base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT) |
+ LPSPI_CCR_SCKDIV(bestScaler);
+#else
+ base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler);
+#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */
+
+ /* return the best prescaler value for user to use later */
+ *tcrPrescaleValue = bestPrescaler;
+
+ /* return the actual calculated baud rate */
+ return bestBaudrate;
+}
+
+/*!
+ * brief Manually configures a specific LPSPI delay parameter (module must be disabled to
+ * change the delay values).
+ *
+ * This function configures the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay along with the delay value.
+ * This allows the user to directly set the delay values if they have
+ * pre-calculated them or if they simply wish to manually increment the value.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * param base LPSPI peripheral address.
+ * param scaler The 8-bit delay value 0x00 to 0xFF (255).
+ * param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t.
+ */
+void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay)
+{
+ /*These settings are only relevant in master mode */
+#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1
+ /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0
+ The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET]
+ So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */
+ uint32_t dbt = (base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT;
+ uint32_t sckdiv = (base->CCR1 & LPSPI_CCR1_SCKHLD_MASK) >> LPSPI_CCR1_SCKHLD_SHIFT;
+ sckdiv += (base->CCR1 & LPSPI_CCR1_SCKSET_MASK) >> LPSPI_CCR1_SCKSET_SHIFT;
+ switch (whichDelay)
+ {
+ case kLPSPI_PcsToSck:
+ base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler) | LPSPI_CCR_DBT(dbt) |
+ LPSPI_CCR_SCKDIV(sckdiv);
+
+ break;
+ case kLPSPI_LastSckToPcs:
+ base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler) | LPSPI_CCR_DBT(dbt) |
+ LPSPI_CCR_SCKDIV(sckdiv);
+
+ break;
+ case kLPSPI_BetweenTransfer:
+ base->CCR = base->CCR | LPSPI_CCR_DBT(scaler) | LPSPI_CCR_SCKDIV(sckdiv);
+#else
+ switch (whichDelay)
+ {
+ case kLPSPI_PcsToSck:
+ base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler);
+
+ break;
+ case kLPSPI_LastSckToPcs:
+ base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler);
+
+ break;
+ case kLPSPI_BetweenTransfer:
+ base->CCR = (base->CCR & (~LPSPI_CCR_DBT_MASK)) | LPSPI_CCR_DBT(scaler);
+#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Calculates the delay based on the desired delay input in nanoseconds (module must be
+ * disabled to change the delay values).
+ *
+ * This function calculates the values for the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay and the desired delay value in
+ * nano-seconds. The function calculates the value needed for the desired delay parameter
+ * and returns the actual calculated delay because an exact delay match may not be possible. In this
+ * case, the closest match is calculated without going below the desired delay value input.
+ * It is possible to input a very large delay value that exceeds the capability of the part, in
+ * which case the maximum supported delay is returned. It is up to the higher level
+ * peripheral driver to alert the user of an out of range delay input.
+ *
+ * Note that the LPSPI module must be configured for master mode before configuring this. And note that
+ * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler).
+ *
+ * param base LPSPI peripheral address.
+ * param delayTimeInNanoSec The desired delay value in nano-seconds.
+ * param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t.
+ * param srcClock_Hz Module source input clock in Hertz.
+ * return actual Calculated delay value in nano-seconds.
+ */
+uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base,
+ uint32_t delayTimeInNanoSec,
+ lpspi_delay_type_t whichDelay,
+ uint32_t srcClock_Hz)
+{
+ uint64_t realDelay, bestDelay;
+ uint32_t scaler, bestScaler;
+ uint32_t diff, min_diff;
+ uint64_t initialDelayNanoSec;
+ uint32_t clockDividedPrescaler;
+
+ /* For delay between transfer, an additional scaler value is needed */
+ uint32_t additionalScaler = 0;
+
+ /*As the RM note, the LPSPI baud rate clock is itself divided by the PRESCALE setting, which can vary between
+ * transfers.*/
+ clockDividedPrescaler =
+ srcClock_Hz / s_baudratePrescaler[(base->TCR & LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT];
+
+ /* Find combination of prescaler and scaler resulting in the delay closest to the requested value.*/
+ min_diff = 0xFFFFFFFFU;
+
+ /* Initialize scaler to max value to generate the max delay */
+ bestScaler = 0xFFU;
+
+ /* Calculate the initial (min) delay and maximum possible delay based on the specific delay as
+ * the delay divisors are slightly different based on which delay we are configuring.
+ */
+ if (whichDelay == kLPSPI_BetweenTransfer)
+ {
+ /* First calculate the initial, default delay, note min delay is 2 clock cycles. Due to large size of
+ calculated values (uint64_t), we need to break up the calculation into several steps to ensure
+ accurate calculated results
+ */
+ initialDelayNanoSec = 1000000000U;
+ initialDelayNanoSec *= 2U;
+ initialDelayNanoSec /= clockDividedPrescaler;
+
+ /* Calculate the maximum delay */
+ bestDelay = 1000000000U;
+ bestDelay *= 257U; /* based on DBT+2, or 255 + 2 */
+ bestDelay /= clockDividedPrescaler;
+
+ additionalScaler = 1U;
+ }
+ else
+ {
+ /* First calculate the initial, default delay, min delay is 1 clock cycle. Due to large size of calculated
+ values (uint64_t), we need to break up the calculation into several steps to ensure accurate calculated
+ results.
+ */
+ initialDelayNanoSec = 1000000000U;
+ initialDelayNanoSec /= clockDividedPrescaler;
+
+ /* Calculate the maximum delay */
+ bestDelay = 1000000000U;
+ bestDelay *= 256U; /* based on SCKPCS+1 or PCSSCK+1, or 255 + 1 */
+ bestDelay /= clockDividedPrescaler;
+
+ additionalScaler = 0U;
+ }
+
+ /* If the initial, default delay is already greater than the desired delay, then
+ * set the delay to their initial value (0) and return the delay. In other words,
+ * there is no way to decrease the delay value further.
+ */
+ if (initialDelayNanoSec >= delayTimeInNanoSec)
+ {
+ LPSPI_MasterSetDelayScaler(base, 0, whichDelay);
+ return (uint32_t)initialDelayNanoSec;
+ }
+
+ /* If min_diff = 0, the exit for loop */
+ for (scaler = 0U; scaler < 256U; scaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ /* Calculate the real delay value as we cycle through the scaler values.
+ Due to large size of calculated values (uint64_t), we need to break up the
+ calculation into several steps to ensure accurate calculated results
+ */
+ realDelay = 1000000000U;
+ realDelay *= ((uint64_t)scaler + 1UL + (uint64_t)additionalScaler);
+ realDelay /= clockDividedPrescaler;
+
+ /* calculate the delay difference based on the conditional statement
+ * that states that the calculated delay must not be less then the desired delay
+ */
+ if (realDelay >= delayTimeInNanoSec)
+ {
+ diff = (uint32_t)(realDelay - (uint64_t)delayTimeInNanoSec);
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestScaler = scaler;
+ bestDelay = realDelay;
+ }
+ }
+ }
+
+ /* write the best scaler value for the delay */
+ LPSPI_MasterSetDelayScaler(base, bestScaler, whichDelay);
+
+ /* return the actual calculated delay value (in ns) */
+ return (uint32_t)bestDelay;
+}
+
+/*Transactional APIs -- Master*/
+
+/*!
+ * brief Initializes the LPSPI master handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+
+ * param base LPSPI peripheral address.
+ * param handle LPSPI handle pointer to lpspi_master_handle_t.
+ * param callback DSPI callback.
+ * param userData callback function parameter.
+ */
+void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base,
+ lpspi_master_handle_t *handle,
+ lpspi_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
+
+ /* Set irq handler. */
+ s_lpspiMasterIsr = LPSPI_MasterTransferHandleIRQ;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+/*!
+ * brief Check the argument for transfer .
+ *
+ * param base LPSPI peripheral address.
+ * param transfer the transfer struct to be used.
+ * param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer
+ * return Return true for right and false for wrong.
+ */
+bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma)
+{
+ assert(transfer != NULL);
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+ /* If the transfer count is zero, then return immediately.*/
+ if (transfer->dataSize == 0U)
+ {
+ return false;
+ }
+
+ /* If both send buffer and receive buffer is null */
+ if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData)))
+ {
+ return false;
+ }
+
+ /*The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4 .
+ *For bytesPerFrame greater than 4 situation:
+ *the transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4 ,
+ *otherwise , the transfer data size can be integer multiples of bytesPerFrame.
+ */
+ if (bytesPerFrame <= 4U)
+ {
+ if ((transfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((bytesPerFrame % 4U) != 0U)
+ {
+ if (transfer->dataSize != bytesPerFrame)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((transfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return false;
+ }
+ }
+ }
+
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((transfer->txData != NULL) && (transfer->rxData != NULL))
+ {
+ return false;
+ }
+ if (NULL == transfer->txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ }
+
+ if (isEdma && ((bytesPerFrame % 4U) == 3U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool LPSPI_MasterTransferWriteAllTxData(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams)
+{
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ uint32_t txRemainingByteCount = transfer->dataSize;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ uint32_t wordToSend =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+ uint32_t rxFifoMaxBytes = MIN(bytesPerFrame, 4U) * LPSPI_GetRxFifoSize(base);
+ uint32_t readData;
+ /*Write the TX data until txRemainingByteCount is equal to 0 */
+ while (txRemainingByteCount > 0U)
+ {
+ if (txRemainingByteCount < (stateParams->bytesEachWrite))
+ {
+ (stateParams->bytesEachWrite) = (uint8_t)txRemainingByteCount;
+ }
+
+ /*Wait until TX FIFO is not full*/
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes) != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+
+ /* To prevent rxfifo overflow, ensure transmitting and receiving are executed in parallel */
+ if (((NULL == (transfer->rxData)) ||
+ ((stateParams->rxRemainingByteCount) - txRemainingByteCount) < rxFifoMaxBytes))
+ {
+ if (stateParams->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared
+ by hardware every time when TCR[FRAMESZ] bit of data is transfered.
+ In this case TCR[TXMSK] should be set to initiate each transfer. */
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ if (stateParams->isPcsContinuous && (txRemainingByteCount == bytesPerFrame))
+ {
+ /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should
+ * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ
+ * of data will be received. */
+ base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK);
+ }
+ txRemainingByteCount -= bytesPerFrame;
+ }
+ else
+ {
+ if ((transfer->txData) != NULL)
+ {
+ wordToSend = LPSPI_CombineWriteData((transfer->txData), (stateParams->bytesEachWrite), isByteSwap);
+ (transfer->txData) += (stateParams->bytesEachWrite);
+ }
+ /* Otherwise push data to tx FIFO to initiate transfer */
+ LPSPI_WriteData(base, wordToSend);
+ txRemainingByteCount -= (stateParams->bytesEachWrite);
+ }
+ }
+
+ /* Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun. */
+ if (((transfer->rxData) != NULL) && ((stateParams->rxRemainingByteCount) != 0U))
+ {
+ /* To ensure parallel execution in 3-wire mode, after writting 1 to TXMSK to generate clock of
+ bytesPerFrame's data wait until bytesPerFrame's data is received. */
+ while ((stateParams->isTxMask) && (LPSPI_GetRxFifoCount(base) == 0U))
+ {
+ }
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+ if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead))
+ {
+ (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount);
+ }
+
+ LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap);
+ (transfer->rxData) += (stateParams->bytesEachRead);
+
+ (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead);
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ }
+ }
+ return true;
+}
+
+static bool LPSPI_MasterTransferClearTCR(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams)
+{
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK));
+ return true;
+}
+
+static bool LPSPI_MasterTransferReadDataInFifo(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams)
+{
+ uint32_t readData;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ while ((stateParams->rxRemainingByteCount) > 0U)
+ {
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+
+ if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead))
+ {
+ (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount);
+ }
+
+ LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap);
+ (transfer->rxData) += (stateParams->bytesEachRead);
+
+ (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead);
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ }
+ return true;
+}
+
+static bool LPSPI_MasterTransferReadDataInFifoNoBuf(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams)
+{
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) && (--waitTimes != 0U))
+#else
+ while ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ return true;
+}
+
+/*!
+ * brief LPSPI master transfer data using a polling method.
+ *
+ * This function transfers data using a polling method. This is a blocking function, which does not return until all
+ * transfers have been completed.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer)
+{
+ assert(transfer != NULL);
+
+ /* Check that LPSPI is not busy.*/
+ if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ModuleBusyFlag) != 0U)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+
+ /* Variables */
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+ lpspi_transfer_blocking_param_t stateParams;
+ (void)memset(&stateParams, 0, sizeof(stateParams));
+
+ stateParams.isTxMask = false;
+ stateParams.rxRemainingByteCount = transfer->dataSize;
+ /*The TX and RX FIFO sizes are always the same*/
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ /* No need to configure PCS continous if the transfer byte count is smaller than frame size */
+ stateParams.isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) &&
+ (bytesPerFrame < transfer->dataSize));
+
+ /* Mask tx data in half duplex mode */
+ if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) &&
+ (transfer->txData == NULL))
+ {
+ stateParams.isTxMask = true;
+ }
+
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ LPSPI_Enable(base, true);
+
+ /* Configure transfer control register. */
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK |
+ LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_PCS(whichPcs);
+
+ /*TCR is also shared the FIFO, so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* PCS should be configured separately from the other bits, otherwise it will not take effect. */
+ base->TCR |= LPSPI_TCR_CONT(stateParams.isPcsContinuous) | LPSPI_TCR_CONTC(stateParams.isPcsContinuous) |
+ LPSPI_TCR_RXMSK(NULL == transfer->rxData);
+
+ /*TCR is also shared the FIFO, so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (bytesPerFrame <= 4U)
+ {
+ stateParams.bytesEachWrite = (uint8_t)bytesPerFrame;
+ stateParams.bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ stateParams.bytesEachWrite = 4U;
+ stateParams.bytesEachRead = 4U;
+ }
+
+ if (false == LPSPI_MasterTransferWriteAllTxData(base, transfer, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (stateParams.isPcsContinuous && !stateParams.isTxMask)
+ {
+ /* In PCS continous mode(TCR[CONT]), after write all the data in TX FIFO, TCR[CONTC] and TCR[CONT] should be
+ cleared to de-assert the PCS. Note that TCR register also use the TX FIFO. Also CONTC should be cleared when
+ tx is not masked, otherwise written to TCR register with TXMSK bit wet will initiate a new transfer. */
+ if (false == LPSPI_MasterTransferClearTCR(base, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+
+ /*Read out the RX data in FIFO*/
+ if (transfer->rxData != NULL)
+ {
+ if (false == LPSPI_MasterTransferReadDataInFifo(base, transfer, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+ else
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
+ if (false == LPSPI_MasterTransferReadDataInFifoNoBuf(base, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI master transfer data using an interrupt method.
+ *
+ * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Flush FIFO, clear status, disable all the interrupts. */
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* Variables */
+ bool isRxMask = false;
+ uint8_t txWatermark;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t tmpTimes;
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+ handle->writeTcrInIsr = false;
+ handle->bytesPerFrame = (uint16_t)((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ /* No need to configure PCS continous if the transfer byte count is smaller than frame size */
+ bool isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) &&
+ (transfer->dataSize > handle->bytesPerFrame));
+ handle->writeRegRemainingTimes =
+ (transfer->dataSize / (uint32_t)handle->bytesPerFrame) * (((uint32_t)handle->bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+ handle->isPcsContinuous = isPcsContinuous;
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (handle->bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)handle->bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+ }
+
+ /*Set the RX and TX watermarks to reduce the ISR times.*/
+ if (handle->fifoSize > 1U)
+ {
+ txWatermark = 1U;
+ handle->rxWatermark = handle->fifoSize - 2U;
+ }
+ else
+ {
+ txWatermark = 0U;
+ handle->rxWatermark = 0U;
+ }
+ LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
+
+ /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0;
+ }
+
+ /* Mask tx data in half duplex mode since the tx/rx share the same pin, so that the data received from slave is not
+ * interfered. */
+ if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) &&
+ (handle->txData == NULL))
+ {
+ handle->isTxMask = true;
+ }
+
+ /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* Configure transfer control register. */
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK |
+ LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_PCS(whichPcs);
+
+ /*TCR is also shared the FIFO , so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* PCS should be configured separately from the other bits, otherwise it will not take effect. */
+ base->TCR |= LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(isPcsContinuous) | LPSPI_TCR_RXMSK(isRxMask);
+
+ /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
+ * and you should also enable the INTMUX interupt in your application.
+ */
+ (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
+
+ /*TCR is also shared the FIFO , so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (handle->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by
+ hardware every time when TCR[FRAMESZ] bit of data is transfered. In this case TCR[TXMSK] should be set to
+ initiate each transfer. */
+
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ /* Fill up the TX data in FIFO to initiate transfer */
+ LPSPI_MasterTransferFillUpTxFifo(base, handle);
+ }
+
+ /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
+ * The IRQ handler will get the status of RX and TX interrupt flags.
+ */
+ if (handle->rxData != NULL)
+ {
+ if (handle->isTxMask)
+ {
+ /* if tx data is masked, transfer is initiated by writing 1 to TCR[TXMSK] and TCR[FRMESZ] bits of data is
+ read. If rx water mark is set larger than TCR[FRMESZ], rx interrupt will not be generated. Lower the rx
+ water mark setting */
+ if ((handle->bytesPerFrame / 4U) < (uint16_t)handle->rxWatermark)
+ {
+ handle->rxWatermark =
+ (uint8_t)(handle->bytesPerFrame / 4U) > 0U ? (uint8_t)(handle->bytesPerFrame / 4U - 1U) : 0U;
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->rxWatermark);
+ }
+ }
+ else
+ {
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise
+ *there is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ tmpTimes = handle->readRegRemainingTimes;
+ if (tmpTimes <= handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(tmpTimes - 1U);
+ }
+ }
+
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
+ }
+
+ return kStatus_Success;
+}
+
+static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t wordToSend = 0;
+ uint8_t fifoSize = handle->fifoSize;
+ uint32_t writeRegRemainingTimes = handle->writeRegRemainingTimes;
+ uint32_t readRegRemainingTimes = handle->readRegRemainingTimes;
+ size_t txRemainingByteCount = handle->txRemainingByteCount;
+ uint8_t bytesEachWrite = handle->bytesEachWrite;
+ bool isByteSwap = handle->isByteSwap;
+
+ /* Make sure the difference in remaining TX and RX byte counts does not exceed FIFO depth
+ * and that the number of TX FIFO entries does not exceed the FIFO depth.
+ * But no need to make the protection if there is no rxData.
+ */
+ while ((LPSPI_GetTxFifoCount(base) < fifoSize) &&
+ (((readRegRemainingTimes - writeRegRemainingTimes) < (uint32_t)fifoSize) || (handle->rxData == NULL)))
+ {
+ if (txRemainingByteCount < (size_t)bytesEachWrite)
+ {
+ handle->bytesEachWrite = (uint8_t)txRemainingByteCount;
+ bytesEachWrite = handle->bytesEachWrite;
+ }
+
+ if (handle->txData != NULL)
+ {
+ wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap);
+ handle->txData += bytesEachWrite;
+ }
+ else
+ {
+ wordToSend = handle->txBuffIfNull;
+ }
+
+ /*Write the word to TX register*/
+ LPSPI_WriteData(base, wordToSend);
+
+ /*Decrease the write TX register times.*/
+ --handle->writeRegRemainingTimes;
+ writeRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ /*Decrease the remaining TX byte count.*/
+ handle->txRemainingByteCount -= (size_t)bytesEachWrite;
+ txRemainingByteCount = handle->txRemainingByteCount;
+
+ if (handle->txRemainingByteCount == 0U)
+ {
+ /* If PCS is continuous, update TCR to de-assert PCS */
+ if (handle->isPcsContinuous)
+ {
+ /* Only write to the TCR if the FIFO has room */
+ if (LPSPI_GetTxFifoCount(base) < fifoSize)
+ {
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
+ handle->writeTcrInIsr = false;
+ }
+ /* Else, set a global flag to tell the ISR to do write to the TCR */
+ else
+ {
+ handle->writeTcrInIsr = true;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_Success, handle->userData);
+ }
+}
+
+/*!
+ * brief Gets the master transfer remaining bytes.
+ *
+ * This function gets the master transfer remaining bytes.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ if (handle->rxData != NULL)
+ {
+ remainingByte = handle->rxRemainingByteCount;
+ }
+ else
+ {
+ remainingByte = handle->txRemainingByteCount;
+ }
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI master abort transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ LPSPI_Reset(base);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+ handle->txRemainingByteCount = 0;
+ handle->rxRemainingByteCount = 0;
+}
+
+/*!
+ * brief LPSPI Master IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receive IRQ.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t readData;
+ uint8_t bytesEachRead = handle->bytesEachRead;
+ bool isByteSwap = handle->isByteSwap;
+ uint32_t readRegRemainingTimes = handle->readRegRemainingTimes;
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->rxRemainingByteCount != 0U)
+ {
+ /* First, disable the interrupts to avoid potentially triggering another interrupt
+ * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll
+ * re-enable the interrupts based on the LPSPI state after reading out the FIFO.
+ */
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (handle->rxRemainingByteCount != 0U))
+ {
+ /*Read out the data*/
+ readData = LPSPI_ReadData(base);
+
+ /*Decrease the read RX register times.*/
+ --handle->readRegRemainingTimes;
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+
+ if (handle->rxRemainingByteCount < (size_t)bytesEachRead)
+ {
+ handle->bytesEachRead = (uint8_t)(handle->rxRemainingByteCount);
+ bytesEachRead = handle->bytesEachRead;
+ }
+
+ LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap);
+ handle->rxData += bytesEachRead;
+
+ /*Decrease the remaining RX byte count.*/
+ handle->rxRemainingByteCount -= (size_t)bytesEachRead;
+ }
+
+ /* Re-enable the interrupts only if rxCount indicates there is more data to receive,
+ * else we may get a spurious interrupt.
+ * */
+ if (handle->rxRemainingByteCount != 0U)
+ {
+ /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
+ LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U));
+ }
+ }
+
+ if (handle->txRemainingByteCount != 0U)
+ {
+ if (handle->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by
+ hardware every time when TCR[FRAMESZ] bit of data is transfered.
+ In this case TCR[TXMSK] should be set to initiate each transfer. */
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ if ((handle->txRemainingByteCount == (uint32_t)handle->bytesPerFrame) && (handle->isPcsContinuous))
+ {
+ /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should
+ * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ
+ * of data will be received. */
+ base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK);
+ }
+ handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ LPSPI_MasterTransferFillUpTxFifo(base, handle);
+ }
+ }
+ else
+ {
+ if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)))
+ {
+ if ((handle->isPcsContinuous) && (handle->writeTcrInIsr) && (!handle->isTxMask))
+ {
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
+ handle->writeTcrInIsr = false;
+ }
+ }
+ }
+
+ if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U) && (!handle->writeTcrInIsr))
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
+ if (handle->rxData == NULL)
+ {
+ if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) != 0U)
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransferCompleteFlag);
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_MasterTransferComplete(base, handle);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransferCompleteInterruptEnable);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+ else
+ {
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_MasterTransferComplete(base, handle);
+ }
+ }
+}
+
+/*Transactional APIs -- Slave*/
+/*!
+ * brief Initializes the LPSPI slave handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * param base LPSPI peripheral address.
+ * param handle LPSPI handle pointer to lpspi_slave_handle_t.
+ * param callback DSPI callback.
+ * param userData callback function parameter.
+ */
+void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base,
+ lpspi_slave_handle_t *handle,
+ lpspi_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
+
+ /* Set irq handler. */
+ s_lpspiSlaveIsr = LPSPI_SlaveTransferHandleIRQ;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+/*!
+ * brief LPSPI slave transfer data using an interrupt method.
+ *
+ * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Flush FIFO, clear status, disable all the inerrupts. */
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* Variables */
+ bool isRxMask = false;
+ bool isTxMask = false;
+ uint8_t txWatermark;
+ uint32_t readRegRemainingTimes;
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_SlaveByteSwap) != 0U);
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+ }
+ /* Set proper RX and TX watermarks to reduce the ISR response times. */
+ if (handle->fifoSize > 1U)
+ {
+ txWatermark = 1U;
+ handle->rxWatermark = handle->fifoSize - 2U;
+ }
+ else
+ {
+ txWatermark = 0U;
+ handle->rxWatermark = 0U;
+ }
+ LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
+
+ /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0U;
+ }
+ /* If there is no txData, mask the transmit data so that no data is loaded from transmit FIFO and output pin
+ * is tristated. */
+ if (handle->txData == NULL)
+ {
+ isTxMask = true;
+ handle->txRemainingByteCount = 0U;
+ }
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK |
+ LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) | LPSPI_TCR_PCS(whichPcs);
+
+ /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
+ * and you should also enable the INTMUX interupt in your application.
+ */
+ (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
+
+ /*TCR is also shared the FIFO, so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* Fill up the TX data in FIFO */
+ if (handle->txData != NULL)
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
+ * The IRQ handler will get the status of RX and TX interrupt flags.
+ */
+ if (handle->rxData != NULL)
+ {
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(readRegRemainingTimes - 1U);
+ }
+
+ /* RX request and FIFO overflow request enable */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable | (uint32_t)kLPSPI_ReceiveErrorInterruptEnable);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
+ }
+
+ if (handle->txData != NULL)
+ {
+ /* TX FIFO underflow request enable */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransmitErrorInterruptEnable);
+ }
+
+ return kStatus_Success;
+}
+
+static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t wordToSend = 0U;
+ uint8_t bytesEachWrite = handle->bytesEachWrite;
+ bool isByteSwap = handle->isByteSwap;
+
+ while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize))
+ {
+ if (handle->txRemainingByteCount < (size_t)bytesEachWrite)
+ {
+ handle->bytesEachWrite = (uint8_t)handle->txRemainingByteCount;
+ bytesEachWrite = handle->bytesEachWrite;
+ }
+
+ wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap);
+ handle->txData += bytesEachWrite;
+
+ /*Decrease the remaining TX byte count.*/
+ handle->txRemainingByteCount -= (size_t)bytesEachWrite;
+
+ /*Write the word to TX register*/
+ LPSPI_WriteData(base, wordToSend);
+
+ if (handle->txRemainingByteCount == 0U)
+ {
+ break;
+ }
+ }
+}
+
+static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ if (handle->state == (uint8_t)kLPSPI_Error)
+ {
+ status = kStatus_LPSPI_Error;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, status, handle->userData);
+ }
+}
+
+/*!
+ * brief Gets the slave transfer remaining bytes.
+ *
+ * This function gets the slave transfer remaining bytes.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ if (handle->rxData != NULL)
+ {
+ remainingByte = handle->rxRemainingByteCount;
+ }
+ else
+ {
+ remainingByte = handle->txRemainingByteCount;
+ }
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI slave aborts a transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+
+ LPSPI_Reset(base);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+ handle->txRemainingByteCount = 0U;
+ handle->rxRemainingByteCount = 0U;
+}
+
+/*!
+ * brief LPSPI Slave IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receives an IRQ.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t readData; /* variable to store word read from RX FIFO */
+ uint8_t bytesEachRead = handle->bytesEachRead;
+ bool isByteSwap = handle->isByteSwap;
+ uint32_t readRegRemainingTimes;
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->rxRemainingByteCount > 0U)
+ {
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+ {
+ /*Read out the data*/
+ readData = LPSPI_ReadData(base);
+
+ /*Decrease the read RX register times.*/
+ --handle->readRegRemainingTimes;
+
+ if (handle->rxRemainingByteCount < (size_t)bytesEachRead)
+ {
+ handle->bytesEachRead = (uint8_t)handle->rxRemainingByteCount;
+ bytesEachRead = handle->bytesEachRead;
+ }
+
+ LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap);
+ handle->rxData += bytesEachRead;
+
+ /*Decrease the remaining RX byte count.*/
+ handle->rxRemainingByteCount -= (size_t)bytesEachRead;
+
+ if ((handle->txRemainingByteCount > 0U) && (handle->txData != NULL))
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ if (handle->rxRemainingByteCount == 0U)
+ {
+ break;
+ }
+ }
+ }
+
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
+ LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U));
+ }
+ }
+ if ((handle->rxData == NULL) && (handle->txRemainingByteCount != 0U) && (handle->txData != NULL))
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U))
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets and the TX FIFO empty*/
+ if (handle->rxData == NULL)
+ {
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_FrameCompleteFlag) != 0U) &&
+ (LPSPI_GetTxFifoCount(base) == 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag);
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_SlaveTransferComplete(base, handle);
+ }
+ else
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag);
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_FrameCompleteInterruptEnable);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+ else
+ {
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_SlaveTransferComplete(base, handle);
+ }
+ }
+
+ /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransmitErrorFlag) != 0U) &&
+ ((base->IER & LPSPI_IER_TEIE_MASK) != 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransmitErrorFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData != NULL)
+ {
+ handle->state = (uint8_t)kLPSPI_Error;
+ }
+ handle->errorCount++;
+ }
+ /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ReceiveErrorFlag) != 0U) &&
+ ((base->IER & LPSPI_IER_REIE_MASK) != 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_ReceiveErrorFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData != NULL)
+ {
+ handle->state = (uint8_t)kLPSPI_Error;
+ }
+ handle->errorCount++;
+ }
+}
+
+static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap)
+{
+ assert(txData != NULL);
+
+ uint32_t wordToSend = 0U;
+
+ switch (bytesEachWrite)
+ {
+ case 1:
+ wordToSend = *txData;
+ ++txData;
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+
+ break;
+
+ case 3:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+ break;
+
+ case 4:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 24U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 24U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ return wordToSend;
+}
+
+static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap)
+{
+ assert(rxData != NULL);
+
+ switch (bytesEachRead)
+ {
+ case 1:
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ case 3:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ case 4:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+static bool LPSPI_TxFifoReady(LPSPI_Type *base)
+{
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while (((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while ((uint8_t)LPSPI_GetTxFifoCount(base) != 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ return true;
+}
+
+static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param)
+{
+ if (LPSPI_IsMaster(base))
+ {
+ s_lpspiMasterIsr(base, (lpspi_master_handle_t *)param);
+ }
+ else
+ {
+ s_lpspiSlaveIsr(base, (lpspi_slave_handle_t *)param);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if defined(LPSPI0)
+void LPSPI0_DriverIRQHandler(void);
+void LPSPI0_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[0] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]);
+}
+#endif
+
+#if defined(LPSPI1)
+void LPSPI1_DriverIRQHandler(void);
+void LPSPI1_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[1] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]);
+}
+#endif
+
+#if defined(LPSPI2)
+void LPSPI2_DriverIRQHandler(void);
+void LPSPI2_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[2] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]);
+}
+#endif
+
+#if defined(LPSPI3)
+void LPSPI3_DriverIRQHandler(void);
+void LPSPI3_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[3] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]);
+}
+#endif
+
+#if defined(LPSPI4)
+void LPSPI4_DriverIRQHandler(void);
+void LPSPI4_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[4] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]);
+}
+#endif
+
+#if defined(LPSPI5)
+void LPSPI5_DriverIRQHandler(void);
+void LPSPI5_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[5] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]);
+}
+#endif
+
+#if defined(DMA__LPSPI0)
+void DMA_SPI0_INT_DriverIRQHandler(void);
+void DMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
+}
+#endif
+
+#if defined(DMA__LPSPI1)
+void DMA_SPI1_INT_DriverIRQHandler(void);
+void DMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
+}
+#endif
+#if defined(DMA__LPSPI2)
+void DMA_SPI2_INT_DriverIRQHandler(void);
+void DMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
+}
+#endif
+
+#if defined(DMA__LPSPI3)
+void DMA_SPI3_INT_DriverIRQHandler(void);
+void DMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI0)
+void ADMA_SPI0_INT_DriverIRQHandler(void);
+void ADMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI1)
+void ADMA_SPI1_INT_DriverIRQHandler(void);
+void ADMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
+}
+#endif
+#if defined(ADMA__LPSPI2)
+void ADMA_SPI2_INT_DriverIRQHandler(void);
+void ADMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI3)
+void ADMA_SPI3_INT_DriverIRQHandler(void);
+void ADMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h
new file mode 100644
index 0000000000..98a4116982
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPSPI_H_
+#define _FSL_LPSPI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup lpspi_driver
+ * @{
+ */
+
+/**********************************************************************************************************************
+ * Definitions
+ *********************************************************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI driver version. */
+#define FSL_LPSPI_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
+/*@}*/
+
+#ifndef LPSPI_DUMMY_DATA
+/*! @brief LPSPI dummy data if no Tx data.*/
+#define LPSPI_DUMMY_DATA (0x00U) /*!< Dummy data used for tx if there is not txData. */
+#endif
+
+/*! @brief Retry times for waiting flag. */
+#ifndef SPI_RETRY_TIMES
+#define SPI_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief Global variable for dummy data value setting. */
+extern volatile uint8_t g_lpspiDummyData[];
+
+/*! @brief Status for the LPSPI driver.*/
+enum
+{
+ kStatus_LPSPI_Busy = MAKE_STATUS(kStatusGroup_LPSPI, 0), /*!< LPSPI transfer is busy.*/
+ kStatus_LPSPI_Error = MAKE_STATUS(kStatusGroup_LPSPI, 1), /*!< LPSPI driver error. */
+ kStatus_LPSPI_Idle = MAKE_STATUS(kStatusGroup_LPSPI, 2), /*!< LPSPI is idle.*/
+ kStatus_LPSPI_OutOfRange = MAKE_STATUS(kStatusGroup_LPSPI, 3), /*!< LPSPI transfer out Of range. */
+ kStatus_LPSPI_Timeout = MAKE_STATUS(kStatusGroup_LPSPI, 4) /*!< LPSPI timeout polling status flags. */
+};
+
+/*! @brief LPSPI status flags in SPIx_SR register.*/
+enum _lpspi_flags
+{
+ kLPSPI_TxDataRequestFlag = LPSPI_SR_TDF_MASK, /*!< Transmit data flag */
+ kLPSPI_RxDataReadyFlag = LPSPI_SR_RDF_MASK, /*!< Receive data flag */
+ kLPSPI_WordCompleteFlag = LPSPI_SR_WCF_MASK, /*!< Word Complete flag */
+ kLPSPI_FrameCompleteFlag = LPSPI_SR_FCF_MASK, /*!< Frame Complete flag */
+ kLPSPI_TransferCompleteFlag = LPSPI_SR_TCF_MASK, /*!< Transfer Complete flag */
+ kLPSPI_TransmitErrorFlag = LPSPI_SR_TEF_MASK, /*!< Transmit Error flag (FIFO underrun) */
+ kLPSPI_ReceiveErrorFlag = LPSPI_SR_REF_MASK, /*!< Receive Error flag (FIFO overrun) */
+ kLPSPI_DataMatchFlag = LPSPI_SR_DMF_MASK, /*!< Data Match flag */
+ kLPSPI_ModuleBusyFlag = LPSPI_SR_MBF_MASK, /*!< Module Busy flag */
+ kLPSPI_AllStatusFlag = (LPSPI_SR_TDF_MASK | LPSPI_SR_RDF_MASK | LPSPI_SR_WCF_MASK | LPSPI_SR_FCF_MASK |
+ LPSPI_SR_TCF_MASK | LPSPI_SR_TEF_MASK | LPSPI_SR_REF_MASK | LPSPI_SR_DMF_MASK |
+ LPSPI_SR_MBF_MASK) /*!< Used for clearing all w1c status flags */
+};
+
+/*! @brief LPSPI interrupt source.*/
+enum _lpspi_interrupt_enable
+{
+ kLPSPI_TxInterruptEnable = LPSPI_IER_TDIE_MASK, /*!< Transmit data interrupt enable */
+ kLPSPI_RxInterruptEnable = LPSPI_IER_RDIE_MASK, /*!< Receive data interrupt enable */
+ kLPSPI_WordCompleteInterruptEnable = LPSPI_IER_WCIE_MASK, /*!< Word complete interrupt enable */
+ kLPSPI_FrameCompleteInterruptEnable = LPSPI_IER_FCIE_MASK, /*!< Frame complete interrupt enable */
+ kLPSPI_TransferCompleteInterruptEnable = LPSPI_IER_TCIE_MASK, /*!< Transfer complete interrupt enable */
+ kLPSPI_TransmitErrorInterruptEnable = LPSPI_IER_TEIE_MASK, /*!< Transmit error interrupt enable(FIFO underrun)*/
+ kLPSPI_ReceiveErrorInterruptEnable = LPSPI_IER_REIE_MASK, /*!< Receive Error interrupt enable (FIFO overrun) */
+ kLPSPI_DataMatchInterruptEnable = LPSPI_IER_DMIE_MASK, /*!< Data Match interrupt enable */
+ kLPSPI_AllInterruptEnable =
+ (LPSPI_IER_TDIE_MASK | LPSPI_IER_RDIE_MASK | LPSPI_IER_WCIE_MASK | LPSPI_IER_FCIE_MASK | LPSPI_IER_TCIE_MASK |
+ LPSPI_IER_TEIE_MASK | LPSPI_IER_REIE_MASK | LPSPI_IER_DMIE_MASK) /*!< All above interrupts enable.*/
+};
+
+/*! @brief LPSPI DMA source.*/
+enum _lpspi_dma_enable
+{
+ kLPSPI_TxDmaEnable = LPSPI_DER_TDDE_MASK, /*!< Transmit data DMA enable */
+ kLPSPI_RxDmaEnable = LPSPI_DER_RDDE_MASK /*!< Receive data DMA enable */
+};
+
+/*! @brief LPSPI master or slave mode configuration.*/
+typedef enum _lpspi_master_slave_mode
+{
+ kLPSPI_Master = 1U, /*!< LPSPI peripheral operates in master mode.*/
+ kLPSPI_Slave = 0U /*!< LPSPI peripheral operates in slave mode.*/
+} lpspi_master_slave_mode_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) configuration (which PCS to configure).*/
+typedef enum _lpspi_which_pcs_config
+{
+ kLPSPI_Pcs0 = 0U, /*!< PCS[0] */
+ kLPSPI_Pcs1 = 1U, /*!< PCS[1] */
+ kLPSPI_Pcs2 = 2U, /*!< PCS[2] */
+ kLPSPI_Pcs3 = 3U /*!< PCS[3] */
+} lpspi_which_pcs_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity configuration.*/
+typedef enum _lpspi_pcs_polarity_config
+{
+ kLPSPI_PcsActiveHigh = 1U, /*!< PCS Active High (idles low) */
+ kLPSPI_PcsActiveLow = 0U /*!< PCS Active Low (idles high) */
+} lpspi_pcs_polarity_config_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity.*/
+enum _lpspi_pcs_polarity
+{
+ kLPSPI_Pcs0ActiveLow = 1U << 0, /*!< Pcs0 Active Low (idles high). */
+ kLPSPI_Pcs1ActiveLow = 1U << 1, /*!< Pcs1 Active Low (idles high). */
+ kLPSPI_Pcs2ActiveLow = 1U << 2, /*!< Pcs2 Active Low (idles high). */
+ kLPSPI_Pcs3ActiveLow = 1U << 3, /*!< Pcs3 Active Low (idles high). */
+ kLPSPI_PcsAllActiveLow = 0xFU /*!< Pcs0 to Pcs5 Active Low (idles high). */
+};
+
+/*! @brief LPSPI clock polarity configuration.*/
+typedef enum _lpspi_clock_polarity
+{
+ kLPSPI_ClockPolarityActiveHigh = 0U, /*!< CPOL=0. Active-high LPSPI clock (idles low)*/
+ kLPSPI_ClockPolarityActiveLow = 1U /*!< CPOL=1. Active-low LPSPI clock (idles high)*/
+} lpspi_clock_polarity_t;
+
+/*! @brief LPSPI clock phase configuration.*/
+typedef enum _lpspi_clock_phase
+{
+ kLPSPI_ClockPhaseFirstEdge = 0U, /*!< CPHA=0. Data is captured on the leading edge of the SCK and changed on the
+ following edge.*/
+ kLPSPI_ClockPhaseSecondEdge = 1U /*!< CPHA=1. Data is changed on the leading edge of the SCK and captured on the
+ following edge.*/
+} lpspi_clock_phase_t;
+
+/*! @brief LPSPI data shifter direction options.*/
+typedef enum _lpspi_shift_direction
+{
+ kLPSPI_MsbFirst = 0U, /*!< Data transfers start with most significant bit.*/
+ kLPSPI_LsbFirst = 1U /*!< Data transfers start with least significant bit.*/
+} lpspi_shift_direction_t;
+
+/*! @brief LPSPI Host Request select configuration. */
+typedef enum _lpspi_host_request_select
+{
+ kLPSPI_HostReqExtPin = 0U, /*!< Host Request is an ext pin. */
+ kLPSPI_HostReqInternalTrigger = 1U /*!< Host Request is an internal trigger. */
+} lpspi_host_request_select_t;
+
+/*! @brief LPSPI Match configuration options. */
+typedef enum _lpspi_match_config
+{
+ kLPSI_MatchDisabled = 0x0U, /*!< LPSPI Match Disabled. */
+ kLPSI_1stWordEqualsM0orM1 = 0x2U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordEqualsM0orM1 = 0x3U, /*!< LPSPI Match Enabled. */
+ kLPSI_1stWordEqualsM0and2ndWordEqualsM1 = 0x4U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordEqualsM0andNxtWordEqualsM1 = 0x5U, /*!< LPSPI Match Enabled. */
+ kLPSI_1stWordAndM1EqualsM0andM1 = 0x6U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordAndM1EqualsM0andM1 = 0x7U, /*!< LPSPI Match Enabled. */
+} lpspi_match_config_t;
+
+/*! @brief LPSPI pin (SDO and SDI) configuration. */
+typedef enum _lpspi_pin_config
+{
+ kLPSPI_SdiInSdoOut = 0U, /*!< LPSPI SDI input, SDO output. */
+ kLPSPI_SdiInSdiOut = 1U, /*!< LPSPI SDI input, SDI output. */
+ kLPSPI_SdoInSdoOut = 2U, /*!< LPSPI SDO input, SDO output. */
+ kLPSPI_SdoInSdiOut = 3U /*!< LPSPI SDO input, SDI output. */
+} lpspi_pin_config_t;
+
+/*! @brief LPSPI data output configuration. */
+typedef enum _lpspi_data_out_config
+{
+ kLpspiDataOutRetained = 0U, /*!< Data out retains last value when chip select is de-asserted */
+ kLpspiDataOutTristate = 1U /*!< Data out is tristated when chip select is de-asserted */
+} lpspi_data_out_config_t;
+
+/*! @brief LPSPI transfer width configuration. */
+typedef enum _lpspi_transfer_width
+{
+ kLPSPI_SingleBitXfer = 0U, /*!< 1-bit shift at a time, data out on SDO, in on SDI (normal mode) */
+ kLPSPI_TwoBitXfer = 1U, /*!< 2-bits shift out on SDO/SDI and in on SDO/SDI */
+ kLPSPI_FourBitXfer = 2U /*!< 4-bits shift out on SDO/SDI/PCS[3:2] and in on SDO/SDI/PCS[3:2] */
+} lpspi_transfer_width_t;
+
+/*! @brief LPSPI delay type selection.*/
+typedef enum _lpspi_delay_type
+{
+ kLPSPI_PcsToSck = 1U, /*!< PCS-to-SCK delay. */
+ kLPSPI_LastSckToPcs, /*!< Last SCK edge to PCS delay. */
+ kLPSPI_BetweenTransfer /*!< Delay between transfers. */
+} lpspi_delay_type_t;
+
+#define LPSPI_MASTER_PCS_SHIFT (4U) /*!< LPSPI master PCS shift macro , internal used. */
+#define LPSPI_MASTER_PCS_MASK (0xF0U) /*!< LPSPI master PCS shift macro , internal used. */
+
+/*! @brief Use this enumeration for LPSPI master transfer configFlags. */
+enum _lpspi_transfer_config_flag_for_master
+{
+ kLPSPI_MasterPcs0 = 0U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS0 signal */
+ kLPSPI_MasterPcs1 = 1U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS1 signal */
+ kLPSPI_MasterPcs2 = 2U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS2 signal */
+ kLPSPI_MasterPcs3 = 3U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS3 signal */
+
+ kLPSPI_MasterPcsContinuous = 1U << 20, /*!< Is PCS signal continuous */
+
+ kLPSPI_MasterByteSwap =
+ 1U << 22 /*!< Is master swap the byte.
+ * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set
+ * lpspi_shift_direction_t to MSB).
+ * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_MasterByteSwapyou flag is used
+ * or not, the waveform is 1 2 3 4 5 6 7 8.
+ * 2. If you set bitPerFrame = 16 :
+ * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_MasterByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag.
+ * 3. If you set bitPerFrame = 32 :
+ * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_MasterByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag.
+ */
+};
+
+#define LPSPI_SLAVE_PCS_SHIFT (4U) /*!< LPSPI slave PCS shift macro , internal used. */
+#define LPSPI_SLAVE_PCS_MASK (0xF0U) /*!< LPSPI slave PCS shift macro , internal used. */
+
+/*! @brief Use this enumeration for LPSPI slave transfer configFlags. */
+enum _lpspi_transfer_config_flag_for_slave
+{
+ kLPSPI_SlavePcs0 = 0U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS0 signal */
+ kLPSPI_SlavePcs1 = 1U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS1 signal */
+ kLPSPI_SlavePcs2 = 2U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS2 signal */
+ kLPSPI_SlavePcs3 = 3U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS3 signal */
+
+ kLPSPI_SlaveByteSwap =
+ 1U << 22 /*!< Is slave swap the byte.
+ * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set
+ * lpspi_shift_direction_t to MSB).
+ * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_SlaveByteSwap flag is used
+ * or not, the waveform is 1 2 3 4 5 6 7 8.
+ * 2. If you set bitPerFrame = 16 :
+ * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_SlaveByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag.
+ * 3. If you set bitPerFrame = 32 :
+ * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_SlaveByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag.
+ */
+};
+
+/*! @brief LPSPI transfer state, which is used for LPSPI transactional API state machine. */
+enum _lpspi_transfer_state
+{
+ kLPSPI_Idle = 0x0U, /*!< Nothing in the transmitter/receiver. */
+ kLPSPI_Busy, /*!< Transfer queue is not finished. */
+ kLPSPI_Error /*!< Transfer error. */
+};
+
+/*! @brief LPSPI master configuration structure.*/
+typedef struct _lpspi_master_config
+{
+ uint32_t baudRate; /*!< Baud Rate for LPSPI. */
+ uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ lpspi_clock_polarity_t cpol; /*!< Clock polarity. */
+ lpspi_clock_phase_t cpha; /*!< Clock phase. */
+ lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */
+
+ uint32_t pcsToSckDelayInNanoSec; /*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay.
+ It sets the boundary value if out of range.*/
+ uint32_t lastSckToPcsDelayInNanoSec; /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum
+ delay. It sets the boundary value if out of range.*/
+ uint32_t betweenTransferDelayInNanoSec; /*!< After the SCK delay time with nanoseconds, setting to 0 sets the
+ minimum delay. It sets the boundary value if out of range.*/
+
+ lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (PCS). */
+ lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */
+
+ lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data
+ *during single bit transfers.*/
+
+ lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated
+ * between accesses (LPSPI_PCS is negated). */
+ bool enableInputDelay; /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave
+ setup time. Refer to device data sheet for specific time length. */
+} lpspi_master_config_t;
+
+/*! @brief LPSPI slave configuration structure.*/
+typedef struct _lpspi_slave_config
+{
+ uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ lpspi_clock_polarity_t cpol; /*!< Clock polarity. */
+ lpspi_clock_phase_t cpha; /*!< Clock phase. */
+ lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */
+
+ lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (pcs) */
+ lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */
+
+ lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data
+ *during single bit transfers.*/
+
+ lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated
+ * between accesses (LPSPI_PCS is negated). */
+} lpspi_slave_config_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_master_handle typedefs.
+ */
+typedef struct _lpspi_master_handle lpspi_master_handle_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_slave_handle typedefs.
+ */
+typedef struct _lpspi_slave_handle lpspi_slave_handle_t;
+
+/*!
+ * @brief Master completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle Pointer to the handle for the LPSPI master.
+ * @param status Success or error code describing whether the transfer is completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_master_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_master_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief Slave completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle Pointer to the handle for the LPSPI slave.
+ * @param status Success or error code describing whether the transfer is completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_slave_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_slave_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief LPSPI master/slave transfer structure.*/
+typedef struct _lpspi_transfer
+{
+ uint8_t *txData; /*!< Send buffer. */
+ uint8_t *rxData; /*!< Receive buffer. */
+ volatile size_t dataSize; /*!< Transfer bytes. */
+
+ uint32_t configFlags; /*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if
+ the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the
+ transfer is used for slave.*/
+} lpspi_transfer_t;
+
+/*! @brief LPSPI master transfer handle structure used for transactional API. */
+struct _lpspi_master_handle
+{
+ volatile bool isPcsContinuous; /*!< Is PCS continuous in transfer. */
+ volatile bool writeTcrInIsr; /*!< A flag that whether should write TCR in ISR. */
+
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+ volatile bool isTxMask; /*!< A flag that whether TCR[TXMSK] is set. */
+ volatile uint16_t bytesPerFrame; /*!< Number of bytes in each frame */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if the txData is NULL. */
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ lpspi_master_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+};
+
+/*! @brief LPSPI slave transfer handle structure used for transactional API. */
+struct _lpspi_slave_handle
+{
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ volatile uint32_t errorCount; /*!< Error count for slave transfer.*/
+
+ lpspi_slave_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+};
+
+/**********************************************************************************************************************
+ * API
+ *********************************************************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LPSPI master.
+ *
+ * @param base LPSPI peripheral address.
+ * @param masterConfig Pointer to structure lpspi_master_config_t.
+ * @param srcClock_Hz Module source input clock in Hertz
+ */
+void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Sets the lpspi_master_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_MasterInit().
+ * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified
+ * before calling the LPSPI_MasterInit().
+ * Example:
+ * @code
+ * lpspi_master_config_t masterConfig;
+ * LPSPI_MasterGetDefaultConfig(&masterConfig);
+ * @endcode
+ * @param masterConfig pointer to lpspi_master_config_t structure
+ */
+void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig);
+
+/*!
+ * @brief LPSPI slave configuration.
+ *
+ * @param base LPSPI peripheral address.
+ * @param slaveConfig Pointer to a structure lpspi_slave_config_t.
+ */
+void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig);
+
+/*!
+ * @brief Sets the lpspi_slave_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_SlaveInit().
+ * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified
+ * before calling the LPSPI_SlaveInit().
+ * Example:
+ * @code
+ * lpspi_slave_config_t slaveConfig;
+ * LPSPI_SlaveGetDefaultConfig(&slaveConfig);
+ * @endcode
+ * @param slaveConfig pointer to lpspi_slave_config_t structure.
+ */
+void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig);
+
+/*!
+ * @brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock.
+ * @param base LPSPI peripheral address.
+ */
+void LPSPI_Deinit(LPSPI_Type *base);
+
+/*!
+ * @brief Restores the LPSPI peripheral to reset state. Note that this function
+ * sets all registers to reset state. As a result, the LPSPI module can't work after calling
+ * this API.
+ * @param base LPSPI peripheral address.
+ */
+void LPSPI_Reset(LPSPI_Type *base);
+
+/*!
+ * @brief Get the LPSPI instance from peripheral base address.
+ *
+ * @param base LPSPI peripheral base address.
+ * @return LPSPI instance.
+ */
+uint32_t LPSPI_GetInstance(LPSPI_Type *base);
+
+/*!
+ * @brief Enables the LPSPI peripheral and sets the MCR MDIS to 0.
+ *
+ * @param base LPSPI peripheral address.
+ * @param enable Pass true to enable module, false to disable module.
+ */
+static inline void LPSPI_Enable(LPSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR |= LPSPI_CR_MEN_MASK;
+ }
+ else
+ {
+ base->CR &= ~LPSPI_CR_MEN_MASK;
+ }
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the LPSPI status flag state.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI status(in SR register).
+ */
+static inline uint32_t LPSPI_GetStatusFlags(LPSPI_Type *base)
+{
+ return (base->SR);
+}
+
+/*!
+ * @brief Gets the LPSPI Tx FIFO size.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Tx FIFO size.
+ */
+static inline uint8_t LPSPI_GetTxFifoSize(LPSPI_Type *base)
+{
+ return (1U << ((base->PARAM & LPSPI_PARAM_TXFIFO_MASK) >> LPSPI_PARAM_TXFIFO_SHIFT));
+}
+
+/*!
+ * @brief Gets the LPSPI Rx FIFO size.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Rx FIFO size.
+ */
+static inline uint8_t LPSPI_GetRxFifoSize(LPSPI_Type *base)
+{
+ return (1U << ((base->PARAM & LPSPI_PARAM_RXFIFO_MASK) >> LPSPI_PARAM_RXFIFO_SHIFT));
+}
+
+/*!
+ * @brief Gets the LPSPI Tx FIFO count.
+ * @param base LPSPI peripheral address.
+ * @return The number of words in the transmit FIFO.
+ */
+static inline uint32_t LPSPI_GetTxFifoCount(LPSPI_Type *base)
+{
+ return ((base->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT);
+}
+
+/*!
+ * @brief Gets the LPSPI Rx FIFO count.
+ * @param base LPSPI peripheral address.
+ * @return The number of words in the receive FIFO.
+ */
+static inline uint32_t LPSPI_GetRxFifoCount(LPSPI_Type *base)
+{
+ return ((base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT);
+}
+
+/*!
+ * @brief Clears the LPSPI status flag.
+ *
+ * This function clears the desired status bit by using a write-1-to-clear. The user passes in the base and the
+ * desired status flag bit to clear. The list of status flags is defined in the _lpspi_flags.
+ * Example usage:
+ * @code
+ * LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag|kLPSPI_RxDataReadyFlag);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param statusFlags The status flag used from type _lpspi_flags.
+ */
+static inline void LPSPI_ClearStatusFlags(LPSPI_Type *base, uint32_t statusFlags)
+{
+ base->SR = statusFlags; /*!< The status flags are cleared by writing 1 (w1c).*/
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the LPSPI interrupts.
+ *
+ * This function configures the various interrupt masks of the LPSPI. The parameters are base and an interrupt mask.
+ * Note that, for Tx fill and Rx FIFO drain requests, enabling the interrupt request disables the DMA request.
+ *
+ * @code
+ * LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable );
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable.
+ */
+static inline void LPSPI_EnableInterrupts(LPSPI_Type *base, uint32_t mask)
+{
+ base->IER |= mask;
+}
+
+/*!
+ * @brief Disables the LPSPI interrupts.
+ *
+ * @code
+ * LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable );
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable.
+ */
+static inline void LPSPI_DisableInterrupts(LPSPI_Type *base, uint32_t mask)
+{
+ base->IER &= ~mask;
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables the LPSPI DMA request.
+ *
+ * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask.
+ * @code
+ * LPSPI_EnableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_dma_enable.
+ */
+static inline void LPSPI_EnableDMA(LPSPI_Type *base, uint32_t mask)
+{
+ base->DER |= mask;
+}
+
+/*!
+ * @brief Disables the LPSPI DMA request.
+ *
+ * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask.
+ * @code
+ * SPI_DisableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_dma_enable.
+ */
+static inline void LPSPI_DisableDMA(LPSPI_Type *base, uint32_t mask)
+{
+ base->DER &= ~mask;
+}
+
+/*!
+ * @brief Gets the LPSPI Transmit Data Register address for a DMA operation.
+ *
+ * This function gets the LPSPI Transmit Data Register address because this value is needed
+ * for the DMA operation.
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Transmit Data Register address.
+ */
+static inline uint32_t LPSPI_GetTxRegisterAddress(LPSPI_Type *base)
+{
+ return (uint32_t) & (base->TDR);
+}
+
+/*!
+ * @brief Gets the LPSPI Receive Data Register address for a DMA operation.
+ *
+ * This function gets the LPSPI Receive Data Register address because this value is needed
+ * for the DMA operation.
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Receive Data Register address.
+ */
+static inline uint32_t LPSPI_GetRxRegisterAddress(LPSPI_Type *base)
+{
+ return (uint32_t) & (base->RDR);
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Check the argument for transfer .
+ *
+ * @param base LPSPI peripheral address.
+ * @param transfer the transfer struct to be used.
+ * @param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer
+ * @return Return true for right and false for wrong.
+ */
+bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma);
+
+/*!
+ * @brief Configures the LPSPI for either master or slave.
+ *
+ * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0).
+ *
+ * @param base LPSPI peripheral address.
+ * @param mode Mode setting (master or slave) of type lpspi_master_slave_mode_t.
+ */
+static inline void LPSPI_SetMasterSlaveMode(LPSPI_Type *base, lpspi_master_slave_mode_t mode)
+{
+ base->CFGR1 = (base->CFGR1 & (~LPSPI_CFGR1_MASTER_MASK)) | LPSPI_CFGR1_MASTER(mode);
+}
+
+/*!
+ * @brief Configures the peripheral chip select used for the transfer.
+ *
+ * @param base LPSPI peripheral address.
+ * @param select LPSPI Peripheral Chip Select (PCS) configuration.
+ */
+static inline void LPSPI_SelectTransferPCS(LPSPI_Type *base, lpspi_which_pcs_t select)
+{
+ base->TCR = (base->TCR & (~LPSPI_TCR_PCS_MASK)) | LPSPI_TCR_PCS((uint8_t)select);
+}
+
+/*!
+ * @brief Set the PCS signal to continuous or uncontinuous mode.
+ *
+ * @note In master mode, continuous transfer will keep the PCS asserted at the end of the frame size, until a command
+ * word is received that starts a new frame. So PCS must be set back to uncontinuous when transfer finishes.
+ * In slave mode, when continuous transfer is enabled, the LPSPI will only transmit the first frame size bits, after
+ * that the LPSPI will transmit received data back (assuming a 32-bit shift register).
+ *
+ * @param base LPSPI peripheral address.
+ * @param IsContinous True to set the transfer PCS to continuous mode, false to set to uncontinuous mode.
+ */
+static inline void LPSPI_SetPCSContinous(LPSPI_Type *base, bool IsContinous)
+{
+ if (IsContinous)
+ {
+ base->TCR |= LPSPI_TCR_CONT_MASK;
+ }
+ else
+ {
+ base->TCR &= ~LPSPI_TCR_CONT_MASK;
+ }
+}
+
+/*!
+ * @brief Returns whether the LPSPI module is in master mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return Returns true if the module is in master mode or false if the module is in slave mode.
+ */
+static inline bool LPSPI_IsMaster(LPSPI_Type *base)
+{
+ return (bool)((base->CFGR1) & LPSPI_CFGR1_MASTER_MASK);
+}
+
+/*!
+ * @brief Flushes the LPSPI FIFOs.
+ *
+ * @param base LPSPI peripheral address.
+ * @param flushTxFifo Flushes (true) the Tx FIFO, else do not flush (false) the Tx FIFO.
+ * @param flushRxFifo Flushes (true) the Rx FIFO, else do not flush (false) the Rx FIFO.
+ */
+static inline void LPSPI_FlushFifo(LPSPI_Type *base, bool flushTxFifo, bool flushRxFifo)
+{
+ base->CR |= ((uint32_t)flushTxFifo << LPSPI_CR_RTF_SHIFT) | ((uint32_t)flushRxFifo << LPSPI_CR_RRF_SHIFT);
+}
+
+/*!
+ * @brief Sets the transmit and receive FIFO watermark values.
+ *
+ * This function allows the user to set the receive and transmit FIFO watermarks. The function
+ * does not compare the watermark settings to the FIFO size. The FIFO watermark should not be
+ * equal to or greater than the FIFO size. It is up to the higher level driver to make this check.
+ *
+ * @param base LPSPI peripheral address.
+ * @param txWater The TX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated.
+ * @param rxWater The RX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated.
+ */
+static inline void LPSPI_SetFifoWatermarks(LPSPI_Type *base, uint32_t txWater, uint32_t rxWater)
+{
+ base->FCR = LPSPI_FCR_TXWATER(txWater) | LPSPI_FCR_RXWATER(rxWater);
+}
+
+/*!
+ * @brief Configures all LPSPI peripheral chip select polarities simultaneously.
+ *
+ * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0).
+ *
+ * This is an example: PCS0 and PCS1 set to active low and other PCSs set to active high. Note that the number of
+ * PCS is device-specific.
+ * @code
+ * LPSPI_SetAllPcsPolarity(base, kLPSPI_Pcs0ActiveLow | kLPSPI_Pcs1ActiveLow);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The PCS polarity mask; Use the enum _lpspi_pcs_polarity.
+ */
+static inline void LPSPI_SetAllPcsPolarity(LPSPI_Type *base, uint32_t mask)
+{
+ base->CFGR1 = (base->CFGR1 & ~LPSPI_CFGR1_PCSPOL_MASK) | LPSPI_CFGR1_PCSPOL(~mask);
+}
+
+/*!
+ * @brief Configures the frame size.
+ *
+ * The minimum frame size is 8-bits and the maximum frame size is 4096-bits. If the frame size is less than or equal
+ * to 32-bits, the word size and frame size are identical. If the frame size is greater than 32-bits, the word
+ * size is 32-bits for each word except the last (the last word contains the remainder bits if the frame size is not
+ * divisible by 32). The minimum word size is 2-bits. A frame size of 33-bits (or similar) is not supported.
+ *
+ * Note 1: The transmit command register should be initialized before enabling the LPSPI in slave mode, although
+ * the command register does not update until after the LPSPI is enabled. After it is enabled, the transmit command
+ * register
+ * should only be changed if the LPSPI is idle.
+ *
+ * Note 2: The transmit and command FIFO is a combined FIFO that includes both transmit data and command words. That
+ * means the TCR register should be written to when the Tx FIFO is not full.
+ *
+ * @param base LPSPI peripheral address.
+ * @param frameSize The frame size in number of bits.
+ */
+static inline void LPSPI_SetFrameSize(LPSPI_Type *base, uint32_t frameSize)
+{
+ base->TCR = (base->TCR & ~LPSPI_TCR_FRAMESZ_MASK) | LPSPI_TCR_FRAMESZ(frameSize - 1U);
+}
+
+/*!
+ * @brief Sets the LPSPI baud rate in bits per second.
+ *
+ * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest
+ * possible baud rate without exceeding the desired baud rate and returns the
+ * calculated baud rate in bits-per-second. It requires the caller to provide
+ * the frequency of the module source clock (in Hertz). Note that the baud rate
+ * does not go into effect until the Transmit Control Register (TCR) is programmed
+ * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue
+ * parameter for later programming in the TCR. The higher level
+ * peripheral driver should alert the user of an out of range baud rate input.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * @param base LPSPI peripheral address.
+ * @param baudRate_Bps The desired baud rate in bits per second.
+ * @param srcClock_Hz Module source input clock in Hertz.
+ * @param tcrPrescaleValue The TCR prescale value needed to program the TCR.
+ * @return The actual calculated baud rate. This function may also return a "0" if the
+ * LPSPI is not configured for master mode or if the LPSPI module is not disabled.
+ */
+
+uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base,
+ uint32_t baudRate_Bps,
+ uint32_t srcClock_Hz,
+ uint32_t *tcrPrescaleValue);
+
+/*!
+ * @brief Manually configures a specific LPSPI delay parameter (module must be disabled to
+ * change the delay values).
+ *
+ * This function configures the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay along with the delay value.
+ * This allows the user to directly set the delay values if they have
+ * pre-calculated them or if they simply wish to manually increment the value.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * @param base LPSPI peripheral address.
+ * @param scaler The 8-bit delay value 0x00 to 0xFF (255).
+ * @param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t.
+ */
+void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay);
+
+/*!
+ * @brief Calculates the delay based on the desired delay input in nanoseconds (module must be
+ * disabled to change the delay values).
+ *
+ * This function calculates the values for the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay and the desired delay value in
+ * nano-seconds. The function calculates the value needed for the desired delay parameter
+ * and returns the actual calculated delay because an exact delay match may not be possible. In this
+ * case, the closest match is calculated without going below the desired delay value input.
+ * It is possible to input a very large delay value that exceeds the capability of the part, in
+ * which case the maximum supported delay is returned. It is up to the higher level
+ * peripheral driver to alert the user of an out of range delay input.
+ *
+ * Note that the LPSPI module must be configured for master mode before configuring this. And note that
+ * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler).
+ *
+ * @param base LPSPI peripheral address.
+ * @param delayTimeInNanoSec The desired delay value in nano-seconds.
+ * @param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t.
+ * @param srcClock_Hz Module source input clock in Hertz.
+ * @return actual Calculated delay value in nano-seconds.
+ */
+uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base,
+ uint32_t delayTimeInNanoSec,
+ lpspi_delay_type_t whichDelay,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Writes data into the transmit data buffer.
+ *
+ * This function writes data passed in by the user to the Transmit Data Register (TDR).
+ * The user can pass up to 32-bits of data to load into the TDR. If the frame size exceeds 32-bits,
+ * the user has to manage sending the data one 32-bit word at a time.
+ * Any writes to the TDR result in an immediate push to the transmit FIFO.
+ * This function can be used for either master or slave modes.
+ *
+ * @param base LPSPI peripheral address.
+ * @param data The data word to be sent.
+ */
+static inline void LPSPI_WriteData(LPSPI_Type *base, uint32_t data)
+{
+ base->TDR = data;
+}
+
+/*!
+ * @brief Reads data from the data buffer.
+ *
+ * This function reads the data from the Receive Data Register (RDR).
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The data read from the data buffer.
+ */
+static inline uint32_t LPSPI_ReadData(LPSPI_Type *base)
+{
+ return (base->RDR);
+}
+
+/*!
+ * @brief Set up the dummy data.
+ *
+ * @param base LPSPI peripheral address.
+ * @param dummyData Data to be transferred when tx buffer is NULL.
+ * Note:
+ * This API has no effect when LPSPI in slave interrupt mode, because driver
+ * will set the TXMSK bit to 1 if txData is NULL, no data is loaded from transmit
+ * FIFO and output pin is tristated.
+ */
+void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData);
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+/*Transactional APIs*/
+
+/*!
+ * @brief Initializes the LPSPI master handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+
+ * @param base LPSPI peripheral address.
+ * @param handle LPSPI handle pointer to lpspi_master_handle_t.
+ * @param callback DSPI callback.
+ * @param userData callback function parameter.
+ */
+void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base,
+ lpspi_master_handle_t *handle,
+ lpspi_master_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief LPSPI master transfer data using a polling method.
+ *
+ * This function transfers data using a polling method. This is a blocking function, which does not return until all
+ * transfers have been
+ * completed.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * @param base LPSPI peripheral address.
+ * @param transfer pointer to lpspi_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer);
+
+/*!
+ * @brief LPSPI master transfer data using an interrupt method.
+ *
+ * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * @param transfer pointer to lpspi_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @brief Gets the master transfer remaining bytes.
+ *
+ * This function gets the master transfer remaining bytes.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count);
+
+/*!
+ * @brief LPSPI master abort transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief LPSPI Master IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receive IRQ.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief Initializes the LPSPI slave handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle LPSPI handle pointer to lpspi_slave_handle_t.
+ * @param callback DSPI callback.
+ * @param userData callback function parameter.
+ */
+void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base,
+ lpspi_slave_handle_t *handle,
+ lpspi_slave_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief LPSPI slave transfer data using an interrupt method.
+ *
+ * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * @param transfer pointer to lpspi_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @brief Gets the slave transfer remaining bytes.
+ *
+ * This function gets the slave transfer remaining bytes.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the non-blocking transaction.
+ * @return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count);
+
+/*!
+ * @brief LPSPI slave aborts a transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ * @brief LPSPI Slave IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receives an IRQ.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ *@}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /*_FSL_LPSPI_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c
new file mode 100644
index 0000000000..92e8bbdb4d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpspi_edma.h"
+
+/***********************************************************************************************************************
+ * Definitions
+ ***********************************************************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpspi_edma"
+#endif
+
+/*!
+ * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
+ */
+typedef struct _lpspi_master_edma_private_handle
+{
+ LPSPI_Type *base; /*!< LPSPI peripheral base address. */
+ lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */
+} lpspi_master_edma_private_handle_t;
+
+/*!
+ * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
+ */
+typedef struct _lpspi_slave_edma_private_handle
+{
+ LPSPI_Type *base; /*!< LPSPI peripheral base address. */
+ lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */
+} lpspi_slave_edma_private_handle_t;
+
+/***********************************************************************************************************************
+ * Prototypes
+ ***********************************************************************************************************************/
+
+/*!
+ * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA.
+ * This is not a public API.
+ */
+static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+
+/*!
+ * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA.
+ * This is not a public API.
+ */
+static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+
+static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
+
+/***********************************************************************************************************************
+ * Variables
+ ***********************************************************************************************************************/
+/*! @brief Pointers to lpspi bases for each instance. */
+static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
+
+/*! @brief Pointers to lpspi edma handles for each instance. */
+static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
+static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
+
+/***********************************************************************************************************************
+ * Code
+ ***********************************************************************************************************************/
+static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
+{
+ assert(rxData != NULL);
+
+ switch (bytesEachRead)
+ {
+ case 1:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ break;
+
+ case 4:
+
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Initializes the LPSPI master eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx and Tx are the same source) DMA
+ * request source.
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaIntermediaryToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
+ * param callback LPSPI callback.
+ * param userData callback function parameter.
+ * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_master_edma_handle_t *handle,
+ lpspi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle)
+{
+ assert(handle != NULL);
+ assert(edmaRxRegToRxDataHandle != NULL);
+ assert(edmaTxDataToTxRegHandle != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = LPSPI_GetInstance(base);
+
+ s_lpspiMasterEdmaPrivateHandle[instance].base = base;
+ s_lpspiMasterEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
+}
+
+static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base)
+{
+ /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+}
+
+/*!
+ * brief LPSPI master transfer data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ /* Disable module before configuration */
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, true))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_PrepareTransferEDMA(base);
+
+ /* Variables */
+ bool isThereExtraTxBytes = false;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ bool isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
+ uint32_t instance = LPSPI_GetInstance(base);
+ uint8_t dummyData = g_lpspiDummyData[instance];
+ uint8_t bytesLastWrite = 0;
+ /*Used for byte swap*/
+ uint32_t addrOffset = 0;
+ uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ edma_transfer_config_t transferConfigRx = {0};
+ edma_transfer_config_t transferConfigTx = {0};
+ edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+
+ handle->state = (uint8_t)kLPSPI_Busy;
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+ handle->isPcsContinuous = isPcsContinuous;
+ handle->isByteSwap = isByteSwap;
+ handle->isThereExtraRxBytes = false;
+
+ /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
+ LPSPI_SetFifoWatermarks(base, 0U, 0U);
+
+ /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
+ * hard to controlled by software. */
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+
+ handle->bytesLastRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+
+ handle->bytesLastRead = 4U;
+
+ if ((transfer->dataSize % 4U) != 0U)
+ {
+ bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
+ handle->bytesLastRead = bytesLastWrite;
+
+ isThereExtraTxBytes = true;
+
+ --handle->writeRegRemainingTimes;
+
+ --handle->readRegRemainingTimes;
+ handle->isThereExtraRxBytes = true;
+ }
+ }
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
+ &s_lpspiMasterEdmaPrivateHandle[instance]);
+
+ /* Configure rx EDMA transfer */
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ if (handle->rxData != NULL)
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigRx.destOffset = 1;
+ }
+ else
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigRx.destOffset = 0;
+ }
+ transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigRx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset;
+ transferConfigRx.srcOffset = 0;
+
+ transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */
+ handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigRx, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ (uint32_t)kEDMA_MajorInterruptEnable);
+
+ /* Configure tx EDMA transfer */
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+
+ if (isThereExtraTxBytes)
+ {
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ addrOffset = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_extraBytes);
+
+ if (handle->isPcsContinuous)
+ {
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous);
+ }
+ else
+ {
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
+ }
+ }
+
+ if (handle->isPcsContinuous)
+ {
+ handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK);
+
+ transferConfigTx.srcAddr = (uint32_t) & (handle->transmitCommand);
+ transferConfigTx.srcOffset = 0;
+
+ transferConfigTx.destAddr = (uint32_t) & (base->TCR);
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_pcsContinuous);
+ EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL);
+ }
+
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t)(handle->txData);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ addrOffset = 0U;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+
+ transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
+
+ if (isThereExtraTxBytes)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_extraBytes);
+ }
+ else if (handle->isPcsContinuous)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_pcsContinuous);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, NULL);
+ }
+
+ EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+ LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ return kStatus_Success;
+}
+
+static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle != NULL);
+ assert(g_lpspiEdmaPrivateHandle != NULL);
+
+ uint32_t readData;
+
+ lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle;
+
+ lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
+
+ size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
+ uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
+ bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
+
+ LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
+
+ if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
+ {
+ while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
+ {
+ }
+ readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
+
+ if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
+ {
+ LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
+ readData, bytesLastRead, isByteSwap);
+ }
+ }
+
+ lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (lpspiEdmaPrivateHandle->handle->callback != NULL)
+ {
+ lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
+ kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
+ }
+}
+
+/*!
+ * brief LPSPI master aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+}
+
+/*!
+ * brief Gets the master eDMA transfer remaining bytes.
+ *
+ * This function gets the master eDMA transfer remaining bytes.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the EDMA transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ remainingByte =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the LPSPI slave eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx as the same source) DMA request
+ * source.
+ *
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaTxDataToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
+ *
+ * param base LPSPI peripheral base address.
+ * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
+ * param callback LPSPI callback.
+ * param userData callback function parameter.
+ * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_slave_edma_handle_t *handle,
+ lpspi_slave_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle)
+{
+ assert(handle != NULL);
+ assert(edmaRxRegToRxDataHandle != NULL);
+ assert(edmaTxDataToTxRegHandle != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = LPSPI_GetInstance(base);
+
+ s_lpspiSlaveEdmaPrivateHandle[instance].base = base;
+ s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
+}
+
+/*!
+ * brief LPSPI slave transfers data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ /* Disable module before configuration. */
+ LPSPI_Enable(base, false);
+ /* Check arguements, also dma transfer can not support 3 bytes */
+ if (!LPSPI_CheckTransferArgument(base, transfer, true))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_PrepareTransferEDMA(base);
+
+ /* Variables */
+ bool isThereExtraTxBytes = false;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ uint8_t bytesLastWrite = 0;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t mask = (uint32_t)kLPSPI_RxDmaEnable;
+
+ /* Used for byte swap */
+ uint32_t addrOffset = 0;
+ uint32_t instance = LPSPI_GetInstance(base);
+ uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ edma_transfer_config_t transferConfigRx = {0};
+ edma_transfer_config_t transferConfigTx = {0};
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+ handle->isByteSwap = isByteSwap;
+ handle->isThereExtraRxBytes = false;
+
+ /* Because DMA is fast enough, set the RX and TX watermarks to 0. */
+ LPSPI_SetFifoWatermarks(base, 0U, 0U);
+
+ /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at
+ any time since we use rx dma transfer finish cllback to indicate transfer finish. */
+ base->TCR =
+ (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) |
+ LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+
+ handle->bytesLastRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+
+ handle->bytesLastRead = 4U;
+
+ if ((transfer->dataSize % 4U) != 0U)
+ {
+ bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
+ handle->bytesLastRead = bytesLastWrite;
+
+ isThereExtraTxBytes = true;
+ --handle->writeRegRemainingTimes;
+
+ handle->isThereExtraRxBytes = true;
+ --handle->readRegRemainingTimes;
+ }
+ }
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback,
+ &s_lpspiSlaveEdmaPrivateHandle[instance]);
+
+ /*Rx*/
+ if (handle->readRegRemainingTimes > 0U)
+ {
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ if (handle->rxData != NULL)
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigRx.destOffset = 1;
+ }
+ else
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigRx.destOffset = 0;
+ }
+ transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigRx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset;
+ transferConfigRx.srcOffset = 0;
+
+ transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
+
+ /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
+ handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigRx, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ (uint32_t)kEDMA_MajorInterruptEnable);
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+ }
+
+ /*Tx*/
+ if (handle->txData != NULL)
+ {
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+ if (isThereExtraTxBytes)
+ {
+ transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
+ transferConfigTx.srcOffset = 1;
+ transferConfigTx.destOffset = 0;
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ addrOffset = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_extraBytes);
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
+ }
+
+ transferConfigTx.srcAddr = (uint32_t)(handle->txData);
+ transferConfigTx.srcOffset = 1;
+ transferConfigTx.destOffset = 0;
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+ transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
+
+ if (isThereExtraTxBytes)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_extraBytes);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, NULL);
+ }
+ EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
+ mask |= (uint32_t)kLPSPI_TxDmaEnable;
+ }
+
+ LPSPI_EnableDMA(base, mask);
+
+ return kStatus_Success;
+}
+
+static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle != NULL);
+ assert(g_lpspiEdmaPrivateHandle != NULL);
+
+ uint32_t readData;
+
+ lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle;
+
+ lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
+
+ size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
+ uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
+ bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
+
+ LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
+
+ if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
+ {
+ while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
+ {
+ }
+ readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
+
+ if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
+ {
+ LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
+ readData, bytesLastRead, isByteSwap);
+ }
+ }
+
+ lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (lpspiEdmaPrivateHandle->handle->callback != NULL)
+ {
+ lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
+ kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
+ }
+}
+
+/*!
+ * brief LPSPI slave aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+}
+
+/*!
+ * brief Gets the slave eDMA transfer remaining bytes.
+ *
+ * This function gets the slave eDMA transfer remaining bytes.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the eDMA transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ remainingByte =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h
new file mode 100644
index 0000000000..02ce26103f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPSPI_EDMA_H_
+#define _FSL_LPSPI_EDMA_H_
+
+#include "fsl_lpspi.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup lpspi_edma_driver
+ * @{
+ */
+
+/***********************************************************************************************************************
+ * Definitions
+ **********************************************************************************************************************/
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI EDMA driver version. */
+#define FSL_LPSPI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 3, 1))
+/*@}*/
+
+/*!
+ * @brief Forward declaration of the _lpspi_master_edma_handle typedefs.
+ */
+typedef struct _lpspi_master_edma_handle lpspi_master_edma_handle_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_slave_edma_handle typedefs.
+ */
+typedef struct _lpspi_slave_edma_handle lpspi_slave_edma_handle_t;
+
+/*!
+ * @brief Completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle Pointer to the handle for the LPSPI master.
+ * @param status Success or error code describing whether the transfer completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_master_edma_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_master_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+/*!
+ * @brief Completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle Pointer to the handle for the LPSPI slave.
+ * @param status Success or error code describing whether the transfer completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_slave_edma_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_slave_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief LPSPI master eDMA transfer handle structure used for transactional API. */
+struct _lpspi_master_edma_handle
+{
+ volatile bool isPcsContinuous; /*!< Is PCS continuous in transfer. */
+
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ volatile uint8_t bytesLastRead; /*!< Bytes for last read RDR. */
+ volatile bool isThereExtraRxBytes; /*!< Is there extra RX byte. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if there is not txData for DMA purpose.*/
+ uint32_t rxBuffIfNull; /*!< Used if there is not rxData for DMA purpose.*/
+
+ uint32_t transmitCommand; /*!< Used to write TCR for DMA purpose.*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ lpspi_master_edma_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+
+ edma_handle_t *edmaRxRegToRxDataHandle; /*!<edma_handle_t handle point used for RxReg to RxData buff*/
+ edma_handle_t *edmaTxDataToTxRegHandle; /*!<edma_handle_t handle point used for TxData to TxReg buff*/
+
+ edma_tcd_t lpspiSoftwareTCD[3]; /*!<SoftwareTCD, internal used*/
+};
+
+/*! @brief LPSPI slave eDMA transfer handle structure used for transactional API.*/
+struct _lpspi_slave_edma_handle
+{
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ volatile uint8_t bytesLastRead; /*!< Bytes for last read RDR. */
+ volatile bool isThereExtraRxBytes; /*!< Is there extra RX byte. */
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if there is not txData for DMA purpose.*/
+ uint32_t rxBuffIfNull; /*!< Used if there is not rxData for DMA purpose.*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state.*/
+
+ uint32_t errorCount; /*!< Error count for slave transfer.*/
+
+ lpspi_slave_edma_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+
+ edma_handle_t *edmaRxRegToRxDataHandle; /*!<edma_handle_t handle point used for RxReg to RxData buff*/
+ edma_handle_t *edmaTxDataToTxRegHandle; /*!<edma_handle_t handle point used for TxData to TxReg*/
+
+ edma_tcd_t lpspiSoftwareTCD[2]; /*!<SoftwareTCD, internal used*/
+};
+
+/***********************************************************************************************************************
+ * API
+ **********************************************************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*Transactional APIs*/
+
+/*!
+ * @brief Initializes the LPSPI master eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that the LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx are the same source) DMA
+ * request source.
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaTxDataToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Tx DMAMUX source for edmaRxRegToRxDataHandle.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
+ * @param callback LPSPI callback.
+ * @param userData callback function parameter.
+ * @param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * @param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_master_edma_handle_t *handle,
+ lpspi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle);
+
+/*!
+ * @brief LPSPI master transfer data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * @param transfer pointer to lpspi_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @brief LPSPI master aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the master eDMA transfer remaining bytes.
+ *
+ * This function gets the master eDMA transfer remaining bytes.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the EDMA transaction.
+ * @return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Initializes the LPSPI slave eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx as the same source) DMA request
+ * source.
+ *
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaTxDataToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
+ * @param callback LPSPI callback.
+ * @param userData callback function parameter.
+ * @param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * @param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_slave_edma_handle_t *handle,
+ lpspi_slave_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle);
+
+/*!
+ * @brief LPSPI slave transfers data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * @param transfer pointer to lpspi_transfer_t structure.
+ * @return status of status_t.
+ */
+status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @brief LPSPI slave aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the slave eDMA transfer remaining bytes.
+ *
+ * This function gets the slave eDMA transfer remaining bytes.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * @param count Number of bytes transferred so far by the eDMA transaction.
+ * @return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /*_FSL_LPSPI_EDMA_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h
new file mode 100644
index 0000000000..ab4c647907
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __FSL_LPSPI_FREERTOS_H__
+#define __FSL_LPSPI_FREERTOS_H__
+
+#include "FreeRTOS.h"
+#include "portable.h"
+#include "semphr.h"
+
+#include "fsl_lpspi.h"
+
+/*!
+ * @addtogroup lpspi_freertos_driver LPSPI FreeRTOS Driver
+ * @{
+ */
+
+/**********************************************************************************************************************
+ * Definitions
+ *********************************************************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI FreeRTOS driver version 2.3.1. */
+#define FSL_LPSPI_FREERTOS_DRIVER_VERSION (MAKE_VERSION(2, 3, 1))
+/*@}*/
+
+/*!
+ * @cond RTOS_PRIVATE
+ * @brief LPSPI FreeRTOS handle
+ */
+typedef struct _lpspi_rtos_handle
+{
+ LPSPI_Type *base; /*!< LPSPI base address */
+ lpspi_master_handle_t drv_handle; /*!< Handle of the underlying driver, treated as opaque by the RTOS layer */
+ status_t async_status;
+ SemaphoreHandle_t mutex; /*!< Mutex to lock the handle during a trasfer */
+ SemaphoreHandle_t event; /*!< Semaphore to notify and unblock task when transfer ends */
+} lpspi_rtos_handle_t;
+/*! \endcond */
+
+/**********************************************************************************************************************
+ * API
+ *********************************************************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name LPSPI RTOS Operation
+ * @{
+ */
+
+/*!
+ * @brief Initializes LPSPI.
+ *
+ * This function initializes the LPSPI module and related RTOS context.
+ *
+ * @param handle The RTOS LPSPI handle, the pointer to an allocated space for RTOS context.
+ * @param base The pointer base address of the LPSPI instance to initialize.
+ * @param masterConfig Configuration structure to set-up LPSPI in master mode.
+ * @param srcClock_Hz Frequency of input clock of the LPSPI module.
+ * @return status of the operation.
+ */
+status_t LPSPI_RTOS_Init(lpspi_rtos_handle_t *handle,
+ LPSPI_Type *base,
+ const lpspi_master_config_t *masterConfig,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPSPI.
+ *
+ * This function deinitializes the LPSPI module and related RTOS context.
+ *
+ * @param handle The RTOS LPSPI handle.
+ */
+status_t LPSPI_RTOS_Deinit(lpspi_rtos_handle_t *handle);
+
+/*!
+ * @brief Performs SPI transfer.
+ *
+ * This function performs an SPI transfer according to data given in the transfer structure.
+ *
+ * @param handle The RTOS LPSPI handle.
+ * @param transfer Structure specifying the transfer parameters.
+ * @return status of the operation.
+ */
+status_t LPSPI_RTOS_Transfer(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* __FSL_LPSPI_FREERTOS_H__ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.c
new file mode 100644
index 0000000000..e847de6bb0
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.c
@@ -0,0 +1,2368 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpuart.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpuart"
+#endif
+
+/* LPUART transfer state. */
+enum
+{
+ kLPUART_TxIdle, /*!< TX idle. */
+ kLPUART_TxBusy, /*!< TX busy. */
+ kLPUART_RxIdle, /*!< RX idle. */
+ kLPUART_RxBusy /*!< RX busy. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Check whether the RX ring buffer is full.
+ *
+ * @userData handle LPUART handle pointer.
+ * @retval true RX ring buffer is full.
+ * @retval false RX ring buffer is not full.
+ */
+static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Write to TX register using non-blocking method.
+ *
+ * This function writes data to the TX register directly, upper layer must make
+ * sure the TX register is empty or TX FIFO has empty room before calling this function.
+ *
+ * @note This function does not check whether all the data has been sent out to bus,
+ * so before disable TX, check kLPUART_TransmissionCompleteFlag to ensure the TX is
+ * finished.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the data to write.
+ * @param length Size of the buffer to be sent.
+ */
+static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length);
+
+/*!
+ * @brief Read RX register using non-blocking method.
+ *
+ * This function reads data from the TX register directly, upper layer must make
+ * sure the RX register is full or TX FIFO has data before calling this function.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the buffer to store the received data.
+ * @param length Size of the buffer.
+ */
+static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length);
+
+/*!
+ * @brief LPUART_TransferHandleIDLEIsReady handle function.
+ * This function handles when IDLE is ready.
+ *
+ * @param base LPUART peripheral base address.
+ * @param irqHandle LPUART handle pointer.
+ */
+static void LPUART_TransferHandleIDLEReady(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief LPUART_TransferHandleReceiveDataIsFull handle function.
+ * This function handles when receive data is full.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ */
+static void LPUART_TransferHandleReceiveDataFull(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief LPUART_TransferHandleSendDataIsEmpty handle function.
+ * This function handles when send data is empty.
+ *
+ * @param base LPUART peripheral base address.
+ * @param irqHandle LPUART handle pointer.
+ */
+static void LPUART_TransferHandleSendDataEmpty(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief LPUART_TransferHandleTransmissionIsComplete handle function.
+ * This function handles Transmission complete and the interrupt is enabled.
+ *
+ * @param base LPUART peripheral base address.
+ * @param irqHandle LPUART handle pointer.
+ */
+static void LPUART_TransferHandleTransmissionComplete(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Array of LPUART peripheral base address. */
+static LPUART_Type *const s_lpuartBases[] = LPUART_BASE_PTRS;
+/* Array of LPUART handle. */
+void *s_lpuartHandle[ARRAY_SIZE(s_lpuartBases)];
+/* Array of LPUART IRQ number. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+static const IRQn_Type s_lpuartRxIRQ[] = LPUART_RX_IRQS;
+const IRQn_Type s_lpuartTxIRQ[] = LPUART_TX_IRQS;
+#else
+const IRQn_Type s_lpuartIRQ[] = LPUART_RX_TX_IRQS;
+#endif
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of LPUART clock name. */
+static const clock_ip_name_t s_lpuartClock[] = LPUART_CLOCKS;
+
+#if defined(LPUART_PERIPH_CLOCKS)
+/* Array of LPUART functional clock name. */
+static const clock_ip_name_t s_lpuartPeriphClocks[] = LPUART_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* LPUART ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+lpuart_isr_t s_lpuartIsr[ARRAY_SIZE(s_lpuartBases)] = {[0 ...(ARRAY_SIZE(s_lpuartBases) - 1)] =
+ (lpuart_isr_t)DefaultISR};
+#else
+lpuart_isr_t s_lpuartIsr[ARRAY_SIZE(s_lpuartBases)];
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Get the LPUART instance from peripheral base address.
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART instance.
+ */
+uint32_t LPUART_GetInstance(LPUART_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_lpuartBases); instance++)
+ {
+ if (s_lpuartBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lpuartBases));
+
+ return instance;
+}
+
+/*!
+ * brief Get the length of received data in RX ring buffer.
+ *
+ * userData handle LPUART handle pointer.
+ * return Length of received data in RX ring buffer.
+ */
+size_t LPUART_TransferGetRxRingBufferLength(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ size_t size;
+ size_t tmpRxRingBufferSize = handle->rxRingBufferSize;
+ uint16_t tmpRxRingBufferTail = handle->rxRingBufferTail;
+ uint16_t tmpRxRingBufferHead = handle->rxRingBufferHead;
+
+ if (tmpRxRingBufferTail > tmpRxRingBufferHead)
+ {
+ size = ((size_t)tmpRxRingBufferHead + tmpRxRingBufferSize - (size_t)tmpRxRingBufferTail);
+ }
+ else
+ {
+ size = ((size_t)tmpRxRingBufferHead - (size_t)tmpRxRingBufferTail);
+ }
+
+ return size;
+}
+
+static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ bool full;
+
+ if (LPUART_TransferGetRxRingBufferLength(base, handle) == (handle->rxRingBufferSize - 1U))
+ {
+ full = true;
+ }
+ else
+ {
+ full = false;
+ }
+ return full;
+}
+
+static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ size_t i;
+
+ /* The Non Blocking write data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+ base->DATA = data[i];
+ }
+}
+
+static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ size_t i;
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+ /* The Non Blocking read data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (isSevenDataBits)
+ {
+ data[i] = (uint8_t)(base->DATA & 0x7FU);
+ }
+ else
+ {
+ data[i] = (uint8_t)base->DATA;
+ }
+#else
+ data[i] = (uint8_t)(base->DATA);
+#endif
+ }
+}
+
+/*!
+ * brief Initializes an LPUART instance with the user configuration structure and the peripheral clock.
+ *
+ * This function configures the LPUART module with user-defined settings. Call the LPUART_GetDefaultConfig() function
+ * to configure the configuration structure and get the default configuration.
+ * The example below shows how to use this API to configure the LPUART.
+ * code
+ * lpuart_config_t lpuartConfig;
+ * lpuartConfig.baudRate_Bps = 115200U;
+ * lpuartConfig.parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig.dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig.isMsb = false;
+ * lpuartConfig.stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig.txFifoWatermark = 0;
+ * lpuartConfig.rxFifoWatermark = 1;
+ * LPUART_Init(LPUART1, &lpuartConfig, 20000000U);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param config Pointer to a user-defined configuration structure.
+ * param srcClock_Hz LPUART clock source frequency in HZ.
+ * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not support in current clock source.
+ * retval kStatus_Success LPUART initialize succeed
+ */
+#ifndef __rtems__
+status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz)
+#else /* __rtems__ */
+status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz, bool do_reset)
+#endif /* __rtems__ */
+{
+ assert(NULL != config);
+ assert(0U < config->baudRate_Bps);
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) > config->txFifoWatermark);
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) > config->rxFifoWatermark);
+#endif
+
+ status_t status = kStatus_Success;
+ uint32_t temp;
+ uint16_t sbr, sbrTemp;
+ uint8_t osr, osrTemp;
+ uint32_t tempDiff, calculatedBaud, baudDiff;
+
+ /* This LPUART instantiation uses a slightly different baud rate calculation
+ * The idea is to use the best OSR (over-sampling rate) possible
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations
+ * loop to find the best OSR value possible, one that generates minimum baudDiff
+ * iterate through the rest of the supported values of OSR */
+
+ baudDiff = config->baudRate_Bps;
+ osr = 0U;
+ sbr = 0U;
+ for (osrTemp = 4U; osrTemp <= 32U; osrTemp++)
+ {
+ /* calculate the temporary sbr value */
+ sbrTemp = (uint16_t)((srcClock_Hz * 10U / (config->baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U);
+ /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/
+ if (sbrTemp == 0U)
+ {
+ sbrTemp = 1U;
+ }
+ /* Calculate the baud rate based on the temporary OSR and SBR values */
+ calculatedBaud = (srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp));
+ tempDiff = calculatedBaud > config->baudRate_Bps ? (calculatedBaud - config->baudRate_Bps) :
+ (config->baudRate_Bps - calculatedBaud);
+
+ if (tempDiff <= baudDiff)
+ {
+ baudDiff = tempDiff;
+ osr = osrTemp; /* update and store the best OSR value calculated */
+ sbr = sbrTemp; /* update store the best SBR value calculated */
+ }
+ }
+
+#ifndef __rtems__
+ /* Check to see if actual baud rate is within 3% of desired baud rate
+ * based on the best calculate OSR value */
+ if (baudDiff > ((config->baudRate_Bps / 100U) * 3U))
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ status = kStatus_LPUART_BaudrateNotSupport;
+ }
+ else
+#else /* __rtems__ */
+ /*
+ * Better to have any baudrate then none. With this change, the function can
+ * not fail any more.
+ */
+#endif /* __rtems__ */
+ {
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPUART_GetInstance(base);
+
+ /* Enable lpuart clock */
+ (void)CLOCK_EnableClock(s_lpuartClock[instance]);
+#if defined(LPUART_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_lpuartPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_LPUART_HAS_GLOBAL) && FSL_FEATURE_LPUART_HAS_GLOBAL
+ /*Reset all internal logic and registers, except the Global Register */
+#ifndef __rtems__
+ LPUART_SoftwareReset(base);
+#else /* __rtems__ */
+ if (do_reset) {
+ LPUART_SoftwareReset(base);
+ }
+#endif /* __rtems__ */
+#else
+ /* Disable LPUART TX RX before setting. */
+ base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK);
+#endif
+
+ temp = base->BAUD;
+
+ /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling.
+ * If so, then "BOTHEDGE" sampling must be turned on */
+ if ((osr > 3U) && (osr < 8U))
+ {
+ temp |= LPUART_BAUD_BOTHEDGE_MASK;
+ }
+
+ /* program the osr value (bit value is one less than actual value) */
+ temp &= ~LPUART_BAUD_OSR_MASK;
+ temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL);
+
+ /* write the sbr value to the BAUD registers */
+ temp &= ~LPUART_BAUD_SBR_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBR(sbr);
+
+ /* Set bit count and parity mode. */
+ base->BAUD &= ~LPUART_BAUD_M10_MASK;
+
+ temp = base->CTRL & ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
+ LPUART_CTRL_IDLECFG_MASK);
+
+ temp |= (uint8_t)config->parityMode | LPUART_CTRL_IDLECFG(config->rxIdleConfig) |
+ LPUART_CTRL_ILT(config->rxIdleType);
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (kLPUART_SevenDataBits == config->dataBitsCount)
+ {
+ if (kLPUART_ParityDisabled != config->parityMode)
+ {
+ temp &= ~LPUART_CTRL_M7_MASK; /* Seven data bits and one parity bit */
+ }
+ else
+ {
+ temp |= LPUART_CTRL_M7_MASK;
+ }
+ }
+ else
+#endif
+ {
+ if (kLPUART_ParityDisabled != config->parityMode)
+ {
+ temp |= LPUART_CTRL_M_MASK; /* Eight data bits and one parity bit */
+ }
+ }
+
+ base->CTRL = temp;
+
+#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
+ /* set stop bit per char */
+ temp = base->BAUD & ~LPUART_BAUD_SBNS_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBNS((uint8_t)config->stopBitCount);
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Set tx/rx WATER watermark
+ Note:
+ Take care of the RX FIFO, RX interrupt request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ RX interrupt because the water mark is 2.
+ */
+ base->WATER = (((uint32_t)(config->rxFifoWatermark) << 16U) | config->txFifoWatermark);
+
+ /* Enable tx/rx FIFO */
+ base->FIFO |= (LPUART_FIFO_TXFE_MASK | LPUART_FIFO_RXFE_MASK);
+
+ /* Flush FIFO */
+ base->FIFO |= (LPUART_FIFO_TXFLUSH_MASK | LPUART_FIFO_RXFLUSH_MASK);
+#endif
+
+ /* Clear all status flags */
+ temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK);
+
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp |= LPUART_STAT_LBKDIF_MASK;
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK);
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ /* Set the CTS configuration/TX CTS source. */
+ base->MODIR |= LPUART_MODIR_TXCTSC(config->txCtsConfig) | LPUART_MODIR_TXCTSSRC(config->txCtsSource);
+ if (true == config->enableRxRTS)
+ {
+ /* Enable the receiver RTS(request-to-send) function. */
+ base->MODIR |= LPUART_MODIR_RXRTSE_MASK;
+ }
+ if (true == config->enableTxCTS)
+ {
+ /* Enable the CTS(clear-to-send) function. */
+ base->MODIR |= LPUART_MODIR_TXCTSE_MASK;
+ }
+#endif
+
+ /* Set data bits order. */
+ if (true == config->isMsb)
+ {
+ temp |= LPUART_STAT_MSBF_MASK;
+ }
+ else
+ {
+ temp &= ~LPUART_STAT_MSBF_MASK;
+ }
+
+ base->STAT |= temp;
+
+ /* Enable TX/RX base on configure structure. */
+ temp = base->CTRL;
+ if (true == config->enableTx)
+ {
+ temp |= LPUART_CTRL_TE_MASK;
+ }
+
+ if (true == config->enableRx)
+ {
+ temp |= LPUART_CTRL_RE_MASK;
+ }
+
+ base->CTRL = temp;
+ }
+
+ return status;
+}
+/*!
+ * brief Deinitializes a LPUART instance.
+ *
+ * This function waits for transmit to complete, disables TX and RX, and disables the LPUART clock.
+ *
+ * param base LPUART peripheral base address.
+ */
+void LPUART_Deinit(LPUART_Type *base)
+{
+ uint32_t temp;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Wait tx FIFO send out*/
+ while (0U != ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXWATER_SHIFT))
+ {
+ }
+#endif
+ /* Wait last char shift out */
+ while (0U == (base->STAT & LPUART_STAT_TC_MASK))
+ {
+ }
+
+ /* Clear all status flags */
+ temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK);
+
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp |= LPUART_STAT_LBKDIF_MASK;
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK);
+#endif
+
+ base->STAT |= temp;
+
+ /* Disable the module. */
+ base->CTRL = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = LPUART_GetInstance(base);
+
+ /* Disable lpuart clock */
+ (void)CLOCK_DisableClock(s_lpuartClock[instance]);
+
+#if defined(LPUART_PERIPH_CLOCKS)
+ (void)CLOCK_DisableClock(s_lpuartPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the LPUART configuration structure to a default value. The default
+ * values are:
+ * lpuartConfig->baudRate_Bps = 115200U;
+ * lpuartConfig->parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig->dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig->isMsb = false;
+ * lpuartConfig->stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig->txFifoWatermark = 0;
+ * lpuartConfig->rxFifoWatermark = 1;
+ * lpuartConfig->rxIdleType = kLPUART_IdleTypeStartBit;
+ * lpuartConfig->rxIdleConfig = kLPUART_IdleCharacter1;
+ * lpuartConfig->enableTx = false;
+ * lpuartConfig->enableRx = false;
+ *
+ * param config Pointer to a configuration structure.
+ */
+void LPUART_GetDefaultConfig(lpuart_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->baudRate_Bps = 115200U;
+ config->parityMode = kLPUART_ParityDisabled;
+ config->dataBitsCount = kLPUART_EightDataBits;
+ config->isMsb = false;
+#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
+ config->stopBitCount = kLPUART_OneStopBit;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ config->txFifoWatermark = 0U;
+ config->rxFifoWatermark = 0U;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ config->enableRxRTS = false;
+ config->enableTxCTS = false;
+ config->txCtsConfig = kLPUART_CtsSampleAtStart;
+ config->txCtsSource = kLPUART_CtsSourcePin;
+#endif
+ config->rxIdleType = kLPUART_IdleTypeStartBit;
+ config->rxIdleConfig = kLPUART_IdleCharacter1;
+ config->enableTx = false;
+ config->enableRx = false;
+}
+
+/*!
+ * brief Sets the LPUART instance baudrate.
+ *
+ * This function configures the LPUART module baudrate. This function is used to update
+ * the LPUART module baudrate after the LPUART module is initialized by the LPUART_Init.
+ * code
+ * LPUART_SetBaudRate(LPUART1, 115200U, 20000000U);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param baudRate_Bps LPUART baudrate to be set.
+ * param srcClock_Hz LPUART clock source frequency in HZ.
+ * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not supported in the current clock source.
+ * retval kStatus_Success Set baudrate succeeded.
+ */
+status_t LPUART_SetBaudRate(LPUART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ assert(0U < baudRate_Bps);
+
+ status_t status = kStatus_Success;
+ uint32_t temp, oldCtrl;
+ uint16_t sbr, sbrTemp;
+ uint8_t osr, osrTemp;
+ uint32_t tempDiff, calculatedBaud, baudDiff;
+
+ /* This LPUART instantiation uses a slightly different baud rate calculation
+ * The idea is to use the best OSR (over-sampling rate) possible
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations
+ * loop to find the best OSR value possible, one that generates minimum baudDiff
+ * iterate through the rest of the supported values of OSR */
+
+ baudDiff = baudRate_Bps;
+ osr = 0U;
+ sbr = 0U;
+ for (osrTemp = 4U; osrTemp <= 32U; osrTemp++)
+ {
+ /* calculate the temporary sbr value */
+ sbrTemp = (uint16_t)((srcClock_Hz * 10U / (baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U);
+ /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/
+ if (sbrTemp == 0U)
+ {
+ sbrTemp = 1U;
+ }
+ /* Calculate the baud rate based on the temporary OSR and SBR values */
+ calculatedBaud = srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp);
+
+ tempDiff = calculatedBaud > baudRate_Bps ? (calculatedBaud - baudRate_Bps) : (baudRate_Bps - calculatedBaud);
+
+ if (tempDiff <= baudDiff)
+ {
+ baudDiff = tempDiff;
+ osr = osrTemp; /* update and store the best OSR value calculated */
+ sbr = sbrTemp; /* update store the best SBR value calculated */
+ }
+ }
+
+ /* Check to see if actual baud rate is within 3% of desired baud rate
+ * based on the best calculate OSR value */
+ if (baudDiff < (uint32_t)((baudRate_Bps / 100U) * 3U))
+ {
+ /* Store CTRL before disable Tx and Rx */
+ oldCtrl = base->CTRL;
+
+ /* Disable LPUART TX RX before setting. */
+ base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK);
+
+ temp = base->BAUD;
+
+ /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling.
+ * If so, then "BOTHEDGE" sampling must be turned on */
+ if ((osr > 3U) && (osr < 8U))
+ {
+ temp |= LPUART_BAUD_BOTHEDGE_MASK;
+ }
+
+ /* program the osr value (bit value is one less than actual value) */
+ temp &= ~LPUART_BAUD_OSR_MASK;
+ temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL);
+
+ /* write the sbr value to the BAUD registers */
+ temp &= ~LPUART_BAUD_SBR_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBR(sbr);
+
+ /* Restore CTRL. */
+ base->CTRL = oldCtrl;
+ }
+ else
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ status = kStatus_LPUART_BaudrateNotSupport;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enable 9-bit data mode for LPUART.
+ *
+ * This function set the 9-bit mode for LPUART module. The 9th bit is not used for parity thus can be modified by user.
+ *
+ * param base LPUART peripheral base address.
+ * param enable true to enable, flase to disable.
+ */
+void LPUART_Enable9bitMode(LPUART_Type *base, bool enable)
+{
+ assert(base != NULL);
+
+ uint32_t temp = 0U;
+
+ if (enable)
+ {
+ /* Set LPUART_CTRL_M for 9-bit mode, clear LPUART_CTRL_PE to disable parity. */
+ temp = base->CTRL & ~((uint32_t)LPUART_CTRL_PE_MASK | (uint32_t)LPUART_CTRL_M_MASK);
+ temp |= (uint32_t)LPUART_CTRL_M_MASK;
+ base->CTRL = temp;
+ }
+ else
+ {
+ /* Clear LPUART_CTRL_M. */
+ base->CTRL &= ~(uint32_t)LPUART_CTRL_M_MASK;
+ }
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ /* Clear LPUART_CTRL_M7 to disable 7-bit mode. */
+ base->CTRL &= ~(uint32_t)LPUART_CTRL_M7_MASK;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_10BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_10BIT_DATA_SUPPORT
+ /* Clear LPUART_BAUD_M10 to disable 10-bit mode. */
+ base->BAUD &= ~(uint32_t)LPUART_BAUD_M10_MASK;
+#endif
+}
+
+/*!
+ * brief Transmit an address frame in 9-bit data mode.
+ *
+ * param base LPUART peripheral base address.
+ * param address LPUART slave address.
+ */
+void LPUART_SendAddress(LPUART_Type *base, uint8_t address)
+{
+ assert(base != NULL);
+
+ uint32_t temp = base->DATA & 0xFFFFFC00UL;
+ temp |= ((uint32_t)address | (1UL << LPUART_DATA_R8T8_SHIFT));
+ base->DATA = temp;
+}
+
+/*!
+ * brief Enables LPUART interrupts according to a provided mask.
+ *
+ * This function enables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See the ref _lpuart_interrupt_enable.
+ * This examples shows how to enable TX empty interrupt and RX full interrupt:
+ * code
+ * LPUART_EnableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param mask The interrupts to enable. Logical OR of ref _lpuart_interrupt_enable.
+ */
+void LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask)
+{
+ /* Only consider the real interrupt enable bits. */
+ mask &= (uint32_t)kLPUART_AllInterruptEnable;
+
+ /* Check int enable bits in base->BAUD */
+ uint32_t tempReg = base->BAUD;
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ tempReg |= ((mask << 8U) & LPUART_BAUD_LBKDIE_MASK);
+ /* Clear bit 7 from mask */
+ mask &= ~(uint32_t)kLPUART_LinBreakInterruptEnable;
+#endif
+ tempReg |= ((mask << 8U) & LPUART_BAUD_RXEDGIE_MASK);
+ /* Clear bit 6 from mask */
+ mask &= ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable;
+ base->BAUD = tempReg;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Check int enable bits in base->FIFO */
+ base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) |
+ (mask & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK));
+ /* Clear bit 9 and bit 8 from mask */
+ mask &= ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable);
+#endif
+
+ /* Set int enable bits in base->CTRL */
+ base->CTRL |= mask;
+}
+
+/*!
+ * brief Disables LPUART interrupts according to a provided mask.
+ *
+ * This function disables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See ref _lpuart_interrupt_enable.
+ * This example shows how to disable the TX empty interrupt and RX full interrupt:
+ * code
+ * LPUART_DisableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param mask The interrupts to disable. Logical OR of ref _lpuart_interrupt_enable.
+ */
+void LPUART_DisableInterrupts(LPUART_Type *base, uint32_t mask)
+{
+ /* Only consider the real interrupt enable bits. */
+ mask &= (uint32_t)kLPUART_AllInterruptEnable;
+ /* Check int enable bits in base->BAUD */
+ uint32_t tempReg = base->BAUD;
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ tempReg &= ~((mask << 8U) & LPUART_BAUD_LBKDIE_MASK);
+ /* Clear bit 7 from mask */
+ mask &= ~(uint32_t)kLPUART_LinBreakInterruptEnable;
+#endif
+ tempReg &= ~((mask << 8U) & LPUART_BAUD_RXEDGIE_MASK);
+ /* Clear bit 6 from mask */
+ mask &= ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable;
+ base->BAUD = tempReg;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Check int enable bits in base->FIFO */
+ base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) &
+ ~(mask & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK));
+ /* Clear bit 9 and bit 8 from mask */
+ mask &= ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable);
+#endif
+
+ /* Check int enable bits in base->CTRL */
+ base->CTRL &= ~mask;
+}
+
+/*!
+ * brief Gets enabled LPUART interrupts.
+ *
+ * This function gets the enabled LPUART interrupts. The enabled interrupts are returned
+ * as the logical OR value of the enumerators ref _lpuart_interrupt_enable. To check
+ * a specific interrupt enable status, compare the return value with enumerators
+ * in ref _lpuart_interrupt_enable.
+ * For example, to check whether the TX empty interrupt is enabled:
+ * code
+ * uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(LPUART1);
+ *
+ * if (kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts)
+ * {
+ * ...
+ * }
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART interrupt flags which are logical OR of the enumerators in ref _lpuart_interrupt_enable.
+ */
+uint32_t LPUART_GetEnabledInterrupts(LPUART_Type *base)
+{
+ /* Check int enable bits in base->CTRL */
+ uint32_t temp = (uint32_t)(base->CTRL & (uint32_t)kLPUART_AllInterruptEnable);
+
+ /* Check int enable bits in base->BAUD */
+ temp = (temp & ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable) | ((base->BAUD & LPUART_BAUD_RXEDGIE_MASK) >> 8U);
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp = (temp & ~(uint32_t)kLPUART_LinBreakInterruptEnable) | ((base->BAUD & LPUART_BAUD_LBKDIE_MASK) >> 8U);
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Check int enable bits in base->FIFO */
+ temp =
+ (temp & ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable)) |
+ (base->FIFO & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK));
+#endif
+
+ return temp;
+}
+
+/*!
+ * brief Gets LPUART status flags.
+ *
+ * This function gets all LPUART status flags. The flags are returned as the logical
+ * OR value of the enumerators ref _lpuart_flags. To check for a specific status,
+ * compare the return value with enumerators in the ref _lpuart_flags.
+ * For example, to check whether the TX is empty:
+ * code
+ * if (kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(LPUART1))
+ * {
+ * ...
+ * }
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART status flags which are ORed by the enumerators in the _lpuart_flags.
+ */
+uint32_t LPUART_GetStatusFlags(LPUART_Type *base)
+{
+ uint32_t temp;
+ temp = base->STAT;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ temp |= (base->FIFO &
+ (LPUART_FIFO_TXEMPT_MASK | LPUART_FIFO_RXEMPT_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) >>
+ 16U;
+#endif
+ /* Only keeps the status bits */
+ temp &= (uint32_t)kLPUART_AllFlags;
+ return temp;
+}
+
+/*!
+ * brief Clears status flags with a provided mask.
+ *
+ * This function clears LPUART status flags with a provided mask. Automatically cleared flags
+ * can't be cleared by this function.
+ * Flags that can only cleared or set by hardware are:
+ * kLPUART_TxDataRegEmptyFlag, kLPUART_TransmissionCompleteFlag, kLPUART_RxDataRegFullFlag,
+ * kLPUART_RxActiveFlag, kLPUART_NoiseErrorFlag, kLPUART_ParityErrorFlag,
+ * kLPUART_TxFifoEmptyFlag,kLPUART_RxFifoEmptyFlag
+ * Note: This API should be called when the Tx/Rx is idle, otherwise it takes no effects.
+ *
+ * param base LPUART peripheral base address.
+ * param mask the status flags to be cleared. The user can use the enumerators in the
+ * _lpuart_status_flag_t to do the OR operation and get the mask.
+ * return 0 succeed, others failed.
+ * retval kStatus_LPUART_FlagCannotClearManually The flag can't be cleared by this function but
+ * it is cleared automatically by hardware.
+ * retval kStatus_Success Status in the mask are cleared.
+ */
+status_t LPUART_ClearStatusFlags(LPUART_Type *base, uint32_t mask)
+{
+ uint32_t temp;
+ status_t status;
+
+ /* Only deal with the clearable flags */
+ mask &= (uint32_t)kLPUART_AllClearFlags;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Status bits in FIFO register */
+ if ((mask & ((uint32_t)kLPUART_TxFifoOverflowFlag | (uint32_t)kLPUART_RxFifoUnderflowFlag)) != 0U)
+ {
+ /* Get the FIFO register value and mask the rx/tx FIFO flush bits and the status bits that can be W1C in case
+ they are written 1 accidentally. */
+ temp = (uint32_t)base->FIFO;
+ temp &= (uint32_t)(
+ ~(LPUART_FIFO_TXFLUSH_MASK | LPUART_FIFO_RXFLUSH_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK));
+ temp |= (mask << 16U) & (LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK);
+ base->FIFO = temp;
+ }
+#endif
+ /* Status bits in STAT register */
+ /* First get the STAT register value and mask all the bits that not represent status, then OR with the status bit
+ * that is to be W1C */
+ temp = (base->STAT & 0x3E000000UL) | mask;
+ base->STAT = temp;
+ /* If some flags still pending. */
+ if (0U != (mask & LPUART_GetStatusFlags(base)))
+ {
+ status = kStatus_LPUART_FlagCannotClearManually;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Writes to the transmitter register using a blocking method.
+ *
+ * This function polls the transmitter register, first waits for the register to be empty or TX FIFO to have room,
+ * and writes data to the transmitter buffer, then waits for the data to be sent out to bus.
+ *
+ * param base LPUART peripheral base address.
+ * param data Start address of the data to write.
+ * param length Size of the data to write.
+ * retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully wrote all data.
+ */
+status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ const uint8_t *dataAddress = data;
+ size_t transferSize = length;
+
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != transferSize)
+ {
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (base->STAT & LPUART_STAT_TDRE_MASK)) && (0U != --waitTimes))
+#else
+ while (0U == (base->STAT & LPUART_STAT_TDRE_MASK))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_LPUART_Timeout;
+ }
+#endif
+ base->DATA = *(dataAddress);
+ dataAddress++;
+ transferSize--;
+ }
+ /* Ensure all the data in the transmit buffer are sent out to bus. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (base->STAT & LPUART_STAT_TC_MASK)) && (0U != --waitTimes))
+#else
+ while (0U == (base->STAT & LPUART_STAT_TC_MASK))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_LPUART_Timeout;
+ }
+#endif
+ return kStatus_Success;
+}
+
+/*!
+ * brief Reads the receiver data register using a blocking method.
+ *
+ * This function polls the receiver register, waits for the receiver register full or receiver FIFO
+ * has data, and reads data from the TX register.
+ *
+ * param base LPUART peripheral base address.
+ * param data Start address of the buffer to store the received data.
+ * param length Size of the buffer.
+ * retval kStatus_LPUART_RxHardwareOverrun Receiver overrun happened while receiving data.
+ * retval kStatus_LPUART_NoiseError Noise error happened while receiving data.
+ * retval kStatus_LPUART_FramingError Framing error happened while receiving data.
+ * retval kStatus_LPUART_ParityError Parity error happened while receiving data.
+ * retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully received all data.
+ */
+status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ status_t status = kStatus_Success;
+ uint32_t statusFlag;
+ uint8_t *dataAddress = data;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != (length--))
+ {
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ while (0U == ((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT))
+#else
+ while (0U == (base->STAT & LPUART_STAT_RDRF_MASK))
+#endif
+ {
+#if UART_RETRY_TIMES
+ if (0U == --waitTimes)
+ {
+ status = kStatus_LPUART_Timeout;
+ break;
+ }
+#endif
+ statusFlag = LPUART_GetStatusFlags(base);
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_RxOverrunFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_RxOverrunFlag)) ?
+ (kStatus_LPUART_RxHardwareOverrun) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ /* Other error flags(FE, NF, and PF) are prevented from setting once OR is set, no need to check other
+ * error flags*/
+ break;
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_ParityErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_ParityErrorFlag)) ?
+ (kStatus_LPUART_ParityError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_FramingErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_FramingErrorFlag)) ?
+ (kStatus_LPUART_FramingError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_NoiseErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_NoiseErrorFlag)) ?
+ (kStatus_LPUART_NoiseError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+ if (kStatus_Success != status)
+ {
+ break;
+ }
+ }
+
+ if (kStatus_Success == status)
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (isSevenDataBits)
+ {
+ *(dataAddress) = (uint8_t)(base->DATA & 0x7FU);
+ dataAddress++;
+ }
+ else
+ {
+ *(dataAddress) = (uint8_t)base->DATA;
+ dataAddress++;
+ }
+#else
+ *(dataAddress) = (uint8_t)base->DATA;
+ dataAddress++;
+#endif
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Initializes the LPUART handle.
+ *
+ * This function initializes the LPUART handle, which can be used for other LPUART
+ * transactional APIs. Usually, for a specified LPUART instance,
+ * call this API once to get the initialized handle.
+ *
+ * The LPUART driver supports the "background" receiving, which means that user can set up
+ * an RX ring buffer optionally. Data received is stored into the ring buffer even when the
+ * user doesn't call the LPUART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ * The ring buffer is disabled if passing NULL as p ringBuffer.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param callback Callback function.
+ * param userData User data.
+ */
+void LPUART_TransferCreateHandle(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(lpuart_handle_t));
+
+ /* Set the TX/RX state. */
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ /* Initial seven data bits flag */
+ handle->isSevenDataBits = isSevenDataBits;
+#endif
+
+ /* Get instance from peripheral base address. */
+ instance = LPUART_GetInstance(base);
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_lpuartHandle[instance] = handle;
+
+ s_lpuartIsr[instance] = LPUART_TransferHandleIRQ;
+
+/* Enable interrupt in NVIC. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+ (void)EnableIRQ(s_lpuartRxIRQ[instance]);
+ (void)EnableIRQ(s_lpuartTxIRQ[instance]);
+#else
+ (void)EnableIRQ(s_lpuartIRQ[instance]);
+#endif
+}
+
+/*!
+ * brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ *
+ * note When using RX ring buffer, one byte is reserved for internal use. In other
+ * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * param ringBufferSize size of the ring buffer.
+ */
+void LPUART_TransferStartRingBuffer(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize)
+{
+ assert(NULL != handle);
+ assert(NULL != ringBuffer);
+
+ /* Setup the ring buffer address */
+ handle->rxRingBuffer = ringBuffer;
+ handle->rxRingBufferSize = ringBufferSize;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. */
+ uint32_t irqMask = DisableGlobalIRQ();
+ /* Enable the interrupt to accept the data when user need the ring buffer. */
+ base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+}
+
+/*!
+ * brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferStopRingBuffer(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ if (handle->rxState == (uint8_t)kLPUART_RxIdle)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte.
+ */
+ uint32_t irqMask = DisableGlobalIRQ();
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+ }
+
+ handle->rxRingBuffer = NULL;
+ handle->rxRingBufferSize = 0U;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+}
+
+/*!
+ * brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function send data using an interrupt method. This is a non-blocking function, which
+ * returns directly without waiting for all data written to the transmitter register. When
+ * all data is written to the TX register in the ISR, the LPUART driver calls the callback
+ * function and passes the ref kStatus_LPUART_TxIdle as status parameter.
+ *
+ * note The kStatus_LPUART_TxIdle is passed to the upper layer when all data are written
+ * to the TX register. However, there is no check to ensure that all the data sent out. Before disabling the TX,
+ * check the kLPUART_TransmissionCompleteFlag to ensure that the transmit is finished.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART transfer structure, see #lpuart_transfer_t.
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_LPUART_TxBusy Previous transmission still not finished, data not all written to the TX register.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferSendNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->txData);
+ assert(0U != xfer->dataSize);
+
+ status_t status;
+
+ /* Return error if current TX busy. */
+ if ((uint8_t)kLPUART_TxBusy == handle->txState)
+ {
+ status = kStatus_LPUART_TxBusy;
+ }
+ else
+ {
+ handle->txData = xfer->txData;
+ handle->txDataSize = xfer->dataSize;
+ handle->txDataSizeAll = xfer->dataSize;
+ handle->txState = (uint8_t)kLPUART_TxBusy;
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte.
+ */
+ uint32_t irqMask = DisableGlobalIRQ();
+ /* Enable transmitter interrupt. */
+ base->CTRL |= (uint32_t)LPUART_CTRL_TIE_MASK;
+ EnableGlobalIRQ(irqMask);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
+ * how many bytes are not sent out.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortSend(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. */
+ uint32_t irqMask = DisableGlobalIRQ();
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_TIE_MASK | LPUART_CTRL_TCIE_MASK);
+ EnableGlobalIRQ(irqMask);
+
+ handle->txDataSize = 0;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes that have been sent out to bus.
+ *
+ * This function gets the number of bytes that have been sent out to bus by an interrupt method.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Send bytes count.
+ * retval kStatus_NoTransferInProgress No send in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != count);
+
+ status_t status = kStatus_Success;
+ size_t tmptxDataSize = handle->txDataSize;
+
+ if ((uint8_t)kLPUART_TxIdle == handle->txState)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ *count = handle->txDataSizeAll - tmptxDataSize -
+ ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT);
+#else
+ if ((base->STAT & (uint32_t)kLPUART_TxDataRegEmptyFlag) != 0U)
+ {
+ *count = handle->txDataSizeAll - tmptxDataSize;
+ }
+ else
+ {
+ *count = handle->txDataSizeAll - tmptxDataSize - 1U;
+ }
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using an interrupt method. This is a non-blocking function
+ * which returns without waiting to ensure that all data are received.
+ * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
+ * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in the ring buffer is not enough for read, the receive
+ * request is saved by the LPUART driver. When the new data arrives, the receive request
+ * is serviced first. When all data is received, the LPUART driver notifies the upper layer
+ * through a callback function and passes a status parameter ref kStatus_UART_RxIdle.
+ * For example, the upper layer needs 10 bytes but there are only 5 bytes in ring buffer.
+ * The 5 bytes are copied to xfer->data, which returns with the
+ * parameter p receivedBytes set to 5. For the remaining 5 bytes, the newly arrived data is
+ * saved from xfer->data[5]. When 5 bytes are received, the LPUART driver notifies the upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART transfer structure, see #uart_transfer_t.
+ * param receivedBytes Bytes received from the ring buffer directly.
+ * retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * retval kStatus_LPUART_RxBusy Previous receive request is not finished.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_t *xfer,
+ size_t *receivedBytes)
+{
+ assert(NULL != handle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->rxData);
+ assert(0U != xfer->dataSize);
+
+ uint32_t i;
+ status_t status;
+ uint32_t irqMask;
+ /* How many bytes to copy from ring buffer to user memory. */
+ size_t bytesToCopy = 0U;
+ /* How many bytes to receive. */
+ size_t bytesToReceive;
+ /* How many bytes currently have received. */
+ size_t bytesCurrentReceived;
+
+ /* How to get data:
+ 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
+ to lpuart handle, enable interrupt to store received data to xfer->data. When
+ all data received, trigger callback.
+ 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
+ If there are enough data in ring buffer, copy them to xfer->data and return.
+ If there are not enough data in ring buffer, copy all of them to xfer->data,
+ save the xfer->data remained empty space to lpuart handle, receive data
+ to this empty space and trigger callback when finished. */
+
+ if ((uint8_t)kLPUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_LPUART_RxBusy;
+ }
+ else
+ {
+ bytesToReceive = xfer->dataSize;
+ bytesCurrentReceived = 0;
+
+ /* If RX ring buffer is used. */
+ if (NULL != handle->rxRingBuffer)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ /* Disable LPUART RX IRQ, protect ring buffer. */
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+
+ /* How many bytes in RX ring buffer currently. */
+ bytesToCopy = LPUART_TransferGetRxRingBufferLength(base, handle);
+
+ if (0U != bytesToCopy)
+ {
+ bytesToCopy = MIN(bytesToReceive, bytesToCopy);
+
+ bytesToReceive -= bytesToCopy;
+
+ /* Copy data from ring buffer to user memory. */
+ for (i = 0U; i < bytesToCopy; i++)
+ {
+ xfer->rxData[bytesCurrentReceived] = handle->rxRingBuffer[handle->rxRingBufferTail];
+ bytesCurrentReceived++;
+
+ /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
+ if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+ }
+
+ /* If ring buffer does not have enough data, still need to read more data. */
+ if (0U != bytesToReceive)
+ {
+ /* No data in ring buffer, save the request to LPUART handle. */
+ handle->rxData = &xfer->rxData[bytesCurrentReceived];
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = xfer->dataSize;
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+ }
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ /* Re-enable LPUART RX IRQ. */
+ base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+
+ /* Call user callback since all data are received. */
+ if (0U == bytesToReceive)
+ {
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+ /* Ring buffer not used. */
+ else
+ {
+ handle->rxData = &xfer->rxData[bytesCurrentReceived];
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ /* Enable RX interrupt. */
+ base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ILIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+ }
+
+ /* Return the how many bytes have read. */
+ if (NULL != receivedBytes)
+ {
+ *receivedBytes = bytesCurrentReceived;
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data receiving.
+ *
+ * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
+ * how many bytes not received yet.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortReceive(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
+ if (NULL == handle->rxRingBuffer)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte.
+ */
+ uint32_t irqMask = DisableGlobalIRQ();
+ /* Disable RX interrupt. */
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ILIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+ }
+
+ handle->rxDataSize = 0U;
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes that have been received.
+ *
+ * This function gets the number of bytes that have been received.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Receive bytes count.
+ * retval kStatus_NoTransferInProgress No receive in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != count);
+
+ status_t status = kStatus_Success;
+ size_t tmprxDataSize = handle->rxDataSize;
+
+ if ((uint8_t)kLPUART_RxIdle == handle->rxState)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->rxDataSizeAll - tmprxDataSize;
+ }
+
+ return status;
+}
+
+static void LPUART_TransferHandleIDLEReady(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ uint32_t irqMask;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ uint8_t count;
+ uint8_t tempCount;
+ count = ((uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT));
+
+ while ((0U != handle->rxDataSize) && (0U != count))
+ {
+ tempCount = (uint8_t)MIN(handle->rxDataSize, count);
+
+ /* Using non block API to read the data from the registers. */
+ LPUART_ReadNonBlocking(base, handle->rxData, tempCount);
+ handle->rxData = &handle->rxData[tempCount];
+ handle->rxDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If rxDataSize is 0, invoke rx idle callback.*/
+ if (0U == (handle->rxDataSize))
+ {
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+#endif
+ /* Clear IDLE flag.*/
+ base->STAT = ((base->STAT & 0x3FE00000U) | LPUART_STAT_IDLE_MASK);
+
+ /* If rxDataSize is 0, disable rx ready, overrun and idle line interrupt.*/
+ if (0U == handle->rxDataSize)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ILIE_MASK | LPUART_CTRL_ORIE_MASK);
+ EnableGlobalIRQ(irqMask);
+ }
+ /* Invoke callback if callback is not NULL and rxDataSize is not 0. */
+ else if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_IdleLineDetected, handle->userData);
+ }
+ else
+ {
+ /* Avoid MISRA 15.7 */
+ }
+}
+
+static void LPUART_TransferHandleReceiveDataFull(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ uint8_t count;
+ uint8_t tempCount;
+ uint16_t tpmRxRingBufferHead;
+ uint32_t tpmData;
+ uint32_t irqMask;
+
+ /* Get the size that can be stored into buffer for this interrupt. */
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ count = ((uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT));
+#else
+ count = 1;
+#endif
+
+ /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
+ while ((0U != handle->rxDataSize) && (0U != count))
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ tempCount = (uint8_t)MIN(handle->rxDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to read the data from the registers. */
+ LPUART_ReadNonBlocking(base, handle->rxData, tempCount);
+ handle->rxData = &handle->rxData[tempCount];
+ handle->rxDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data required for upper layer is ready, trigger callback. */
+ if (0U == handle->rxDataSize)
+ {
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+
+ /* If use RX ring buffer, receive data to ring buffer. */
+ if (NULL != handle->rxRingBuffer)
+ {
+ while (0U != count--)
+ {
+ /* If RX ring buffer is full, trigger callback to notify over run. */
+ if (LPUART_TransferIsRxRingBufferFull(base, handle))
+ {
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxRingBufferOverrun, handle->userData);
+ }
+ }
+
+ /* If ring buffer is still full after callback function, the oldest data is overridden. */
+ if (LPUART_TransferIsRxRingBufferFull(base, handle))
+ {
+ /* Increase handle->rxRingBufferTail to make room for new data. */
+ if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+
+ /* Read data. */
+ tpmRxRingBufferHead = handle->rxRingBufferHead;
+ tpmData = base->DATA;
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (handle->isSevenDataBits)
+ {
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)(tpmData & 0x7FU);
+ }
+ else
+ {
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData;
+ }
+#else
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData;
+#endif
+
+ /* Increase handle->rxRingBufferHead. */
+ if (((uint32_t)handle->rxRingBufferHead + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferHead = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferHead++;
+ }
+ }
+ }
+ /* If no receive requst pending, stop RX interrupt. */
+ else if (0U == handle->rxDataSize)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK | LPUART_CTRL_ILIE_MASK);
+ EnableGlobalIRQ(irqMask);
+ }
+ else
+ {
+ /* Avoid MISRA C-2012 15.7 voiation */
+ return;
+ }
+}
+
+static void LPUART_TransferHandleSendDataEmpty(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ uint8_t count;
+ uint8_t tempCount;
+ uint32_t irqMask;
+/* Get the bytes that available at this moment. */
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ count = (uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) -
+ (uint8_t)((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT);
+#else
+ count = 1;
+#endif
+
+ while ((0U != handle->txDataSize) && (0U != count))
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ tempCount = (uint8_t)MIN(handle->txDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to write the data to the registers. */
+ LPUART_WriteNonBlocking(base, handle->txData, tempCount);
+ handle->txData = &handle->txData[tempCount];
+ handle->txDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data are written to data register, notify user with the callback, then TX finished. */
+ if (0U == handle->txDataSize)
+ {
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during
+ * read-modify-wrte. */
+ irqMask = DisableGlobalIRQ();
+ /* Disable TX register empty interrupt and enable transmission completion interrupt. */
+ base->CTRL = (base->CTRL & ~LPUART_CTRL_TIE_MASK) | LPUART_CTRL_TCIE_MASK;
+ EnableGlobalIRQ(irqMask);
+ }
+ }
+}
+
+static void LPUART_TransferHandleTransmissionComplete(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ uint32_t irqMask;
+ /* Set txState to idle only when all data has been sent out to bus. */
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte.
+ */
+ irqMask = DisableGlobalIRQ();
+ /* Disable transmission complete interrupt. */
+ base->CTRL &= ~(uint32_t)LPUART_CTRL_TCIE_MASK;
+ EnableGlobalIRQ(irqMask);
+
+ /* Trigger callback. */
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_TxIdle, handle->userData);
+ }
+}
+
+/*!
+ * brief LPUART IRQ handle function.
+ *
+ * This function handles the LPUART transmit and receive IRQ request.
+ *
+ * param base LPUART peripheral base address.
+ * param irqHandle LPUART handle pointer.
+ */
+void LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle)
+{
+ assert(NULL != irqHandle);
+
+ uint32_t status = LPUART_GetStatusFlags(base);
+ uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(base);
+
+ lpuart_handle_t *handle = (lpuart_handle_t *)irqHandle;
+
+ /* If RX overrun. */
+ if ((uint32_t)kLPUART_RxOverrunFlag == ((uint32_t)kLPUART_RxOverrunFlag & status))
+ {
+ /* Clear overrun flag, otherwise the RX does not work. */
+ base->STAT = ((base->STAT & 0x3FE00000U) | LPUART_STAT_OR_MASK);
+
+ /* Trigger callback. */
+ if (NULL != (handle->callback))
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxHardwareOverrun, handle->userData);
+ }
+ }
+
+ /* If IDLE flag is set and the IDLE interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_IdleLineFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_IdleLineInterruptEnable & enabledInterrupts)))
+ {
+ LPUART_TransferHandleIDLEReady(base, handle);
+ }
+ /* Receive data register full */
+ if ((0U != ((uint32_t)kLPUART_RxDataRegFullFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_RxDataRegFullInterruptEnable & enabledInterrupts)))
+ {
+ LPUART_TransferHandleReceiveDataFull(base, handle);
+ }
+
+ /* Send data register empty and the interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_TxDataRegEmptyFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts)))
+ {
+ LPUART_TransferHandleSendDataEmpty(base, handle);
+ }
+
+ /* Transmission complete and the interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_TransmissionCompleteFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_TransmissionCompleteInterruptEnable & enabledInterrupts)))
+ {
+ LPUART_TransferHandleTransmissionComplete(base, handle);
+ }
+}
+
+/*!
+ * brief LPUART Error IRQ handle function.
+ *
+ * This function handles the LPUART error IRQ request.
+ *
+ * param base LPUART peripheral base address.
+ * param irqHandle LPUART handle pointer.
+ */
+void LPUART_TransferHandleErrorIRQ(LPUART_Type *base, void *irqHandle)
+{
+ /* To be implemented by User. */
+}
+#if defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART0_LPUART1_RX_DriverIRQHandler(void);
+void LPUART0_LPUART1_RX_DriverIRQHandler(void)
+{
+ /* If handle is registered, treat the transfer function is enabled. */
+ if (NULL != s_lpuartHandle[0])
+ {
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ }
+ if (NULL != s_lpuartHandle[1])
+ {
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART0_LPUART1_TX_DriverIRQHandler(void);
+void LPUART0_LPUART1_TX_DriverIRQHandler(void)
+{
+ /* If handle is registered, treat the transfer function is enabled. */
+ if (NULL != s_lpuartHandle[0])
+ {
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ }
+ if (NULL != s_lpuartHandle[1])
+ {
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART0_LPUART1_DriverIRQHandler(void);
+void LPUART0_LPUART1_DriverIRQHandler(void)
+{
+ /* If handle is registered, treat the transfer function is enabled. */
+ if (NULL != s_lpuartHandle[0])
+ {
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ }
+ if (NULL != s_lpuartHandle[1])
+ {
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART0)
+#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART0_TX_DriverIRQHandler(void);
+void LPUART0_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART0_RX_DriverIRQHandler(void);
+void LPUART0_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART0_DriverIRQHandler(void);
+void LPUART0_DriverIRQHandler(void)
+{
+ s_lpuartIsr[0](LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(LPUART1)
+#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART1_TX_DriverIRQHandler(void);
+void LPUART1_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART1_RX_DriverIRQHandler(void);
+void LPUART1_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART1_DriverIRQHandler(void);
+void LPUART1_DriverIRQHandler(void)
+{
+ s_lpuartIsr[1](LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(LPUART2)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART2_TX_DriverIRQHandler(void);
+void LPUART2_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[2](LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART2_RX_DriverIRQHandler(void);
+void LPUART2_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[2](LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART2_DriverIRQHandler(void);
+void LPUART2_DriverIRQHandler(void)
+{
+ s_lpuartIsr[2](LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART3)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART3_TX_DriverIRQHandler(void);
+void LPUART3_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[3](LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART3_RX_DriverIRQHandler(void);
+void LPUART3_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[3](LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART3_DriverIRQHandler(void);
+void LPUART3_DriverIRQHandler(void)
+{
+ s_lpuartIsr[3](LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART4)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART4_TX_DriverIRQHandler(void);
+void LPUART4_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[4](LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART4_RX_DriverIRQHandler(void);
+void LPUART4_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[4](LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART4_DriverIRQHandler(void);
+void LPUART4_DriverIRQHandler(void)
+{
+ s_lpuartIsr[4](LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART5)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART5_TX_DriverIRQHandler(void);
+void LPUART5_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[5](LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART5_RX_DriverIRQHandler(void);
+void LPUART5_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[5](LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART5_DriverIRQHandler(void);
+void LPUART5_DriverIRQHandler(void)
+{
+ s_lpuartIsr[5](LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART6)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART6_TX_DriverIRQHandler(void);
+void LPUART6_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[6](LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART6_RX_DriverIRQHandler(void);
+void LPUART6_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[6](LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART6_DriverIRQHandler(void);
+void LPUART6_DriverIRQHandler(void)
+{
+ s_lpuartIsr[6](LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART7)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART7_TX_DriverIRQHandler(void);
+void LPUART7_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[7](LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART7_RX_DriverIRQHandler(void);
+void LPUART7_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[7](LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART7_DriverIRQHandler(void);
+void LPUART7_DriverIRQHandler(void)
+{
+ s_lpuartIsr[7](LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART8)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART8_TX_DriverIRQHandler(void);
+void LPUART8_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[8](LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART8_RX_DriverIRQHandler(void);
+void LPUART8_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[8](LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART8_DriverIRQHandler(void);
+void LPUART8_DriverIRQHandler(void)
+{
+ s_lpuartIsr[8](LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART9)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART9_TX_DriverIRQHandler(void);
+void LPUART9_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[9](LPUART9, s_lpuartHandle[9]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART9_RX_DriverIRQHandler(void);
+void LPUART9_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[9](LPUART9, s_lpuartHandle[9]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART9_DriverIRQHandler(void);
+void LPUART9_DriverIRQHandler(void)
+{
+ s_lpuartIsr[9](LPUART9, s_lpuartHandle[9]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART10)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART10_TX_DriverIRQHandler(void);
+void LPUART10_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[10](LPUART10, s_lpuartHandle[10]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART10_RX_DriverIRQHandler(void);
+void LPUART10_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[10](LPUART10, s_lpuartHandle[10]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART10_DriverIRQHandler(void);
+void LPUART10_DriverIRQHandler(void)
+{
+ s_lpuartIsr[10](LPUART10, s_lpuartHandle[10]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART11)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART11_TX_DriverIRQHandler(void);
+void LPUART11_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[11](LPUART11, s_lpuartHandle[11]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART11_RX_DriverIRQHandler(void);
+void LPUART11_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[11](LPUART11, s_lpuartHandle[11]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART11_DriverIRQHandler(void);
+void LPUART11_DriverIRQHandler(void)
+{
+ s_lpuartIsr[11](LPUART11, s_lpuartHandle[11]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART12)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART12_TX_DriverIRQHandler(void);
+void LPUART12_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[12](LPUART12, s_lpuartHandle[12]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART12_RX_DriverIRQHandler(void);
+void LPUART12_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr[12](LPUART12, s_lpuartHandle[12]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART12_DriverIRQHandler(void);
+void LPUART12_DriverIRQHandler(void)
+{
+ s_lpuartIsr[12](LPUART12, s_lpuartHandle[12]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(CM4_0__LPUART)
+void M4_0_LPUART_DriverIRQHandler(void);
+void M4_0_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(CM4_0__LPUART)](CM4_0__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_0__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CM4_1__LPUART)
+void M4_1_LPUART_DriverIRQHandler(void);
+void M4_1_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(CM4_1__LPUART)](CM4_1__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_1__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CM4__LPUART)
+void M4_LPUART_DriverIRQHandler(void);
+void M4_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(CM4__LPUART)](CM4__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART0)
+void DMA_UART0_INT_DriverIRQHandler(void);
+void DMA_UART0_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(DMA__LPUART0)](DMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART1)
+void DMA_UART1_INT_DriverIRQHandler(void);
+void DMA_UART1_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(DMA__LPUART1)](DMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART2)
+void DMA_UART2_INT_DriverIRQHandler(void);
+void DMA_UART2_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(DMA__LPUART2)](DMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART3)
+void DMA_UART3_INT_DriverIRQHandler(void);
+void DMA_UART3_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(DMA__LPUART3)](DMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART3)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART4)
+void DMA_UART4_INT_DriverIRQHandler(void);
+void DMA_UART4_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(DMA__LPUART4)](DMA__LPUART4, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART4)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART0)
+void ADMA_UART0_INT_DriverIRQHandler(void);
+void ADMA_UART0_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(ADMA__LPUART0)](ADMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART1)
+void ADMA_UART1_INT_DriverIRQHandler(void);
+void ADMA_UART1_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(ADMA__LPUART1)](ADMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART2)
+void ADMA_UART2_INT_DriverIRQHandler(void);
+void ADMA_UART2_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(ADMA__LPUART2)](ADMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART3)
+void ADMA_UART3_INT_DriverIRQHandler(void);
+void ADMA_UART3_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr[LPUART_GetInstance(ADMA__LPUART3)](ADMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART3)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.h
new file mode 100644
index 0000000000..14409ae6e1
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart.h
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPUART_H_
+#define _FSL_LPUART_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup lpuart_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPUART driver version. */
+#define FSL_LPUART_DRIVER_VERSION (MAKE_VERSION(2, 7, 0))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef UART_RETRY_TIMES
+#define UART_RETRY_TIMES 0U /* Defining to zero means to keep waiting for the flag until it is assert/deassert. */
+#endif
+
+/*! @brief Error codes for the LPUART driver. */
+enum
+{
+ kStatus_LPUART_TxBusy = MAKE_STATUS(kStatusGroup_LPUART, 0), /*!< TX busy */
+ kStatus_LPUART_RxBusy = MAKE_STATUS(kStatusGroup_LPUART, 1), /*!< RX busy */
+ kStatus_LPUART_TxIdle = MAKE_STATUS(kStatusGroup_LPUART, 2), /*!< LPUART transmitter is idle. */
+ kStatus_LPUART_RxIdle = MAKE_STATUS(kStatusGroup_LPUART, 3), /*!< LPUART receiver is idle. */
+ kStatus_LPUART_TxWatermarkTooLarge = MAKE_STATUS(kStatusGroup_LPUART, 4), /*!< TX FIFO watermark too large */
+ kStatus_LPUART_RxWatermarkTooLarge = MAKE_STATUS(kStatusGroup_LPUART, 5), /*!< RX FIFO watermark too large */
+ kStatus_LPUART_FlagCannotClearManually = MAKE_STATUS(kStatusGroup_LPUART, 6), /*!< Some flag can't manually clear */
+ kStatus_LPUART_Error = MAKE_STATUS(kStatusGroup_LPUART, 7), /*!< Error happens on LPUART. */
+ kStatus_LPUART_RxRingBufferOverrun =
+ MAKE_STATUS(kStatusGroup_LPUART, 8), /*!< LPUART RX software ring buffer overrun. */
+ kStatus_LPUART_RxHardwareOverrun = MAKE_STATUS(kStatusGroup_LPUART, 9), /*!< LPUART RX receiver overrun. */
+ kStatus_LPUART_NoiseError = MAKE_STATUS(kStatusGroup_LPUART, 10), /*!< LPUART noise error. */
+ kStatus_LPUART_FramingError = MAKE_STATUS(kStatusGroup_LPUART, 11), /*!< LPUART framing error. */
+ kStatus_LPUART_ParityError = MAKE_STATUS(kStatusGroup_LPUART, 12), /*!< LPUART parity error. */
+ kStatus_LPUART_BaudrateNotSupport =
+ MAKE_STATUS(kStatusGroup_LPUART, 13), /*!< Baudrate is not support in current clock source */
+ kStatus_LPUART_IdleLineDetected = MAKE_STATUS(kStatusGroup_LPUART, 14), /*!< IDLE flag. */
+ kStatus_LPUART_Timeout = MAKE_STATUS(kStatusGroup_LPUART, 15), /*!< LPUART times out. */
+};
+
+/*! @brief LPUART parity mode. */
+typedef enum _lpuart_parity_mode
+{
+ kLPUART_ParityDisabled = 0x0U, /*!< Parity disabled */
+ kLPUART_ParityEven = 0x2U, /*!< Parity enabled, type even, bit setting: PE|PT = 10 */
+ kLPUART_ParityOdd = 0x3U, /*!< Parity enabled, type odd, bit setting: PE|PT = 11 */
+} lpuart_parity_mode_t;
+
+/*! @brief LPUART data bits count. */
+typedef enum _lpuart_data_bits
+{
+ kLPUART_EightDataBits = 0x0U, /*!< Eight data bit */
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ kLPUART_SevenDataBits = 0x1U, /*!< Seven data bit */
+#endif
+} lpuart_data_bits_t;
+
+/*! @brief LPUART stop bit count. */
+typedef enum _lpuart_stop_bit_count
+{
+ kLPUART_OneStopBit = 0U, /*!< One stop bit */
+ kLPUART_TwoStopBit = 1U, /*!< Two stop bits */
+} lpuart_stop_bit_count_t;
+
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+/*! @brief LPUART transmit CTS source. */
+typedef enum _lpuart_transmit_cts_source
+{
+ kLPUART_CtsSourcePin = 0U, /*!< CTS resource is the LPUART_CTS pin. */
+ kLPUART_CtsSourceMatchResult = 1U, /*!< CTS resource is the match result. */
+} lpuart_transmit_cts_source_t;
+
+/*! @brief LPUART transmit CTS configure. */
+typedef enum _lpuart_transmit_cts_config
+{
+ kLPUART_CtsSampleAtStart = 0U, /*!< CTS input is sampled at the start of each character. */
+ kLPUART_CtsSampleAtIdle = 1U, /*!< CTS input is sampled when the transmitter is idle */
+} lpuart_transmit_cts_config_t;
+#endif
+
+/*! @brief LPUART idle flag type defines when the receiver starts counting. */
+typedef enum _lpuart_idle_type_select
+{
+ kLPUART_IdleTypeStartBit = 0U, /*!< Start counting after a valid start bit. */
+ kLPUART_IdleTypeStopBit = 1U, /*!< Start counting after a stop bit. */
+} lpuart_idle_type_select_t;
+
+/*! @brief LPUART idle detected configuration.
+ * This structure defines the number of idle characters that must be received before
+ * the IDLE flag is set.
+ */
+typedef enum _lpuart_idle_config
+{
+ kLPUART_IdleCharacter1 = 0U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter2 = 1U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter4 = 2U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter8 = 3U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter16 = 4U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter32 = 5U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter64 = 6U, /*!< the number of idle characters. */
+ kLPUART_IdleCharacter128 = 7U, /*!< the number of idle characters. */
+} lpuart_idle_config_t;
+
+/*!
+ * @brief LPUART interrupt configuration structure, default settings all disabled.
+ *
+ * This structure contains the settings for all LPUART interrupt configurations.
+ */
+enum _lpuart_interrupt_enable
+{
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ kLPUART_LinBreakInterruptEnable = (LPUART_BAUD_LBKDIE_MASK >> 8U), /*!< LIN break detect. bit 7 */
+#endif
+ kLPUART_RxActiveEdgeInterruptEnable = (LPUART_BAUD_RXEDGIE_MASK >> 8U), /*!< Receive Active Edge. bit 6 */
+ kLPUART_TxDataRegEmptyInterruptEnable = (LPUART_CTRL_TIE_MASK), /*!< Transmit data register empty. bit 23 */
+ kLPUART_TransmissionCompleteInterruptEnable = (LPUART_CTRL_TCIE_MASK), /*!< Transmission complete. bit 22 */
+ kLPUART_RxDataRegFullInterruptEnable = (LPUART_CTRL_RIE_MASK), /*!< Receiver data register full. bit 21 */
+ kLPUART_IdleLineInterruptEnable = (LPUART_CTRL_ILIE_MASK), /*!< Idle line. bit 20 */
+ kLPUART_RxOverrunInterruptEnable = (LPUART_CTRL_ORIE_MASK), /*!< Receiver Overrun. bit 27 */
+ kLPUART_NoiseErrorInterruptEnable = (LPUART_CTRL_NEIE_MASK), /*!< Noise error flag. bit 26 */
+ kLPUART_FramingErrorInterruptEnable = (LPUART_CTRL_FEIE_MASK), /*!< Framing error flag. bit 25 */
+ kLPUART_ParityErrorInterruptEnable = (LPUART_CTRL_PEIE_MASK), /*!< Parity error flag. bit 24 */
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ kLPUART_Match1InterruptEnable = (LPUART_CTRL_MA1IE_MASK), /*!< Parity error flag. bit 15 */
+ kLPUART_Match2InterruptEnable = (LPUART_CTRL_MA2IE_MASK), /*!< Parity error flag. bit 14 */
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ kLPUART_TxFifoOverflowInterruptEnable = (LPUART_FIFO_TXOFE_MASK), /*!< Transmit FIFO Overflow. bit 9 */
+ kLPUART_RxFifoUnderflowInterruptEnable = (LPUART_FIFO_RXUFE_MASK), /*!< Receive FIFO Underflow. bit 8 */
+#endif
+
+ kLPUART_AllInterruptEnable = kLPUART_RxActiveEdgeInterruptEnable | kLPUART_TxDataRegEmptyInterruptEnable |
+ kLPUART_TransmissionCompleteInterruptEnable | kLPUART_RxDataRegFullInterruptEnable |
+ kLPUART_IdleLineInterruptEnable | kLPUART_RxOverrunInterruptEnable |
+ kLPUART_NoiseErrorInterruptEnable | kLPUART_FramingErrorInterruptEnable |
+ kLPUART_ParityErrorInterruptEnable
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ | kLPUART_LinBreakInterruptEnable
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ | kLPUART_Match1InterruptEnable | kLPUART_Match2InterruptEnable
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ | kLPUART_TxFifoOverflowInterruptEnable | kLPUART_RxFifoUnderflowInterruptEnable
+#endif
+ ,
+};
+
+/*!
+ * @brief LPUART status flags.
+ *
+ * This provides constants for the LPUART status flags for use in the LPUART functions.
+ */
+enum _lpuart_flags
+{
+ kLPUART_TxDataRegEmptyFlag =
+ (LPUART_STAT_TDRE_MASK), /*!< Transmit data register empty flag, sets when transmit buffer is empty. bit 23 */
+ kLPUART_TransmissionCompleteFlag =
+ (LPUART_STAT_TC_MASK), /*!< Transmission complete flag, sets when transmission activity complete. bit 22 */
+ kLPUART_RxDataRegFullFlag = (LPUART_STAT_RDRF_MASK), /*!< Receive data register full flag, sets when the receive
+ data buffer is full. bit 21 */
+ kLPUART_IdleLineFlag = (LPUART_STAT_IDLE_MASK), /*!< Idle line detect flag, sets when idle line detected. bit 20 */
+ kLPUART_RxOverrunFlag = (LPUART_STAT_OR_MASK), /*!< Receive Overrun, sets when new data is received before data is
+ read from receive register. bit 19 */
+ kLPUART_NoiseErrorFlag = (LPUART_STAT_NF_MASK), /*!< Receive takes 3 samples of each received bit. If any of these
+ samples differ, noise flag sets. bit 18 */
+ kLPUART_FramingErrorFlag =
+ (LPUART_STAT_FE_MASK), /*!< Frame error flag, sets if logic 0 was detected where stop bit expected. bit 17 */
+ kLPUART_ParityErrorFlag = (LPUART_STAT_PF_MASK), /*!< If parity enabled, sets upon parity error detection. bit 16 */
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ kLPUART_LinBreakFlag = (LPUART_STAT_LBKDIF_MASK), /*!< LIN break detect interrupt flag, sets when LIN break
+ char detected and LIN circuit enabled. bit 31 */
+#endif
+ kLPUART_RxActiveEdgeFlag = (LPUART_STAT_RXEDGIF_MASK), /*!< Receive pin active edge interrupt flag, sets when active
+ edge detected. bit 30 */
+ kLPUART_RxActiveFlag =
+ (LPUART_STAT_RAF_MASK), /*!< Receiver Active Flag (RAF), sets at beginning of valid start. bit 24 */
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ kLPUART_DataMatch1Flag =
+ LPUART_STAT_MA1F_MASK, /*!< The next character to be read from LPUART_DATA matches MA1. bit 15 */
+ kLPUART_DataMatch2Flag =
+ LPUART_STAT_MA2F_MASK, /*!< The next character to be read from LPUART_DATA matches MA2. bit 14 */
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ kLPUART_TxFifoEmptyFlag =
+ (LPUART_FIFO_TXEMPT_MASK >> 16), /*!< TXEMPT bit, sets if transmit buffer is empty. bit 7 */
+ kLPUART_RxFifoEmptyFlag =
+ (LPUART_FIFO_RXEMPT_MASK >> 16), /*!< RXEMPT bit, sets if receive buffer is empty. bit 6 */
+ kLPUART_TxFifoOverflowFlag =
+ (LPUART_FIFO_TXOF_MASK >> 16), /*!< TXOF bit, sets if transmit buffer overflow occurred. bit 1 */
+ kLPUART_RxFifoUnderflowFlag =
+ (LPUART_FIFO_RXUF_MASK >> 16), /*!< RXUF bit, sets if receive buffer underflow occurred. bit 0 */
+#endif
+
+ kLPUART_AllClearFlags = kLPUART_RxActiveEdgeFlag | kLPUART_IdleLineFlag | kLPUART_RxOverrunFlag |
+ kLPUART_NoiseErrorFlag | kLPUART_FramingErrorFlag | kLPUART_ParityErrorFlag
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ | kLPUART_DataMatch1Flag | kLPUART_DataMatch2Flag
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ | kLPUART_TxFifoOverflowFlag | kLPUART_RxFifoUnderflowFlag
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ | kLPUART_LinBreakFlag
+#endif
+ ,
+
+ kLPUART_AllFlags =
+ kLPUART_RxActiveEdgeFlag | kLPUART_IdleLineFlag | kLPUART_RxOverrunFlag | kLPUART_TxDataRegEmptyFlag |
+ kLPUART_TransmissionCompleteFlag | kLPUART_RxDataRegFullFlag | kLPUART_RxActiveFlag | kLPUART_NoiseErrorFlag |
+ kLPUART_FramingErrorFlag | kLPUART_ParityErrorFlag
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ | kLPUART_DataMatch1Flag | kLPUART_DataMatch2Flag
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ | kLPUART_TxFifoOverflowFlag | kLPUART_RxFifoUnderflowFlag | kLPUART_TxFifoEmptyFlag | kLPUART_RxFifoEmptyFlag
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ | kLPUART_LinBreakFlag
+#endif
+ ,
+};
+
+/*! @brief LPUART configuration structure. */
+typedef struct _lpuart_config
+{
+ uint32_t baudRate_Bps; /*!< LPUART baud rate */
+ lpuart_parity_mode_t parityMode; /*!< Parity mode, disabled (default), even, odd */
+ lpuart_data_bits_t dataBitsCount; /*!< Data bits count, eight (default), seven */
+ bool isMsb; /*!< Data bits order, LSB (default), MSB */
+#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
+ lpuart_stop_bit_count_t stopBitCount; /*!< Number of stop bits, 1 stop bit (default) or 2 stop bits */
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ uint8_t txFifoWatermark; /*!< TX FIFO watermark */
+ uint8_t rxFifoWatermark; /*!< RX FIFO watermark */
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ bool enableRxRTS; /*!< RX RTS enable */
+ bool enableTxCTS; /*!< TX CTS enable */
+ lpuart_transmit_cts_source_t txCtsSource; /*!< TX CTS source */
+ lpuart_transmit_cts_config_t txCtsConfig; /*!< TX CTS configure */
+#endif
+ lpuart_idle_type_select_t rxIdleType; /*!< RX IDLE type. */
+ lpuart_idle_config_t rxIdleConfig; /*!< RX IDLE configuration. */
+ bool enableTx; /*!< Enable TX */
+ bool enableRx; /*!< Enable RX */
+} lpuart_config_t;
+
+/*! @brief LPUART transfer structure. */
+typedef struct _lpuart_transfer
+{
+ /*
+ * Use separate TX and RX data pointer, because TX data is const data.
+ * The member data is kept for backward compatibility.
+ */
+ union
+ {
+ uint8_t *data; /*!< The buffer of data to be transfer.*/
+ uint8_t *rxData; /*!< The buffer to receive data. */
+ const uint8_t *txData; /*!< The buffer of data to be sent. */
+ };
+ size_t dataSize; /*!< The byte count to be transfer. */
+} lpuart_transfer_t;
+
+/* Forward declaration of the handle typedef. */
+typedef struct _lpuart_handle lpuart_handle_t;
+
+/*! @brief LPUART transfer callback function. */
+typedef void (*lpuart_transfer_callback_t)(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData);
+
+/*! @brief LPUART handle structure. */
+struct _lpuart_handle
+{
+ const uint8_t *volatile txData; /*!< Address of remaining data to send. */
+ volatile size_t txDataSize; /*!< Size of the remaining data to send. */
+ size_t txDataSizeAll; /*!< Size of the data to send out. */
+ uint8_t *volatile rxData; /*!< Address of remaining data to receive. */
+ volatile size_t rxDataSize; /*!< Size of the remaining data to receive. */
+ size_t rxDataSizeAll; /*!< Size of the data to receive. */
+
+ uint8_t *rxRingBuffer; /*!< Start address of the receiver ring buffer. */
+ size_t rxRingBufferSize; /*!< Size of the ring buffer. */
+ volatile uint16_t rxRingBufferHead; /*!< Index for the driver to store received data into ring buffer. */
+ volatile uint16_t rxRingBufferTail; /*!< Index for the user to get data from the ring buffer. */
+
+ lpuart_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< LPUART callback function parameter.*/
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state. */
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ bool isSevenDataBits; /*!< Seven data bits flag. */
+#endif
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*lpuart_isr_t)(LPUART_Type *base, void *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Array of LPUART handle. */
+extern void *s_lpuartHandle[];
+
+/* Array of LPUART IRQ number. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+extern const IRQn_Type s_lpuartTxIRQ[];
+#else
+extern const IRQn_Type s_lpuartIRQ[];
+#endif
+
+/* LPUART ISR for transactional APIs. */
+extern lpuart_isr_t s_lpuartIsr[];
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* _cplusplus */
+
+#if defined(FSL_FEATURE_LPUART_HAS_GLOBAL) && FSL_FEATURE_LPUART_HAS_GLOBAL
+
+/*!
+ * @name Software Reset
+ * @{
+ */
+
+/*!
+ * @brief Resets the LPUART using software.
+ *
+ * This function resets all internal logic and registers except the Global Register.
+ * Remains set until cleared by software.
+ *
+ * @param base LPUART peripheral base address.
+ */
+static inline void LPUART_SoftwareReset(LPUART_Type *base)
+{
+ base->GLOBAL |= LPUART_GLOBAL_RST_MASK;
+ base->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
+}
+/* @} */
+#endif /*FSL_FEATURE_LPUART_HAS_GLOBAL*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes an LPUART instance with the user configuration structure and the peripheral clock.
+ *
+ * This function configures the LPUART module with user-defined settings. Call the LPUART_GetDefaultConfig() function
+ * to configure the configuration structure and get the default configuration.
+ * The example below shows how to use this API to configure the LPUART.
+ * @code
+ * lpuart_config_t lpuartConfig;
+ * lpuartConfig.baudRate_Bps = 115200U;
+ * lpuartConfig.parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig.dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig.isMsb = false;
+ * lpuartConfig.stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig.txFifoWatermark = 0;
+ * lpuartConfig.rxFifoWatermark = 1;
+ * LPUART_Init(LPUART1, &lpuartConfig, 20000000U);
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @param config Pointer to a user-defined configuration structure.
+ * @param srcClock_Hz LPUART clock source frequency in HZ.
+ * @retval kStatus_LPUART_BaudrateNotSupport Baudrate is not support in current clock source.
+ * @retval kStatus_Success LPUART initialize succeed
+ */
+#ifndef __rtems__
+status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz);
+#else /* __rtems__ */
+status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz, bool do_reset);
+#endif /* __rtems__ */
+
+/*!
+ * @brief Deinitializes a LPUART instance.
+ *
+ * This function waits for transmit to complete, disables TX and RX, and disables the LPUART clock.
+ *
+ * @param base LPUART peripheral base address.
+ */
+void LPUART_Deinit(LPUART_Type *base);
+
+/*!
+ * @brief Gets the default configuration structure.
+ *
+ * This function initializes the LPUART configuration structure to a default value. The default
+ * values are:
+ * lpuartConfig->baudRate_Bps = 115200U;
+ * lpuartConfig->parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig->dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig->isMsb = false;
+ * lpuartConfig->stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig->txFifoWatermark = 0;
+ * lpuartConfig->rxFifoWatermark = 1;
+ * lpuartConfig->rxIdleType = kLPUART_IdleTypeStartBit;
+ * lpuartConfig->rxIdleConfig = kLPUART_IdleCharacter1;
+ * lpuartConfig->enableTx = false;
+ * lpuartConfig->enableRx = false;
+ *
+ * @param config Pointer to a configuration structure.
+ */
+void LPUART_GetDefaultConfig(lpuart_config_t *config);
+/* @} */
+
+/*!
+ * @name Module configuration
+ * @{
+ */
+/*!
+ * @brief Sets the LPUART instance baudrate.
+ *
+ * This function configures the LPUART module baudrate. This function is used to update
+ * the LPUART module baudrate after the LPUART module is initialized by the LPUART_Init.
+ * @code
+ * LPUART_SetBaudRate(LPUART1, 115200U, 20000000U);
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @param baudRate_Bps LPUART baudrate to be set.
+ * @param srcClock_Hz LPUART clock source frequency in HZ.
+ * @retval kStatus_LPUART_BaudrateNotSupport Baudrate is not supported in the current clock source.
+ * @retval kStatus_Success Set baudrate succeeded.
+ */
+status_t LPUART_SetBaudRate(LPUART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz);
+
+/*!
+ * @brief Enable 9-bit data mode for LPUART.
+ *
+ * This function set the 9-bit mode for LPUART module. The 9th bit is not used for parity thus can be modified by user.
+ *
+ * @param base LPUART peripheral base address.
+ * @param enable true to enable, flase to disable.
+ */
+void LPUART_Enable9bitMode(LPUART_Type *base, bool enable);
+
+/*!
+ * @brief Set the LPUART address.
+ *
+ * This function configures the address for LPUART module that works as slave in 9-bit data mode. One or two address
+ * fields can be configured. When the address field's match enable bit is set, the frame it receices with MSB being
+ * 1 is considered as an address frame, otherwise it is considered as data frame. Once the address frame matches one
+ * of slave's own addresses, this slave is addressed. This address frame and its following data frames are stored in
+ * the receive buffer, otherwise the frames will be discarded. To un-address a slave, just send an address frame with
+ * unmatched address.
+ *
+ * @note Any LPUART instance joined in the multi-slave system can work as slave. The position of the address mark is the
+ * same as the parity bit when parity is enabled for 8 bit and 9 bit data formats.
+ *
+ * @param base LPUART peripheral base address.
+ * @param address1 LPUART slave address1.
+ * @param address2 LPUART slave address2.
+ */
+static inline void LPUART_SetMatchAddress(LPUART_Type *base, uint16_t address1, uint16_t address2)
+{
+ /* Configure match address. */
+ uint32_t address = ((uint32_t)address2 << 16U) | (uint32_t)address1 | 0x1000100UL;
+ base->MATCH = address;
+}
+
+/*!
+ * @brief Enable the LPUART match address feature.
+ *
+ * @param base LPUART peripheral base address.
+ * @param match1 true to enable match address1, false to disable.
+ * @param match2 true to enable match address2, false to disable.
+ */
+static inline void LPUART_EnableMatchAddress(LPUART_Type *base, bool match1, bool match2)
+{
+ /* Configure match address1 enable bit. */
+ if (match1)
+ {
+ base->BAUD |= (uint32_t)LPUART_BAUD_MAEN1_MASK;
+ }
+ else
+ {
+ base->BAUD &= ~(uint32_t)LPUART_BAUD_MAEN1_MASK;
+ }
+ /* Configure match address2 enable bit. */
+ if (match2)
+ {
+ base->BAUD |= (uint32_t)LPUART_BAUD_MAEN2_MASK;
+ }
+ else
+ {
+ base->BAUD &= ~(uint32_t)LPUART_BAUD_MAEN2_MASK;
+ }
+}
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+/*!
+ * @brief Sets the rx FIFO watermark.
+ *
+ * @param base LPUART peripheral base address.
+ * @param water Rx FIFO watermark.
+ */
+static inline void LPUART_SetRxFifoWatermark(LPUART_Type *base, uint8_t water)
+{
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) > water);
+ base->WATER = (base->WATER & ~LPUART_WATER_RXWATER_MASK) | LPUART_WATER_RXWATER(water);
+}
+
+/*!
+ * @brief Sets the tx FIFO watermark.
+ *
+ * @param base LPUART peripheral base address.
+ * @param water Tx FIFO watermark.
+ */
+static inline void LPUART_SetTxFifoWatermark(LPUART_Type *base, uint8_t water)
+{
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) > water);
+ base->WATER = (base->WATER & ~LPUART_WATER_TXWATER_MASK) | LPUART_WATER_TXWATER(water);
+}
+#endif
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets LPUART status flags.
+ *
+ * This function gets all LPUART status flags. The flags are returned as the logical
+ * OR value of the enumerators @ref _lpuart_flags. To check for a specific status,
+ * compare the return value with enumerators in the @ref _lpuart_flags.
+ * For example, to check whether the TX is empty:
+ * @code
+ * if (kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(LPUART1))
+ * {
+ * ...
+ * }
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @return LPUART status flags which are ORed by the enumerators in the _lpuart_flags.
+ */
+uint32_t LPUART_GetStatusFlags(LPUART_Type *base);
+
+/*!
+ * @brief Clears status flags with a provided mask.
+ *
+ * This function clears LPUART status flags with a provided mask. Automatically cleared flags
+ * can't be cleared by this function.
+ * Flags that can only cleared or set by hardware are:
+ * kLPUART_TxDataRegEmptyFlag, kLPUART_TransmissionCompleteFlag, kLPUART_RxDataRegFullFlag,
+ * kLPUART_RxActiveFlag, kLPUART_NoiseErrorFlag, kLPUART_ParityErrorFlag,
+ * kLPUART_TxFifoEmptyFlag,kLPUART_RxFifoEmptyFlag
+ * Note: This API should be called when the Tx/Rx is idle, otherwise it takes no effects.
+ *
+ * @param base LPUART peripheral base address.
+ * @param mask the status flags to be cleared. The user can use the enumerators in the
+ * _lpuart_status_flag_t to do the OR operation and get the mask.
+ * @return 0 succeed, others failed.
+ * @retval kStatus_LPUART_FlagCannotClearManually The flag can't be cleared by this function but
+ * it is cleared automatically by hardware.
+ * @retval kStatus_Success Status in the mask are cleared.
+ */
+status_t LPUART_ClearStatusFlags(LPUART_Type *base, uint32_t mask);
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables LPUART interrupts according to a provided mask.
+ *
+ * This function enables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See the @ref _lpuart_interrupt_enable.
+ * This examples shows how to enable TX empty interrupt and RX full interrupt:
+ * @code
+ * LPUART_EnableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @param mask The interrupts to enable. Logical OR of @ref _lpuart_interrupt_enable.
+ */
+void LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables LPUART interrupts according to a provided mask.
+ *
+ * This function disables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See @ref _lpuart_interrupt_enable.
+ * This example shows how to disable the TX empty interrupt and RX full interrupt:
+ * @code
+ * LPUART_DisableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @param mask The interrupts to disable. Logical OR of @ref _lpuart_interrupt_enable.
+ */
+void LPUART_DisableInterrupts(LPUART_Type *base, uint32_t mask);
+
+/*!
+ * @brief Gets enabled LPUART interrupts.
+ *
+ * This function gets the enabled LPUART interrupts. The enabled interrupts are returned
+ * as the logical OR value of the enumerators @ref _lpuart_interrupt_enable. To check
+ * a specific interrupt enable status, compare the return value with enumerators
+ * in @ref _lpuart_interrupt_enable.
+ * For example, to check whether the TX empty interrupt is enabled:
+ * @code
+ * uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(LPUART1);
+ *
+ * if (kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts)
+ * {
+ * ...
+ * }
+ * @endcode
+ *
+ * @param base LPUART peripheral base address.
+ * @return LPUART interrupt flags which are logical OR of the enumerators in @ref _lpuart_interrupt_enable.
+ */
+uint32_t LPUART_GetEnabledInterrupts(LPUART_Type *base);
+/* @} */
+
+#if defined(FSL_FEATURE_LPUART_HAS_DMA_ENABLE) && FSL_FEATURE_LPUART_HAS_DMA_ENABLE
+/*!
+ * @name DMA Configuration
+ * @{
+ */
+/*!
+ * @brief Gets the LPUART data register address.
+ *
+ * This function returns the LPUART data register address, which is mainly used by the DMA/eDMA.
+ *
+ * @param base LPUART peripheral base address.
+ * @return LPUART data register addresses which are used both by the transmitter and receiver.
+ */
+static inline uint32_t LPUART_GetDataRegisterAddress(LPUART_Type *base)
+{
+ return (uint32_t) & (base->DATA);
+}
+
+/*!
+ * @brief Enables or disables the LPUART transmitter DMA request.
+ *
+ * This function enables or disables the transmit data register empty flag, STAT[TDRE], to generate DMA requests.
+ *
+ * @param base LPUART peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void LPUART_EnableTxDMA(LPUART_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->BAUD |= LPUART_BAUD_TDMAE_MASK;
+ }
+ else
+ {
+ base->BAUD &= ~LPUART_BAUD_TDMAE_MASK;
+ }
+}
+
+/*!
+ * @brief Enables or disables the LPUART receiver DMA.
+ *
+ * This function enables or disables the receiver data register full flag, STAT[RDRF], to generate DMA requests.
+ *
+ * @param base LPUART peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void LPUART_EnableRxDMA(LPUART_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->BAUD |= LPUART_BAUD_RDMAE_MASK;
+ }
+ else
+ {
+ base->BAUD &= ~LPUART_BAUD_RDMAE_MASK;
+ }
+}
+/* @} */
+#endif /* FSL_FEATURE_LPUART_HAS_DMA_ENABLE */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Get the LPUART instance from peripheral base address.
+ *
+ * @param base LPUART peripheral base address.
+ * @return LPUART instance.
+ */
+uint32_t LPUART_GetInstance(LPUART_Type *base);
+
+/*!
+ * @brief Enables or disables the LPUART transmitter.
+ *
+ * This function enables or disables the LPUART transmitter.
+ *
+ * @param base LPUART peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void LPUART_EnableTx(LPUART_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= LPUART_CTRL_TE_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~LPUART_CTRL_TE_MASK;
+ }
+}
+
+/*!
+ * @brief Enables or disables the LPUART receiver.
+ *
+ * This function enables or disables the LPUART receiver.
+ *
+ * @param base LPUART peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void LPUART_EnableRx(LPUART_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL |= LPUART_CTRL_RE_MASK;
+ }
+ else
+ {
+ base->CTRL &= ~LPUART_CTRL_RE_MASK;
+ }
+}
+
+/*!
+ * @brief Writes to the transmitter register.
+ *
+ * This function writes data to the transmitter register directly. The upper layer must
+ * ensure that the TX register is empty or that the TX FIFO has room before calling this function.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Data write to the TX register.
+ */
+static inline void LPUART_WriteByte(LPUART_Type *base, uint8_t data)
+{
+ base->DATA = data;
+}
+
+/*!
+ * @brief Reads the receiver register.
+ *
+ * This function reads data from the receiver register directly. The upper layer must
+ * ensure that the receiver register is full or that the RX FIFO has data before calling this function.
+ *
+ * @param base LPUART peripheral base address.
+ * @return Data read from data register.
+ */
+static inline uint8_t LPUART_ReadByte(LPUART_Type *base)
+{
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ uint8_t result;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M7_MASK) == 0U) && ((ctrl & LPUART_CTRL_M_MASK) == 0U) &&
+ ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+
+ if (isSevenDataBits)
+ {
+ result = (uint8_t)(base->DATA & 0x7FU);
+ }
+ else
+ {
+ result = (uint8_t)base->DATA;
+ }
+
+ return result;
+#else
+ return (uint8_t)(base->DATA);
+#endif
+}
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+/*!
+ * @brief Gets the rx FIFO data count.
+ *
+ * @param base LPUART peripheral base address.
+ * @return rx FIFO data count.
+ */
+static inline uint8_t LPUART_GetRxFifoCount(LPUART_Type *base)
+{
+ return (uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT);
+}
+
+/*!
+ * @brief Gets the tx FIFO data count.
+ *
+ * @param base LPUART peripheral base address.
+ * @return tx FIFO data count.
+ */
+static inline uint8_t LPUART_GetTxFifoCount(LPUART_Type *base)
+{
+ return (uint8_t)((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT);
+}
+#endif
+
+/*!
+ * @brief Transmit an address frame in 9-bit data mode.
+ *
+ * @param base LPUART peripheral base address.
+ * @param address LPUART slave address.
+ */
+void LPUART_SendAddress(LPUART_Type *base, uint8_t address);
+
+/*!
+ * @brief Writes to the transmitter register using a blocking method.
+ *
+ * This function polls the transmitter register, first waits for the register to be empty or TX FIFO to have room,
+ * and writes data to the transmitter buffer, then waits for the dat to be sent out to the bus.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the data to write.
+ * @param length Size of the data to write.
+ * @retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * @retval kStatus_Success Successfully wrote all data.
+ */
+status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length);
+
+/*!
+ * @brief Reads the receiver data register using a blocking method.
+ *
+ * This function polls the receiver register, waits for the receiver register full or receiver FIFO
+ * has data, and reads data from the TX register.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the buffer to store the received data.
+ * @param length Size of the buffer.
+ * @retval kStatus_LPUART_RxHardwareOverrun Receiver overrun happened while receiving data.
+ * @retval kStatus_LPUART_NoiseError Noise error happened while receiving data.
+ * @retval kStatus_LPUART_FramingError Framing error happened while receiving data.
+ * @retval kStatus_LPUART_ParityError Parity error happened while receiving data.
+ * @retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * @retval kStatus_Success Successfully received all data.
+ */
+status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length);
+
+/* @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LPUART handle.
+ *
+ * This function initializes the LPUART handle, which can be used for other LPUART
+ * transactional APIs. Usually, for a specified LPUART instance,
+ * call this API once to get the initialized handle.
+ *
+ * The LPUART driver supports the "background" receiving, which means that user can set up
+ * an RX ring buffer optionally. Data received is stored into the ring buffer even when the
+ * user doesn't call the LPUART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ * The ring buffer is disabled if passing NULL as @p ringBuffer.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param callback Callback function.
+ * @param userData User data.
+ */
+void LPUART_TransferCreateHandle(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_callback_t callback,
+ void *userData);
+/*!
+ * @brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function send data using an interrupt method. This is a non-blocking function, which
+ * returns directly without waiting for all data written to the transmitter register. When
+ * all data is written to the TX register in the ISR, the LPUART driver calls the callback
+ * function and passes the @ref kStatus_LPUART_TxIdle as status parameter.
+ *
+ * @note The kStatus_LPUART_TxIdle is passed to the upper layer when all data are written
+ * to the TX register. However, there is no check to ensure that all the data sent out. Before disabling the TX,
+ * check the kLPUART_TransmissionCompleteFlag to ensure that the transmit is finished.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param xfer LPUART transfer structure, see #lpuart_transfer_t.
+ * @retval kStatus_Success Successfully start the data transmission.
+ * @retval kStatus_LPUART_TxBusy Previous transmission still not finished, data not all written to the TX register.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferSendNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer);
+
+/*!
+ * @brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ *
+ * @note When using RX ring buffer, one byte is reserved for internal use. In other
+ * words, if @p ringBufferSize is 32, then only 31 bytes are used for saving data.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * @param ringBufferSize size of the ring buffer.
+ */
+void LPUART_TransferStartRingBuffer(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize);
+
+/*!
+ * @brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ */
+void LPUART_TransferStopRingBuffer(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Get the length of received data in RX ring buffer.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @return Length of received data in RX ring buffer.
+ */
+size_t LPUART_TransferGetRxRingBufferLength(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
+ * how many bytes are not sent out.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortSend(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes that have been sent out to bus.
+ *
+ * This function gets the number of bytes that have been sent out to bus by an interrupt method.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Send bytes count.
+ * @retval kStatus_NoTransferInProgress No send in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using an interrupt method. This is a non-blocking function
+ * which returns without waiting to ensure that all data are received.
+ * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
+ * the parameter @p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in the ring buffer is not enough for read, the receive
+ * request is saved by the LPUART driver. When the new data arrives, the receive request
+ * is serviced first. When all data is received, the LPUART driver notifies the upper layer
+ * through a callback function and passes a status parameter kStatus_UART_RxIdle.
+ * For example, the upper layer needs 10 bytes but there are only 5 bytes in ring buffer.
+ * The 5 bytes are copied to xfer->data, which returns with the
+ * parameter @p receivedBytes set to 5. For the remaining 5 bytes, the newly arrived data is
+ * saved from xfer->data[5]. When 5 bytes are received, the LPUART driver notifies the upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param xfer LPUART transfer structure, see uart_transfer_t.
+ * @param receivedBytes Bytes received from the ring buffer directly.
+ * @retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * @retval kStatus_LPUART_RxBusy Previous receive request is not finished.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_t *xfer,
+ size_t *receivedBytes);
+
+/*!
+ * @brief Aborts the interrupt-driven data receiving.
+ *
+ * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
+ * how many bytes not received yet.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortReceive(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes that have been received.
+ *
+ * This function gets the number of bytes that have been received.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Receive bytes count.
+ * @retval kStatus_NoTransferInProgress No receive in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief LPUART IRQ handle function.
+ *
+ * This function handles the LPUART transmit and receive IRQ request.
+ *
+ * @param base LPUART peripheral base address.
+ * @param irqHandle LPUART handle pointer.
+ */
+void LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle);
+
+/*!
+ * @brief LPUART Error IRQ handle function.
+ *
+ * This function handles the LPUART error IRQ request.
+ *
+ * @param base LPUART peripheral base address.
+ * @param irqHandle LPUART handle pointer.
+ */
+void LPUART_TransferHandleErrorIRQ(LPUART_Type *base, void *irqHandle);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_LPUART_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_dma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_dma.h
new file mode 100644
index 0000000000..0434402821
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_dma.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPUART_DMA_H_
+#define _FSL_LPUART_DMA_H_
+
+#include "fsl_lpuart.h"
+#include "fsl_dma.h"
+
+/*!
+ * @addtogroup lpuart_dma_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPUART DMA driver version. */
+#define FSL_LPUART_DMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 0))
+/*@}*/
+
+/* Forward declaration of the handle typedef. */
+typedef struct _lpuart_dma_handle lpuart_dma_handle_t;
+
+/*! @brief LPUART transfer callback function. */
+typedef void (*lpuart_dma_transfer_callback_t)(LPUART_Type *base,
+ lpuart_dma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief LPUART DMA handle
+ */
+struct _lpuart_dma_handle
+{
+ lpuart_dma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< LPUART callback function parameter.*/
+ size_t rxDataSizeAll; /*!< Size of the data to receive. */
+ size_t txDataSizeAll; /*!< Size of the data to send out. */
+
+ dma_handle_t *txDmaHandle; /*!< The DMA TX channel used. */
+ dma_handle_t *rxDmaHandle; /*!< The DMA RX channel used. */
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name EDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LPUART handle which is used in transactional functions.
+ *
+ * @note This function disables all LPUART interrupts.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_dma_handle_t structure.
+ * @param callback Callback function.
+ * @param userData User data.
+ * @param txDmaHandle User-requested DMA handle for TX DMA transfer.
+ * @param rxDmaHandle User-requested DMA handle for RX DMA transfer.
+ */
+void LPUART_TransferCreateHandleDMA(LPUART_Type *base,
+ lpuart_dma_handle_t *handle,
+ lpuart_dma_transfer_callback_t callback,
+ void *userData,
+ dma_handle_t *txDmaHandle,
+ dma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Sends data using DMA.
+ *
+ * This function sends data using DMA. This is a non-blocking function, which returns
+ * right away. When all data is sent, the send callback function is called.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param xfer LPUART DMA transfer structure. See #lpuart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_LPUART_TxBusy Previous transfer on going.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferSendDMA(LPUART_Type *base, lpuart_dma_handle_t *handle, lpuart_transfer_t *xfer);
+
+/*!
+ * @brief Receives data using DMA.
+ *
+ * This function receives data using DMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_dma_handle_t structure.
+ * @param xfer LPUART DMA transfer structure. See #lpuart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_LPUART_RxBusy Previous transfer on going.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferReceiveDMA(LPUART_Type *base, lpuart_dma_handle_t *handle, lpuart_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the sent data using DMA.
+ *
+ * This function aborts send data using DMA.
+ *
+ * @param base LPUART peripheral base address
+ * @param handle Pointer to lpuart_dma_handle_t structure
+ */
+void LPUART_TransferAbortSendDMA(LPUART_Type *base, lpuart_dma_handle_t *handle);
+
+/*!
+ * @brief Aborts the received data using DMA.
+ *
+ * This function aborts the received data using DMA.
+ *
+ * @param base LPUART peripheral base address
+ * @param handle Pointer to lpuart_dma_handle_t structure
+ */
+void LPUART_TransferAbortReceiveDMA(LPUART_Type *base, lpuart_dma_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes written to the LPUART TX register.
+ *
+ * This function gets the number of bytes that have been written to LPUART TX
+ * register by DMA.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Send bytes count.
+ * @retval kStatus_NoTransferInProgress No send in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCountDMA(LPUART_Type *base, lpuart_dma_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief Gets the number of received bytes.
+ *
+ * This function gets the number of received bytes.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Receive bytes count.
+ * @retval kStatus_NoTransferInProgress No receive in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCountDMA(LPUART_Type *base, lpuart_dma_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief LPUART DMA IRQ handle function.
+ *
+ * This function handles the LPUART tx complete IRQ request and invoke user callback.
+ * @note This function is used as default IRQ handler by double weak mechanism.
+ * If user's specific IRQ handler is implemented, make sure this function is invoked in the handler.
+ *
+ * @param base LPUART peripheral base address.
+ * @param lpuartDmaHandle LPUART handle pointer.
+ */
+void LPUART_TransferDMAHandleIRQ(LPUART_Type *base, void *lpuartDmaHandle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_LPUART_DMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.c
new file mode 100644
index 0000000000..7752e54731
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpuart_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpuart_edma"
+#endif
+
+/*<! Structure definition for lpuart_edma_private_handle_t. The structure is private. */
+typedef struct _lpuart_edma_private_handle
+{
+ LPUART_Type *base;
+ lpuart_edma_handle_t *handle;
+} lpuart_edma_private_handle_t;
+
+/* LPUART EDMA transfer handle. */
+enum
+{
+ kLPUART_TxIdle, /* TX idle. */
+ kLPUART_TxBusy, /* TX busy. */
+ kLPUART_RxIdle, /* RX idle. */
+ kLPUART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of LPUART handle. */
+#if (defined(LPUART12))
+#define LPUART_HANDLE_ARRAY_SIZE 13
+#else /* LPUART12 */
+#if (defined(LPUART11))
+#define LPUART_HANDLE_ARRAY_SIZE 12
+#else /* LPUART11 */
+#if (defined(LPUART10))
+#define LPUART_HANDLE_ARRAY_SIZE 11
+#else /* LPUART10 */
+#if (defined(LPUART9))
+#define LPUART_HANDLE_ARRAY_SIZE 10
+#else /* LPUART9 */
+#if (defined(LPUART8))
+#define LPUART_HANDLE_ARRAY_SIZE 9
+#else /* LPUART8 */
+#if (defined(LPUART7))
+#define LPUART_HANDLE_ARRAY_SIZE 8
+#else /* LPUART7 */
+#if (defined(LPUART6))
+#define LPUART_HANDLE_ARRAY_SIZE 7
+#else /* LPUART6 */
+#if (defined(LPUART5))
+#define LPUART_HANDLE_ARRAY_SIZE 6
+#else /* LPUART5 */
+#if (defined(LPUART4))
+#define LPUART_HANDLE_ARRAY_SIZE 5
+#else /* LPUART4 */
+#if (defined(LPUART3))
+#define LPUART_HANDLE_ARRAY_SIZE 4
+#else /* LPUART3 */
+#if (defined(LPUART2))
+#define LPUART_HANDLE_ARRAY_SIZE 3
+#else /* LPUART2 */
+#if (defined(LPUART1))
+#define LPUART_HANDLE_ARRAY_SIZE 2
+#else /* LPUART1 */
+#if (defined(LPUART0))
+#define LPUART_HANDLE_ARRAY_SIZE 1
+#else /* LPUART0 */
+#define LPUART_HANDLE_ARRAY_SIZE FSL_FEATURE_SOC_LPUART_COUNT
+#endif /* LPUART 0 */
+#endif /* LPUART 1 */
+#endif /* LPUART 2 */
+#endif /* LPUART 3 */
+#endif /* LPUART 4 */
+#endif /* LPUART 5 */
+#endif /* LPUART 6 */
+#endif /* LPUART 7 */
+#endif /* LPUART 8 */
+#endif /* LPUART 9 */
+#endif /* LPUART 10 */
+#endif /* LPUART 11 */
+#endif /* LPUART 12 */
+
+/*<! Private handle only used for internally. */
+static lpuart_edma_private_handle_t s_lpuartEdmaPrivateHandle[LPUART_HANDLE_ARRAY_SIZE];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief LPUART EDMA send finished callback function.
+ *
+ * This function is called when LPUART EDMA send finished. It disables the LPUART
+ * TX EDMA request and sends @ref kStatus_LPUART_TxIdle to LPUART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief LPUART EDMA receive finished callback function.
+ *
+ * This function is called when LPUART EDMA receive finished. It disables the LPUART
+ * RX EDMA request and sends @ref kStatus_LPUART_RxIdle to LPUART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(NULL != param);
+
+ lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable LPUART TX EDMA. */
+ LPUART_EnableTxDMA(lpuartPrivateHandle->base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle);
+
+ /* Enable tx complete interrupt */
+ LPUART_EnableInterrupts(lpuartPrivateHandle->base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
+ }
+}
+
+static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(NULL != param);
+
+ lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
+
+ /* Avoid warning for unused parameters. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable transfer. */
+ LPUART_TransferAbortReceiveEDMA(lpuartPrivateHandle->base, lpuartPrivateHandle->handle);
+
+ if (NULL != lpuartPrivateHandle->handle->callback)
+ {
+ lpuartPrivateHandle->handle->callback(lpuartPrivateHandle->base, lpuartPrivateHandle->handle,
+ kStatus_LPUART_RxIdle, lpuartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the LPUART handle which is used in transactional functions.
+ *
+ * note This function disables all LPUART interrupts.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ * param callback Callback function.
+ * param userData User data.
+ * param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void LPUART_TransferCreateHandleEDMA(LPUART_Type *base,
+ lpuart_edma_handle_t *handle,
+ lpuart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = LPUART_GetInstance(base);
+
+ s_lpuartEdmaPrivateHandle[instance].base = base;
+ s_lpuartEdmaPrivateHandle[instance].handle = handle;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ handle->rxEdmaHandle = rxEdmaHandle;
+ handle->txEdmaHandle = txEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Note:
+ Take care of the RX FIFO, EDMA request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ EDMA transfer because the water mark is 2.
+ */
+ if (NULL != rxEdmaHandle)
+ {
+ base->WATER &= (~LPUART_WATER_RXWATER_MASK);
+ }
+#endif
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_lpuartHandle[instance] = handle;
+ /* Set LPUART_TransferEdmaHandleIRQ as DMA IRQ handler */
+ s_lpuartIsr[instance] = LPUART_TransferEdmaHandleIRQ;
+ /* Disable all LPUART internal interrupts */
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_AllInterruptEnable);
+ /* Enable interrupt in NVIC. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+ (void)EnableIRQ(s_lpuartTxIRQ[instance]);
+#else
+ (void)EnableIRQ(s_lpuartIRQ[instance]);
+#endif
+
+ /* Configure TX. */
+ if (NULL != txEdmaHandle)
+ {
+ EDMA_SetCallback(handle->txEdmaHandle, LPUART_SendEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
+ }
+
+ /* Configure RX. */
+ if (NULL != rxEdmaHandle)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, LPUART_ReceiveEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
+ }
+}
+
+/*!
+ * brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent, the send callback function is called.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART eDMA transfer structure. See #lpuart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_LPUART_TxBusy Previous transfer on going.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous TX not finished. */
+ if ((uint8_t)kLPUART_TxBusy == handle->txState)
+ {
+ status = kStatus_LPUART_TxBusy;
+ }
+ else
+ {
+ handle->txState = (uint8_t)kLPUART_TxBusy;
+ handle->txDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
+ (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
+ xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
+ handle->nbytes = (uint8_t)sizeof(uint8_t);
+
+ /* Submit transfer. */
+ if (kStatus_Success !=
+ EDMA_SubmitTransfer(handle->txEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
+ {
+ return kStatus_Fail;
+ }
+ EDMA_StartTransfer(handle->txEdmaHandle);
+
+ /* Enable LPUART TX EDMA. */
+ LPUART_EnableTxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ * param xfer LPUART eDMA transfer structure, see #lpuart_transfer_t.
+ * retval kStatus_Success if succeed, others fail.
+ * retval kStatus_LPUART_RxBusy Previous transfer ongoing.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_ReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous RX not finished. */
+ if ((uint8_t)kLPUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_LPUART_RxBusy;
+ }
+ else
+ {
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+ handle->rxDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t),
+ xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
+ handle->nbytes = (uint8_t)sizeof(uint8_t);
+
+ /* Submit transfer. */
+ if (kStatus_Success !=
+ EDMA_SubmitTransfer(handle->rxEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
+ {
+ return kStatus_Fail;
+ }
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+
+ /* Enable LPUART RX EDMA. */
+ LPUART_EnableRxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the sent data using eDMA.
+ *
+ * This function aborts the sent data using eDMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortSendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+
+ /* Disable LPUART TX EDMA. */
+ LPUART_EnableTxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->txEdmaHandle);
+
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+}
+
+/*!
+ * brief Aborts the received data using eDMA.
+ *
+ * This function aborts the received data using eDMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+
+ /* Disable LPUART RX EDMA. */
+ LPUART_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of received bytes.
+ *
+ * This function gets the number of received bytes.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Receive bytes count.
+ * retval kStatus_NoTransferInProgress No receive in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+ assert(NULL != count);
+
+ if ((uint8_t)kLPUART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll -
+ ((uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel));
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the number of bytes written to the LPUART TX register.
+ *
+ * This function gets the number of bytes written to the LPUART TX
+ * register by DMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Send bytes count.
+ * retval kStatus_NoTransferInProgress No send in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+ assert(NULL != count);
+
+ if ((uint8_t)kLPUART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll -
+ ((uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel));
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPUART eDMA IRQ handle function.
+ *
+ * This function handles the LPUART tx complete IRQ request and invoke user callback.
+ * It is not set to static so that it can be used in user application.
+ * note This function is used as default IRQ handler by double weak mechanism.
+ * If user's specific IRQ handler is implemented, make sure this function is invoked in the handler.
+ *
+ * param base LPUART peripheral base address.
+ * param lpuartEdmaHandle LPUART handle pointer.
+ */
+void LPUART_TransferEdmaHandleIRQ(LPUART_Type *base, void *lpuartEdmaHandle)
+{
+ assert(lpuartEdmaHandle != NULL);
+
+ if (((uint32_t)kLPUART_TransmissionCompleteFlag & LPUART_GetStatusFlags(base)) != 0U)
+ {
+ lpuart_edma_handle_t *handle = (lpuart_edma_handle_t *)lpuartEdmaHandle;
+
+ /* Disable tx complete interrupt */
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
+
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_LPUART_TxIdle, handle->userData);
+ }
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.h
new file mode 100644
index 0000000000..4d6fead5d0
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_edma.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPUART_EDMA_H_
+#define _FSL_LPUART_EDMA_H_
+
+#include "fsl_lpuart.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup lpuart_edma_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPUART EDMA driver version. */
+#define FSL_LPUART_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 0))
+/*@}*/
+
+/* Forward declaration of the handle typedef. */
+typedef struct _lpuart_edma_handle lpuart_edma_handle_t;
+
+/*! @brief LPUART transfer callback function. */
+typedef void (*lpuart_edma_transfer_callback_t)(LPUART_Type *base,
+ lpuart_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief LPUART eDMA handle
+ */
+struct _lpuart_edma_handle
+{
+ lpuart_edma_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< LPUART callback function parameter.*/
+ size_t rxDataSizeAll; /*!< Size of the data to receive. */
+ size_t txDataSizeAll; /*!< Size of the data to send out. */
+
+ edma_handle_t *txEdmaHandle; /*!< The eDMA TX channel used. */
+ edma_handle_t *rxEdmaHandle; /*!< The eDMA RX channel used. */
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ volatile uint8_t txState; /*!< TX transfer state. */
+ volatile uint8_t rxState; /*!< RX transfer state */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the LPUART handle which is used in transactional functions.
+ *
+ * @note This function disables all LPUART interrupts.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_edma_handle_t structure.
+ * @param callback Callback function.
+ * @param userData User data.
+ * @param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * @param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void LPUART_TransferCreateHandleEDMA(LPUART_Type *base,
+ lpuart_edma_handle_t *handle,
+ lpuart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle);
+
+/*!
+ * @brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent, the send callback function is called.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param xfer LPUART eDMA transfer structure. See #lpuart_transfer_t.
+ * @retval kStatus_Success if succeed, others failed.
+ * @retval kStatus_LPUART_TxBusy Previous transfer on going.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer);
+
+/*!
+ * @brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_edma_handle_t structure.
+ * @param xfer LPUART eDMA transfer structure, see #lpuart_transfer_t.
+ * @retval kStatus_Success if succeed, others fail.
+ * @retval kStatus_LPUART_RxBusy Previous transfer ongoing.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_ReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the sent data using eDMA.
+ *
+ * This function aborts the sent data using eDMA.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortSendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts the received data using eDMA.
+ *
+ * This function aborts the received data using eDMA.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle);
+
+/*!
+ * @brief Gets the number of bytes written to the LPUART TX register.
+ *
+ * This function gets the number of bytes written to the LPUART TX
+ * register by DMA.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Send bytes count.
+ * @retval kStatus_NoTransferInProgress No send in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief Gets the number of received bytes.
+ *
+ * This function gets the number of received bytes.
+ *
+ * @param base LPUART peripheral base address.
+ * @param handle LPUART handle pointer.
+ * @param count Receive bytes count.
+ * @retval kStatus_NoTransferInProgress No receive in progress.
+ * @retval kStatus_InvalidArgument Parameter is invalid.
+ * @retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count);
+
+/*!
+ * @brief LPUART eDMA IRQ handle function.
+ *
+ * This function handles the LPUART tx complete IRQ request and invoke user callback.
+ * It is not set to static so that it can be used in user application.
+ * @note This function is used as default IRQ handler by double weak mechanism.
+ * If user's specific IRQ handler is implemented, make sure this function is invoked in the handler.
+ *
+ * @param base LPUART peripheral base address.
+ * @param lpuartEdmaHandle LPUART handle pointer.
+ */
+void LPUART_TransferEdmaHandleIRQ(LPUART_Type *base, void *lpuartEdmaHandle);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_LPUART_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_freertos.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_freertos.h
new file mode 100644
index 0000000000..05d842efd4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpuart/fsl_lpuart_freertos.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __FSL_LPUART_RTOS_H__
+#define __FSL_LPUART_RTOS_H__
+
+#include "fsl_lpuart.h"
+#include <FreeRTOS.h>
+#include <event_groups.h>
+#include <semphr.h>
+
+/*!
+ * @addtogroup lpuart_freertos_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPUART FreeRTOS driver version. */
+#define FSL_LPUART_FREERTOS_DRIVER_VERSION (MAKE_VERSION(2, 6, 0))
+/*@}*/
+
+/*! @brief LPUART RTOS configuration structure. */
+typedef struct _lpuart_rtos_config
+{
+ LPUART_Type *base; /*!< UART base address */
+ uint32_t srcclk; /*!< UART source clock in Hz*/
+ uint32_t baudrate; /*!< Desired communication speed */
+ lpuart_parity_mode_t parity; /*!< Parity setting */
+ lpuart_stop_bit_count_t stopbits; /*!< Number of stop bits to use */
+ uint8_t *buffer; /*!< Buffer for background reception */
+ uint32_t buffer_size; /*!< Size of buffer for background reception */
+ /* Zero in constant and multiplier is interpreted as infinit timeout. */
+ uint32_t rx_timeout_constant_ms; /*!< RX timeout applied per receive */
+ uint32_t rx_timeout_multiplier_ms; /*!< RX timeout added for each byte of the receive. */
+ uint32_t tx_timeout_constant_ms; /*!< TX timeout applied per transmition */
+ uint32_t tx_timeout_multiplier_ms; /*!< TX timeout added for each byte of the transmition. */
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ bool enableRxRTS; /*!< RX RTS enable */
+ bool enableTxCTS; /*!< TX CTS enable */
+ lpuart_transmit_cts_source_t txCtsSource; /*!< TX CTS source */
+ lpuart_transmit_cts_config_t txCtsConfig; /*!< TX CTS configure */
+#endif
+} lpuart_rtos_config_t;
+
+/*!
+ * @cond RTOS_PRIVATE
+ * @name LPUART event flags
+ *
+ * This are only valid states for txEvent and rxEvent (lpuart_rtos_handle_t).
+ */
+/*@{*/
+/*! @brief Event flag - uart transmit complete. */
+#define RTOS_LPUART_TX_COMPLETE 0x1U
+/*! @brief Event flag - uart receive complete. */
+#define RTOS_LPUART_RX_COMPLETE 0x2U
+/*! @brief Event flag - ring buffer overrun. */
+#define RTOS_LPUART_RING_BUFFER_OVERRUN 0x4U
+/*! @brief Event flag - hardware buffer overrun. */
+#define RTOS_LPUART_HARDWARE_BUFFER_OVERRUN 0x8U
+/*@}*/
+
+/*! @brief LPUART FreeRTOS transfer structure. */
+typedef struct _lpuart_rtos_handle
+{
+ LPUART_Type *base; /*!< UART base address */
+ lpuart_transfer_t txTransfer; /*!< TX transfer structure */
+ lpuart_transfer_t rxTransfer; /*!< RX transfer structure */
+ SemaphoreHandle_t rxSemaphore; /*!< RX semaphore for resource sharing */
+ SemaphoreHandle_t txSemaphore; /*!< TX semaphore for resource sharing */
+ EventGroupHandle_t rxEvent; /*!< RX completion event */
+ EventGroupHandle_t txEvent; /*!< TX completion event */
+ uint32_t rx_timeout_constant_ms; /*!< RX Timeout applied per transfer */
+ uint32_t rx_timeout_multiplier_ms; /*!< RX Timeout added for each byte of the transfer. */
+ uint32_t tx_timeout_constant_ms; /*!< TX Timeout applied per transfer */
+ uint32_t tx_timeout_multiplier_ms; /*!< TX Timeout added for each byte of the transfer. */
+ void *t_state; /*!< Transactional state of the underlying driver */
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ StaticSemaphore_t txSemaphoreBuffer; /*!< Statically allocated memory for txSemaphore */
+ StaticSemaphore_t rxSemaphoreBuffer; /*!< Statically allocated memory for rxSemaphore */
+ StaticEventGroup_t txEventBuffer; /*!< Statically allocated memory for txEvent */
+ StaticEventGroup_t rxEventBuffer; /*!< Statically allocated memory for rxEvent */
+#endif
+} lpuart_rtos_handle_t;
+/*! \endcond */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name LPUART RTOS Operation
+ * @{
+ */
+
+/*!
+ * @brief Initializes an LPUART instance for operation in RTOS.
+ *
+ * @param handle The RTOS LPUART handle, the pointer to an allocated space for RTOS context.
+ * @param t_handle The pointer to an allocated space to store the transactional layer internal state.
+ * @param cfg The pointer to the parameters required to configure the LPUART after initialization.
+ * @return 0 succeed, others failed
+ */
+int LPUART_RTOS_Init(lpuart_rtos_handle_t *handle, lpuart_handle_t *t_handle, const lpuart_rtos_config_t *cfg);
+
+/*!
+ * @brief Deinitializes an LPUART instance for operation.
+ *
+ * This function deinitializes the LPUART module, sets all register value to the reset value,
+ * and releases the resources.
+ *
+ * @param handle The RTOS LPUART handle.
+ */
+int LPUART_RTOS_Deinit(lpuart_rtos_handle_t *handle);
+
+/*!
+ * @name LPUART transactional Operation
+ * @{
+ */
+
+/*!
+ * @brief Sends data in the background.
+ *
+ * This function sends data. It is an synchronous API.
+ * If the hardware buffer is full, the task is in the blocked state.
+ *
+ * @param handle The RTOS LPUART handle.
+ * @param buffer The pointer to buffer to send.
+ * @param length The number of bytes to send.
+ */
+int LPUART_RTOS_Send(lpuart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length);
+
+/*!
+ * @brief Receives data.
+ *
+ * This function receives data from LPUART. It is an synchronous API. If any data is immediately available
+ * it is returned immediately and the number of bytes received.
+ *
+ * @param handle The RTOS LPUART handle.
+ * @param buffer The pointer to buffer where to write received data.
+ * @param length The number of bytes to receive.
+ * @param received The pointer to a variable of size_t where the number of received data is filled.
+ */
+int LPUART_RTOS_Receive(lpuart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length, size_t *received);
+
+/*!
+ * @brief Set RX timeout in runtime
+ *
+ * This function can modify RX timeout between initialization and receive.
+ *
+ * param handle The RTOS LPUART handle.
+ * param rx_timeout_constant_ms RX timeout applied per receive.
+ * param rx_timeout_multiplier_ms RX timeout added for each byte of the receive.
+ */
+int LPUART_RTOS_SetRxTimeout(lpuart_rtos_handle_t *handle,
+ uint32_t rx_timeout_constant_ms,
+ uint32_t rx_timeout_multiplier_ms);
+
+/*!
+ * @brief Set TX timeout in runtime
+ *
+ * This function can modify TX timeout between initialization and send.
+ *
+ * param handle The RTOS LPUART handle.
+ * param tx_timeout_constant_ms TX timeout applied per transmition.
+ * param tx_timeout_multiplier_ms TX timeout added for each byte of the transmition.
+ */
+int LPUART_RTOS_SetTxTimeout(lpuart_rtos_handle_t *handle,
+ uint32_t tx_timeout_constant_ms,
+ uint32_t tx_timeout_multiplier_ms);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* __FSL_LPUART_RTOS_H__ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.c b/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.c
new file mode 100644
index 0000000000..04ee5b7de5
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2019-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_mecc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mecc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base MECC base address
+ *
+ * @return The MECC instance
+ */
+static uint32_t MECC_GetInstance(MECC_Type *base);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to MECC bases for each instance. */
+static MECC_Type *const s_meccBases[] = MECC_BASE_PTRS;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t MECC_GetInstance(MECC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_meccBases); instance++)
+ {
+ if (s_meccBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_meccBases));
+
+ return instance;
+}
+
+/*!
+ * brief MECC module initialization function.
+ *
+ * param base MECC base address.
+ */
+void MECC_Init(MECC_Type *base, mecc_config_t *config)
+{
+ uint32_t instance = MECC_GetInstance(base);
+ volatile uint64_t *ocramStartAddr = NULL;
+
+ /* enable all the interrupt status */
+ base->ERR_STAT_EN = kMECC_AllInterruptsStatusEnable;
+ /* clear all the interrupt status */
+ base->ERR_STATUS = kMECC_AllInterruptsFlag;
+ /* disable all the interrpt */
+ base->ERR_SIG_EN = 0U;
+
+ /* enable ECC function */
+ base->PIPE_ECC_EN = MECC_PIPE_ECC_EN_ECC_EN(config->enableMecc);
+
+ __DSB();
+
+ if (instance == (uint32_t)kMECC_Instance0)
+ {
+ /* Need to be initialized for ECC function operation, note that do not use memset() to initialize,
+ because it will use STR instruction and STR is byte access and MECC is 64 bits access operation. */
+ ocramStartAddr = (uint64_t *)config->Ocram1StartAddress;
+ while (ocramStartAddr < (uint64_t *)config->Ocram1EndAddress)
+ {
+ *ocramStartAddr = 0x00;
+ ocramStartAddr++;
+ }
+ }
+ else if (instance == (uint32_t)kMECC_Instance1)
+ {
+ /* Need to be initialized for ECC function operation, note that do not use memset() to initialize,
+ because it will use STR instruction and STR is byte access and MECC is 64 bits access operation. */
+ ocramStartAddr = (uint64_t *)config->Ocram2StartAddress;
+ while (ocramStartAddr < (uint64_t *)config->Ocram2EndAddress)
+ {
+ *ocramStartAddr = 0x00;
+ ocramStartAddr++;
+ }
+ }
+ else
+ {
+ ; /* Intentional empty for MISRA rule 15.7 */
+ }
+}
+
+/*!
+ * brief Deinitializes the MECC.
+ *
+ */
+void MECC_Deinit(MECC_Type *base)
+{
+ /* Disable ECC function */
+ base->PIPE_ECC_EN &= ~MECC_PIPE_ECC_EN_ECC_EN(1);
+}
+
+void MECC_GetDefaultConfig(mecc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Default MECC function. */
+ config->enableMecc = false;
+ /* Ocram 1 start address */
+ config->Ocram1StartAddress = 0x20240000;
+ /* Ocram 1 end address */
+ config->Ocram1EndAddress = 0x202BFFFF;
+ /* Ocram 2 address */
+ config->Ocram1StartAddress = 0x202C0000;
+ /* Ocram 2 address */
+ config->Ocram1EndAddress = 0x2033FFFF;
+}
+
+/* Initialize OCRAM */
+
+/* Mainly use for debug, it can be deprecated when release */
+status_t MECC_ErrorInjection(
+ MECC_Type *base, uint32_t lowerrordata, uint32_t higherrordata, uint8_t eccdata, uint8_t banknumber)
+{
+ status_t status = kStatus_Success;
+
+ switch (banknumber)
+ {
+ case kMECC_OcramBank0:
+ /* Low 32 bits of Ocram bank0 error injection */
+ base->ERR_DATA_INJ_LOW0 = lowerrordata;
+ /* High 32 bits of Ocram bank0 error injection */
+ base->ERR_DATA_INJ_HIGH0 = higherrordata;
+ /* Ecc code of Ocram bank0 error injection */
+ base->ERR_ECC_INJ0 = eccdata;
+ break;
+
+ case kMECC_OcramBank1:
+ /* Low 32 bits of Ocram bank1 error injection */
+ base->ERR_DATA_INJ_LOW1 = lowerrordata;
+ /* High 32 bits of Ocram bank1 error injection */
+ base->ERR_DATA_INJ_HIGH1 = higherrordata;
+ /* Ecc code of Ocram bank1 error injection */
+ base->ERR_ECC_INJ1 = eccdata;
+ break;
+
+ case kMECC_OcramBank2:
+ /* Low 32 bits of Ocram bank2 error injection */
+ base->ERR_DATA_INJ_LOW2 = lowerrordata;
+ /* High 32 bits of Ocram bank2 error injection */
+ base->ERR_DATA_INJ_HIGH2 = higherrordata;
+ /* Ecc code of Ocram bank2 error injection */
+ base->ERR_ECC_INJ2 = eccdata;
+ break;
+
+ case kMECC_OcramBank3:
+ /* Low 32 bits of Ocram bank3 error injection */
+ base->ERR_DATA_INJ_LOW3 = lowerrordata;
+ /* High 32 bits of Ocram bank3 error injection */
+ base->ERR_DATA_INJ_HIGH3 = higherrordata;
+ /* Ecc code of Ocram bank3 error injection */
+ base->ERR_ECC_INJ3 = eccdata;
+ break;
+
+ default:
+ status = kStatus_MECC_BankMiss;
+ break;
+ }
+
+ return status;
+}
+
+status_t MECC_GetSingleErrorInfo(MECC_Type *base, mecc_single_error_info_t *info, uint8_t banknumber)
+{
+ assert(info != NULL);
+ status_t status = kStatus_Success;
+ uint8_t tempPosLow = 0U;
+ uint8_t tempPosHigh = 0U;
+ uint32_t counter = 0U;
+
+ switch (banknumber)
+ {
+ case kMECC_OcramBank0:
+ info->singleErrorEccCode =
+ (uint8_t)((base->SINGLE_ERR_ADDR_ECC0 & MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ECC_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ECC_SHIFT);
+ info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC0 & MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ADDR_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ADDR_SHIFT;
+ info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW0;
+ info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH0;
+ tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW0;
+ tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH0;
+ break;
+
+ case kMECC_OcramBank1:
+ info->singleErrorEccCode =
+ (uint8_t)((base->SINGLE_ERR_ADDR_ECC1 & MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ECC_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ECC_SHIFT);
+ info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC1 & MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ADDR_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ADDR_SHIFT;
+ info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW1;
+ info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH1;
+ tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW1;
+ tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH1;
+ break;
+
+ case kMECC_OcramBank2:
+ info->singleErrorEccCode =
+ (uint8_t)((base->SINGLE_ERR_ADDR_ECC2 & MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ECC_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ECC_SHIFT);
+ info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC2 & MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ADDR_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ADDR_SHIFT;
+ info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW2;
+ info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH2;
+ tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW2;
+ tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH2;
+ break;
+
+ case kMECC_OcramBank3:
+ info->singleErrorEccCode =
+ (uint8_t)((base->SINGLE_ERR_ADDR_ECC3 & MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ECC_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ECC_SHIFT);
+ info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC3 & MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ADDR_MASK) >>
+ MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ADDR_SHIFT;
+ info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW3;
+ info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH3;
+ tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW3;
+ tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH3;
+ break;
+
+ default:
+ status = kStatus_MECC_BankMiss;
+ break;
+ }
+
+ while (tempPosLow > 0U)
+ {
+ tempPosLow = tempPosLow >> 1;
+ counter++;
+ }
+
+ if (counter == 0U)
+ {
+ info->singleErrorPosLow = 0;
+ }
+ else
+ {
+ info->singleErrorPosLow = counter - 1U;
+ }
+
+ counter = 0U;
+ while (tempPosHigh > 0U)
+ {
+ tempPosHigh = tempPosHigh >> 1;
+ counter++;
+ }
+
+ if (counter == 0U)
+ {
+ info->singleErrorPosHigh = 0;
+ }
+ else
+ {
+ info->singleErrorPosHigh = counter - 1U;
+ }
+
+ return status;
+}
+
+status_t MECC_GetMultiErrorInfo(MECC_Type *base, mecc_multi_error_info_t *info, uint8_t banknumber)
+{
+ assert(info != NULL);
+ status_t status = kStatus_Success;
+
+ switch (banknumber)
+ {
+ case kMECC_OcramBank0:
+ info->multiErrorEccCode =
+ (uint8_t)((base->MULTI_ERR_ADDR_ECC0 & MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ECC_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ECC_SHIFT);
+ info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC0 & MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ADDR_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ADDR_SHIFT;
+ info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW0;
+ info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH0;
+ break;
+
+ case kMECC_OcramBank1:
+ info->multiErrorEccCode =
+ (uint8_t)((base->MULTI_ERR_ADDR_ECC1 & MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ECC_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ECC_SHIFT);
+ info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC1 & MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ADDR_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ADDR_SHIFT;
+ info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW1;
+ info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH1;
+ break;
+
+ case kMECC_OcramBank2:
+ info->multiErrorEccCode =
+ (uint8_t)((base->MULTI_ERR_ADDR_ECC2 & MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ECC_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ECC_SHIFT);
+ info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC2 & MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ADDR_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ADDR_SHIFT;
+ info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW2;
+ info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH2;
+ break;
+
+ case kMECC_OcramBank3:
+ info->multiErrorEccCode =
+ (uint8_t)((base->MULTI_ERR_ADDR_ECC3 & MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ECC_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ECC_SHIFT);
+ info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC3 & MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ADDR_MASK) >>
+ MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ADDR_SHIFT;
+ info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW3;
+ info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH3;
+ break;
+
+ default:
+ status = kStatus_MECC_BankMiss;
+ break;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.h b/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.h
new file mode 100644
index 0000000000..472bac08d4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mecc/fsl_mecc.h
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2019-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_MECC_H_
+#define _FSL_MECC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup mecc
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions.
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Driver version 2.0.2. */
+#define FSL_MECC_DRIVER_VERSION (MAKE_VERSION(2U, 0U, 2U))
+/*@}*/
+/*! @brief Error codes for the MECC driver. */
+enum
+{
+ kStatus_MECC_BankMiss = MAKE_STATUS(kStatusGroup_MECC, 0), /*!< Ocram bank miss */
+};
+
+/*!
+ * @brief MECC interrupt configuration structure, default settings all disabled.
+ *
+ * This structure contains the settings for all of the MECC interrupt configurations.
+ */
+enum
+{
+ kMECC_SingleError0InterruptEnable =
+ MECC_ERR_SIG_EN_SINGLE_ERR0_SIG_EN_MASK, /*!< Single Bit Error On Ocram Bank0 interrupt enable.*/
+ kMECC_SingleError1InterruptEnable =
+ MECC_ERR_SIG_EN_SINGLE_ERR1_SIG_EN_MASK, /*!< Single Bit Error On Ocram Bank1 interrupt enable*/
+ kMECC_SingleError2InterruptEnable =
+ MECC_ERR_SIG_EN_SINGLE_ERR2_SIG_EN_MASK, /*!< Single Bit Error On Ocram Bank2 interrupt enable*/
+ kMECC_SingleError3InterruptEnable =
+ MECC_ERR_SIG_EN_SINGLE_ERR3_SIG_EN_MASK, /*!< Single Bit Error On Ocram Bank3 interrupt enable*/
+
+ kMECC_MultiError0InterruptEnable =
+ MECC_ERR_SIG_EN_MULTI_ERR0_SIG_EN_MASK, /*!< Multiple Bits Error On Ocram Bank0 interrupt enable*/
+ kMECC_MultiError1InterruptEnable =
+ MECC_ERR_SIG_EN_MULTI_ERR1_SIG_EN_MASK, /*!< Multiple Bits Error On Ocram Bank1 interrupt enable*/
+ kMECC_MultiError2InterruptEnable =
+ MECC_ERR_SIG_EN_MULTI_ERR2_SIG_EN_MASK, /*!< Multiple Bits Error On Ocram Bank2 interrupt enable*/
+ kMECC_MultiError3InterruptEnable =
+ MECC_ERR_SIG_EN_MULTI_ERR3_SIG_EN_MASK, /*!< Multiple Bits Error On Ocram Bank3 interrupt enable*/
+
+ kMECC_StrobeError0InterruptEnable =
+ MECC_ERR_SIG_EN_STRB_ERR0_SIG_EN_MASK, /*!< AXI Strobe Error On Ocram Bank0 interrupt enable*/
+ kMECC_StrobeError1InterruptEnable =
+ MECC_ERR_SIG_EN_STRB_ERR1_SIG_EN_MASK, /*!< AXI Strobe Error On Ocram Bank1 interrupt enable*/
+ kMECC_StrobeError2InterruptEnable =
+ MECC_ERR_SIG_EN_STRB_ERR2_SIG_EN_MASK, /*!< AXI Strobe Error On Ocram Bank2 interrupt enable*/
+ kMECC_StrobeError3InterruptEnable =
+ MECC_ERR_SIG_EN_STRB_ERR3_SIG_EN_MASK, /*!< AXI Strobe Error On Ocram Bank3 interrupt enable*/
+
+ kMECC_AccessError0InterruptEnable =
+ MECC_ERR_SIG_EN_ADDR_ERR0_SIG_EN_MASK, /*!< Ocram Access Error On Bank0 interrupt enable*/
+ kMECC_AccessError1InterruptEnable =
+ MECC_ERR_SIG_EN_ADDR_ERR1_SIG_EN_MASK, /*!< Ocram Access Error On Bank1 interrupt enable*/
+ kMECC_AccessError2InterruptEnable =
+ MECC_ERR_SIG_EN_ADDR_ERR2_SIG_EN_MASK, /*!< Ocram Access Error On Bank2 interrupt enable*/
+ kMECC_AccessError3InterruptEnable =
+ MECC_ERR_SIG_EN_ADDR_ERR3_SIG_EN_MASK, /*!< Ocram Access Error On Bank3 interrupt enable*/
+
+ kMECC_AllInterruptsEnable = 0xFFFF, /*!< all interrupts enable */
+};
+
+/*!
+ * @brief MECC interrupt status configuration structure, default settings all disabled.
+ *
+ * This structure contains the settings for all of the MECC interrupt status configurations.
+ */
+enum
+{
+ kMECC_SingleError0InterruptStatusEnable =
+ MECC_ERR_STAT_EN_SINGLE_ERR0_STAT_EN_MASK, /*!< Single Bit Error On Ocram Bank0 interrupt status enable.*/
+ kMECC_SingleError1InterruptStatusEnable =
+ MECC_ERR_STAT_EN_SINGLE_ERR1_STAT_EN_MASK, /*!< Single Bit Error On Ocram Bank1 interrupt status enable*/
+ kMECC_SingleError2InterruptStatusEnable =
+ MECC_ERR_STAT_EN_SINGLE_ERR2_STAT_EN_MASK, /*!< Single Bit Error On Ocram Bank2 interrupt status enable*/
+ kMECC_SingleError3InterruptStatusEnable =
+ MECC_ERR_STAT_EN_SINGLE_ERR3_STAT_EN_MASK, /*!< Single Bit Error On Ocram Bank3 interrupt status enable*/
+
+ kMECC_MultiError0InterruptStatusEnable =
+ MECC_ERR_STAT_EN_MULTI_ERR0_STAT_EN_MASK, /*!< Multiple Bits Error On Ocram Bank0 interrupt status enable*/
+ kMECC_MultiError1InterruptStatusEnable =
+ MECC_ERR_STAT_EN_MULTI_ERR1_STAT_EN_MASK, /*!< Multiple Bits Error On Ocram Bank1 interrupt status enable*/
+ kMECC_MultiError2InterruptStatusEnable =
+ MECC_ERR_STAT_EN_MULTI_ERR2_STAT_EN_MASK, /*!< Multiple Bits Error On Ocram Bank2 interrupt status enable*/
+ kMECC_MultiError3InterruptStatusEnable =
+ MECC_ERR_STAT_EN_MULTI_ERR3_STAT_EN_MASK, /*!< Multiple Bits Error On Ocram Bank3 interrupt status enable*/
+
+ kMECC_StrobeError0InterruptStatusEnable =
+ MECC_ERR_STAT_EN_STRB_ERR0_STAT_EN_MASK, /*!< AXI Strobe Error On Ocram Bank0 interrupt status enable*/
+ kMECC_StrobeError1InterruptStatusEnable =
+ MECC_ERR_STAT_EN_STRB_ERR1_STAT_EN_MASK, /*!< AXI Strobe Error On Ocram Bank1 interrupt status enable*/
+ kMECC_StrobeError2InterruptStatusEnable =
+ MECC_ERR_STAT_EN_STRB_ERR2_STAT_EN_MASK, /*!< AXI Strobe Error On Ocram Bank2 interrupt status enable*/
+ kMECC_StrobeError3InterruptStatusEnable =
+ MECC_ERR_STAT_EN_STRB_ERR3_STAT_EN_MASK, /*!< AXI Strobe Error On Ocram Bank3 interrupt status enable*/
+
+ kMECC_AccessError0InterruptStatusEnable =
+ MECC_ERR_STAT_EN_ADDR_ERR0_STAT_EN_MASK, /*!< Ocram Access Error On Bank0 interrupt status enable*/
+ kMECC_AccessError1InterruptStatusEnable =
+ MECC_ERR_STAT_EN_ADDR_ERR1_STAT_EN_MASK, /*!< Ocram Access Error On Bank1 interrupt status enable*/
+ kMECC_AccessError2InterruptStatusEnable =
+ MECC_ERR_STAT_EN_ADDR_ERR2_STAT_EN_MASK, /*!< Ocram Access Error On Bank2 interrupt status enable*/
+ kMECC_AccessError3InterruptStatusEnable =
+ MECC_ERR_STAT_EN_ADDR_ERR3_STAT_EN_MASK, /*!< Ocram Access Error On Bank3 interrupt status enable*/
+
+ kMECC_AllInterruptsStatusEnable = 0xFFFF, /*!< all interrupts enable */
+};
+
+/*!
+ * @brief MECC status flags.
+ *
+ * This provides constants for the MECC status flags for use in the MECC functions.
+ */
+enum
+{
+ kMECC_SingleError0InterruptFlag =
+ MECC_ERR_STATUS_SINGLE_ERR0_MASK, /*!< Single Bit Error On Ocram Bank0 interrupt flag*/
+ kMECC_SingleError1InterruptFlag =
+ MECC_ERR_STATUS_SINGLE_ERR1_MASK, /*!< Single Bit Error On Ocram Bank1 interrupt flag*/
+ kMECC_SingleError2InterruptFlag =
+ MECC_ERR_STATUS_SINGLE_ERR2_MASK, /*!< Single Bit Error On Ocram Bank2 interrupt flag*/
+ kMECC_SingleError3InterruptFlag =
+ MECC_ERR_STATUS_SINGLE_ERR3_MASK, /*!< Single Bit Error On Ocram Bank3 interrupt flag*/
+
+ kMECC_MultiError0InterruptFlag =
+ MECC_ERR_STATUS_MULTI_ERR0_MASK, /*!< Multiple Bits Error On Ocram Bank0 interrupt flag*/
+ kMECC_MultiError1InterruptFlag =
+ MECC_ERR_STATUS_MULTI_ERR1_MASK, /*!< Multiple Bits Error On Ocram Bank1 interrupt flag*/
+ kMECC_MultiError2InterruptFlag =
+ MECC_ERR_STATUS_MULTI_ERR2_MASK, /*!< Multiple Bits Error On Ocram Bank2 interrupt flag*/
+ kMECC_MultiError3InterruptFlag =
+ MECC_ERR_STATUS_MULTI_ERR3_MASK, /*!< Multiple Bits Error On Ocram Bank3 interrupt flag*/
+
+ kMECC_StrobeError0InterruptFlag =
+ MECC_ERR_STATUS_STRB_ERR0_MASK, /*!< AXI Strobe Error On Ocram Bank0 interrupt flag*/
+ kMECC_StrobeError1InterruptFlag =
+ MECC_ERR_STATUS_STRB_ERR1_MASK, /*!< AXI Strobe Error On Ocram Bank1 interrupt flag*/
+ kMECC_StrobeError2InterruptFlag =
+ MECC_ERR_STATUS_STRB_ERR2_MASK, /*!< AXI Strobe Error On Ocram Bank2 interrupt flag*/
+ kMECC_StrobeError3InterruptFlag =
+ MECC_ERR_STATUS_STRB_ERR3_MASK, /*!< AXI Strobe Error On Ocram Bank3 interrupt flag*/
+
+ kMECC_AccessError0InterruptFlag = MECC_ERR_STATUS_ADDR_ERR0_MASK, /*!< Ocram Access Error On Bank0 interrupt flag*/
+ kMECC_AccessError1InterruptFlag = MECC_ERR_STATUS_ADDR_ERR1_MASK, /*!< Ocram Access Error On Bank1 interrupt flag*/
+ kMECC_AccessError2InterruptFlag = MECC_ERR_STATUS_ADDR_ERR2_MASK, /*!< Ocram Access Error On Bank2 interrupt flag*/
+ kMECC_AccessError3InterruptFlag = MECC_ERR_STATUS_ADDR_ERR3_MASK, /*!< Ocram Access Error On Bank3 interrupt flag*/
+
+ kMECC_AllInterruptsFlag = 0xFFFF, /*!< all interrupts interrupt flag */
+};
+
+/*! @brief MECC ocram bank number */
+enum
+{
+ kMECC_OcramBank0 = 0U, /*!< ocram bank number 0: ocram_base_address+0x20*i */
+ kMECC_OcramBank1 = 1U, /*!< ocram bank number 1: ocram_base_address+0x20*i+0x8 */
+ kMECC_OcramBank2 = 2U, /*!< ocram bank number 2: ocram_base_address+0x20*i+0x10 */
+ kMECC_OcramBank3 = 3U, /*!< ocram bank number 3: ocram_base_address+0x20*i+0x18 */
+};
+
+/*! @brief MECC instance */
+enum
+{
+ kMECC_Instance0 = 0U, /*!< Peripheral MECC1 base */
+ kMECC_Instance1 = 1U, /*!< Peripheral MECC2 base */
+};
+
+/*! @brief MECC user configuration.*/
+typedef struct _mecc_config
+{
+ bool enableMecc; /*!< Enable the MECC function. */
+ uint32_t Ocram1StartAddress; /*!< Ocram 1 start address. */
+ uint32_t Ocram1EndAddress; /*!< Ocram 1 end address. */
+ uint32_t Ocram2StartAddress; /*!< Ocram 2 start address. */
+ uint32_t Ocram2EndAddress; /*!< Ocram 2 end address. */
+} mecc_config_t;
+
+/*! @brief MECC ocram single error information, including single error address, ECC code, error data and error bit
+ * position */
+typedef struct _mecc_single_error_info
+{
+ uint32_t singleErrorAddress; /*!< Single error address on Ocram bank n */
+ uint32_t singleErrorDataLow; /*!< Single error low 32 bits uncorrected read data on Ocram bank n */
+ uint32_t singleErrorDataHigh; /*!< Single error high 32 bits uncorrected read data on Ocram bank n */
+ uint32_t singleErrorPosLow; /*!< Single error bit postion of low 32 bits read data on Ocram bank n */
+ uint32_t singleErrorPosHigh; /*!< Single error bit postion of high 32 bits read data on Ocram bank n */
+ uint8_t singleErrorEccCode; /*!< Single error ECC code on Ocram bank n */
+} mecc_single_error_info_t;
+
+/*! @brief MECC ocram multiple error information, including multiple error address, ECC code, error data */
+typedef struct _mecc_multi_error_info
+{
+ uint32_t multiErrorAddress; /*!< Multiple error address on Ocram bank n */
+ uint32_t multiErrorDataLow; /*!< Multiple error low 32 bits read data on Ocram bank n */
+ uint32_t multiErrorDataHigh; /*!< Multiple error high 32 bits read data on Ocram bank n */
+ uint8_t multiErrorEccCode; /*!< Multiple error ECC code on Ocram bank n */
+} mecc_multi_error_info_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief MECC module initialization function.
+ *
+ * @param base MECC base address.
+ * @param config pointer to the MECC configuration structure.
+ */
+void MECC_Init(MECC_Type *base, mecc_config_t *config);
+
+/*!
+ * @brief Deinitializes the MECC.
+ *
+ * @param base MECC base address.
+ */
+void MECC_Deinit(MECC_Type *base);
+
+/*!
+ * @brief Sets the MECC configuration structure to default values.
+ *
+ * @param config pointer to the MECC configuration structure.
+ */
+void MECC_GetDefaultConfig(mecc_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+/*!
+ * @brief Gets MECC status flags.
+ *
+ * @param base MECC peripheral base address.
+ * @return MECC status flags.
+ */
+static inline uint32_t MECC_GetStatusFlags(MECC_Type *base)
+{
+ return base->ERR_STATUS & (uint32_t)kMECC_AllInterruptsFlag;
+}
+
+/*!
+ * @brief MECC module clear interrupt status.
+ *
+ * @param base MECC base address.
+ * @param mask status to clear.
+ */
+static inline void MECC_ClearStatusFlags(MECC_Type *base, uint32_t mask)
+{
+ base->ERR_STATUS = mask;
+}
+
+/*!
+ * @brief MECC module enable interrupt status.
+ *
+ * @param base MECC base address.
+ * @param mask status to enable.
+ */
+static inline void MECC_EnableInterruptStatus(MECC_Type *base, uint32_t mask)
+{
+ base->ERR_STAT_EN |= mask;
+}
+
+/*!
+ * @brief MECC module disable interrupt status.
+ *
+ * @param base MECC base address.
+ * @param mask status to disable.
+ */
+static inline void MECC_DisableInterruptStatus(MECC_Type *base, uint32_t mask)
+{
+ base->ERR_STAT_EN &= ~mask;
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief MECC module enable interrupt.
+ *
+ * @param base MECC base address.
+ * @param mask The interrupts to enable.
+ */
+static inline void MECC_EnableInterrupts(MECC_Type *base, uint32_t mask)
+{
+ base->ERR_SIG_EN |= mask;
+}
+
+/*!
+ * @brief MECC module disable interrupt.
+ *
+ * @param base MECC base address.
+ * @param mask The interrupts to disable.
+ */
+static inline void MECC_DisableInterrupts(MECC_Type *base, uint32_t mask)
+{
+ base->ERR_SIG_EN &= ~mask;
+}
+/* @} */
+
+/*!
+ * @name functional
+ * @{
+ */
+
+/*!
+ * @brief MECC module error injection.
+ *
+ * @param base MECC base address.
+ * @param lowerrordata low 32 bits data.
+ * @param higherrordata high 32 bits data.
+ * @param eccdata ecc code.
+ * @param banknumber ocram bank number.
+ * @retval kStatus_Success.
+ *
+ * Bank0: ocram_base_address+0x20*i
+ * Bank1: ocram_base_address+0x20*i+0x8
+ * Bank2: ocram_base_address+0x20*i+0x10
+ * Bank3: ocram_base_address+0x20*i+0x18
+ * i = 0,1,2,3,4.....
+ */
+status_t MECC_ErrorInjection(
+ MECC_Type *base, uint32_t lowerrordata, uint32_t higherrordata, uint8_t eccdata, uint8_t banknumber);
+
+/*!
+ * @brief MECC module get single error information.
+ *
+ * @param base MECC base address.
+ * @param info single error information.
+ * @param banknumber ocram bank number.
+ * @retval kStatus_Success.
+ * @retval kStatus_MECC_BankMiss.
+ *
+ * Bank0: ocram_base_address+0x20*i
+ * Bank1: ocram_base_address+0x20*i+0x8
+ * Bank2: ocram_base_address+0x20*i+0x10
+ * Bank3: ocram_base_address+0x20*i+0x18
+ * i = 0,1,2,3,4.....
+ */
+status_t MECC_GetSingleErrorInfo(MECC_Type *base, mecc_single_error_info_t *info, uint8_t banknumber);
+
+/*!
+ * @brief MECC module get multiple error information.
+ *
+ * @param base MECC base address.
+ * @param info multiple error information.
+ * @param banknumber ocram bank number.
+ * @retval kStatus_Success.
+ * @retval kStatus_MECC_BankMiss.
+ *
+ * Bank0: ocram_base_address+0x20*i
+ * Bank1: ocram_base_address+0x20*i+0x8
+ * Bank2: ocram_base_address+0x20*i+0x10
+ * Bank3: ocram_base_address+0x20*i+0x18
+ * i = 0,1,2,3,4.....
+ */
+status_t MECC_GetMultiErrorInfo(MECC_Type *base, mecc_multi_error_info_t *info, uint8_t banknumber);
+
+/*! @}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.c b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.c
new file mode 100644
index 0000000000..c4e4eaa961
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2017, 2019-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_mipi_csi2rx.h"
+
+/*
+ * The MIPI CSI2 peripheral can not work independently, some other control and
+ * status registers must be used together. There are two integration methods
+ * with these registers.
+ *
+ * 1. The registers are collected in one dedicated module: CSR.
+ * 2. The registers are scattered in multiple modules.
+ *
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mipi_csi2rx"
+#endif
+
+#if (defined(FSL_FEATURE_CSI2RX_CSR_OFFSET) && FSL_FEATURE_CSI2RX_CSR_OFFSET)
+#define CSI2RX_GET_CSR(csi_base) (MIPI_CSI_CSR_Type *)((uint32_t)(csi_base) - (uint32_t)FSL_FEATURE_CSI2RX_CSR_OFFSET)
+#define MIPI_CSI2RX_HAS_CSR 1
+#else
+#define MIPI_CSI2RX_HAS_CSR 0
+#include "fsl_soc_mipi_csi2rx.h"
+#endif
+
+#if MIPI_CSI2RX_HAS_CSR
+
+/* Macro Map */
+#ifndef MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK
+#define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK \
+ MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(2U)
+#define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK \
+ MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(1U)
+#endif
+
+#ifndef MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK
+#define MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK MIPI_CSI_CSR_PHY_CTRL_CONT_CLK_MODE_MASK
+#endif
+
+#ifndef MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE
+#define MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(x) MIPI_CSI_CSR_PHY_CTRL_S_PRG_RXHS_SETTLE(x)
+#endif
+
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * @param base The CSI2RX peripheral base address.
+ * @return CSI2RX instance number starting from 0.
+ */
+uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base);
+
+#if MIPI_CSI2RX_HAS_CSR
+
+/*!
+ * @brief Perform CSI2RX resource reset in system level.
+ *
+ * @param base The CSI2RX peripheral base address.
+ * @param reset Pass in true to set to reset state, false to release reset.
+ */
+static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset);
+
+/*!
+ * @brief Initialize the CSI2RX interface.
+ *
+ * @param base The CSI2RX peripheral base address.
+ * @param tHsSettle_EscClk t-HS_SETTLE in esc clock period.
+ */
+static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk);
+
+/*!
+ * @brief Deinitialize the CSI2RX interface.
+ *
+ * @param base The CSI2RX peripheral base address.
+ */
+static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base);
+
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map MIPI CSI2RX instance number to base address. */
+static const uint32_t s_csi2rxBaseAddrs[] = MIPI_CSI2RX_BASE_ADDRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to MPI CSI2RX clocks for each instance. */
+static const clock_ip_name_t s_csi2rxClocks[] = MIPI_CSI2RX_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+#if MIPI_CSI2RX_HAS_CSR
+static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset)
+{
+ MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
+
+ if (reset)
+ {
+ csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
+ }
+ else
+ {
+ csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
+ csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK |
+ MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
+ }
+}
+
+static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk)
+{
+ MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
+
+ /* Pixel link control */
+ csr->PLM_CTRL = 0;
+
+ /* Configure the PHY. */
+ csr->PHY_CTRL = MIPI_CSI_CSR_PHY_CTRL_RX_ENABLE_MASK | /* Enable RX. */
+ MIPI_CSI_CSR_PHY_CTRL_AUTO_PD_EN_MASK | /* Auto power down unused lanes. */
+ MIPI_CSI_CSR_PHY_CTRL_PD_MASK | MIPI_CSI_CSR_PHY_CTRL_DDRCLK_EN_MASK | /* Enable the DDR clock. */
+ MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK | /* Continue clock. */
+ MIPI_CSI_CSR_PHY_CTRL_RTERM_SEL_MASK | /* LPRX voltage level enable HS termination */
+ MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(tHsSettle_EscClk - 1UL); /* T(HS-SETTLE) */
+
+ /* Don't support interlace currently. */
+ csr->VC_INTERLACED = 0U;
+
+ /* Don't mask any data type */
+#if defined(MIPI_CSI_CSR_DATA_TYPE_DISABLE_BF_DATA_TYPE_DISABLE_MASK)
+ csr->DATA_TYPE_DISABLE_BF = 0U;
+#else
+ csr->DATA_TYPE_DIS = 0U;
+#endif
+
+ /* VC fence. */
+#if defined(MIPI_CSI_CSR_STREAM_FENCING_CONTROL_STREAM_FENCING_CONTROL_MASK)
+ csr->STREAM_FENCING_CONTROL = 0U;
+#else
+ csr->STREAM_FENCING_CTRL = 0U;
+#endif
+
+#if defined(MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK)
+ /* Wait for PL clock active. */
+ while (0UL != (csr->PLM_CTRL & MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK))
+ {
+ }
+#endif
+
+ /* Enable pixel link master. */
+ csr->PLM_CTRL |= (MIPI_CSI_CSR_PLM_CTRL_ENABLE_MASK | MIPI_CSI_CSR_PLM_CTRL_VALID_OVERRIDE_MASK);
+
+ /* Power up PHY. */
+ csr->PHY_CTRL &= ~MIPI_CSI_CSR_PHY_CTRL_PD_MASK;
+
+ /* Start clock. */
+ csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK;
+}
+
+static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base)
+{
+ MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
+
+ /* Disable the PHY. */
+ csr->PHY_CTRL = 0;
+
+ /* Disable the pixel link master. */
+ csr->PLM_CTRL = 0;
+
+ /* Stop the clock and assert reset. */
+ csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
+}
+#endif
+
+uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base)
+{
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(s_csi2rxBaseAddrs); i++)
+ {
+ if ((uint32_t)base == s_csi2rxBaseAddrs[i])
+ {
+ return i;
+ }
+ }
+
+ assert(false);
+
+ return 0;
+}
+
+/*!
+ * brief Enables and configures the CSI2RX peripheral module.
+ *
+ * param base CSI2RX peripheral address.
+ * param config CSI2RX module configuration structure.
+ */
+void CSI2RX_Init(MIPI_CSI2RX_Type *base, const csi2rx_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* un-gate clock */
+ (void)CLOCK_EnableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ MIPI_CSI2RX_SoftwareReset(base, false);
+
+ CSI2RX_REG_CFG_NUM_LANES(base) = config->laneNum - 1UL;
+ CSI2RX_REG_CFG_DISABLE_DATA_LANES(base) =
+ MIPI_CSI2RX_CSI2RX_CFG_NUM_LANES_csi2rx_cfg_num_lanes_MASK & ~((1UL << (uint32_t)config->laneNum) - 1UL);
+
+ /* Don't disable data types. */
+ CSI2RX_REG_CFG_DISABLE_PAYLOAD_0(base) = 0;
+ CSI2RX_REG_CFG_DISABLE_PAYLOAD_1(base) = 0;
+
+ /* Disable all interrupts. */
+ CSI2RX_REG_IRQ_MASK(base) = MIPI_CSI2RX_CSI2RX_IRQ_MASK_csi2rx_irq_mask_MASK;
+
+ MIPI_CSI2RX_InitInterface(base, config->tHsSettle_EscClk);
+}
+
+/*!
+ * brief Disables the CSI2RX peripheral module.
+ *
+ * param base CSI2RX peripheral address.
+ */
+void CSI2RX_Deinit(MIPI_CSI2RX_Type *base)
+{
+ MIPI_CSI2RX_DeinitInterface(base);
+
+ MIPI_CSI2RX_SoftwareReset(base, true);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* gate clock */
+ (void)CLOCK_DisableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.h b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.h
new file mode 100644
index 0000000000..ce1d14d490
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_csi2rx/fsl_mipi_csi2rx.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2017, 2019-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_MIPI_CSI2RX_H_
+#define _FSL_MIPI_CSI2RX_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup csi2rx
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief CSI2RX driver version. */
+#define FSL_CSI2RX_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+#if (defined(FSL_FEATURE_CSI2RX_HAS_NO_REG_PREFIX) && FSL_FEATURE_CSI2RX_HAS_NO_REG_PREFIX)
+
+#define CSI2RX_REG_CFG_NUM_LANES(base) (base)->CFG_NUM_LANES
+#define CSI2RX_REG_CFG_DISABLE_DATA_LANES(base) (base)->CFG_DISABLE_DATA_LANES
+#define CSI2RX_REG_BIT_ERR(base) (base)->BIT_ERR
+#define CSI2RX_REG_IRQ_STATUS(base) (base)->IRQ_STATUS
+#define CSI2RX_REG_IRQ_MASK(base) (base)->IRQ_MASK
+#define CSI2RX_REG_ULPS_STATUS(base) (base)->ULPS_STATUS
+#define CSI2RX_REG_PPI_ERRSOT_HS(base) (base)->PPI_ERRSOT_HS
+#define CSI2RX_REG_PPI_ERRSOTSYNC_HS(base) (base)->PPI_ERRSOTSYNC_HS
+#define CSI2RX_REG_PPI_ERRESC(base) (base)->PPI_ERRESC
+#define CSI2RX_REG_PPI_ERRSYNCESC(base) (base)->PPI_ERRSYNCESC
+#define CSI2RX_REG_PPI_ERRCONTROL(base) (base)->PPI_ERRCONTROL
+#define CSI2RX_REG_CFG_DISABLE_PAYLOAD_0(base) (base)->CFG_DISABLE_PAYLOAD_0
+#define CSI2RX_REG_CFG_DISABLE_PAYLOAD_1(base) (base)->CFG_DISABLE_PAYLOAD_1
+#define CSI2RX_REG_CFG_IGNORE_VC(base) (base)->CFG_IGNORE_VC
+#define CSI2RX_REG_CFG_VID_VC(base) (base)->CFG_VID_VC
+#define CSI2RX_REG_CFG_VID_P_FIFO_SEND_LEVEL(base) (base)->CFG_VID_P_FIFO_SEND_LEVEL
+#define CSI2RX_REG_CFG_VID_VSYNC(base) (base)->CFG_VID_VSYNC
+#define CSI2RX_REG_CFG_VID_HSYNC_FP(base) (base)->CFG_VID_HSYNC_FP
+#define CSI2RX_REG_CFG_VID_HSYNC(base) (base)->CFG_VID_HSYNC
+#define CSI2RX_REG_CFG_VID_HSYNC_BP(base) (base)->CFG_VID_HSYNC_BP
+
+#else
+
+#define CSI2RX_REG_CFG_NUM_LANES(base) (base)->CSI2RX_CFG_NUM_LANES
+#define CSI2RX_REG_CFG_DISABLE_DATA_LANES(base) (base)->CSI2RX_CFG_DISABLE_DATA_LANES
+#define CSI2RX_REG_BIT_ERR(base) (base)->CSI2RX_BIT_ERR
+#define CSI2RX_REG_IRQ_STATUS(base) (base)->CSI2RX_IRQ_STATUS
+#define CSI2RX_REG_IRQ_MASK(base) (base)->CSI2RX_IRQ_MASK
+#define CSI2RX_REG_ULPS_STATUS(base) (base)->CSI2RX_ULPS_STATUS
+#define CSI2RX_REG_PPI_ERRSOT_HS(base) (base)->CSI2RX_PPI_ERRSOT_HS
+#define CSI2RX_REG_PPI_ERRSOTSYNC_HS(base) (base)->CSI2RX_PPI_ERRSOTSYNC_HS
+#define CSI2RX_REG_PPI_ERRESC(base) (base)->CSI2RX_PPI_ERRESC
+#define CSI2RX_REG_PPI_ERRSYNCESC(base) (base)->CSI2RX_PPI_ERRSYNCESC
+#define CSI2RX_REG_PPI_ERRCONTROL(base) (base)->CSI2RX_PPI_ERRCONTROL
+#define CSI2RX_REG_CFG_DISABLE_PAYLOAD_0(base) (base)->CSI2RX_CFG_DISABLE_PAYLOAD_0
+#define CSI2RX_REG_CFG_DISABLE_PAYLOAD_1(base) (base)->CSI2RX_CFG_DISABLE_PAYLOAD_1
+#define CSI2RX_REG_CFG_IGNORE_VC(base) (base)->CSI2RX_CFG_IGNORE_VC
+#define CSI2RX_REG_CFG_VID_VC(base) (base)->CSI2RX_CFG_VID_VC
+#define CSI2RX_REG_CFG_VID_P_FIFO_SEND_LEVEL(base) (base)->CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL
+#define CSI2RX_REG_CFG_VID_VSYNC(base) (base)->CSI2RX_CFG_VID_VSYNC
+#define CSI2RX_REG_CFG_VID_HSYNC_FP(base) (base)->CSI2RX_CFG_VID_HSYNC_FP
+#define CSI2RX_REG_CFG_VID_HSYNC(base) (base)->CSI2RX_CFG_VID_HSYNC
+#define CSI2RX_REG_CFG_VID_HSYNC_BP(base) (base)->CSI2RX_CFG_VID_HSYNC_BP
+
+#endif
+
+#ifndef MIPI_CSI2RX_CSI2RX_CFG_NUM_LANES_csi2rx_cfg_num_lanes_MASK
+#define MIPI_CSI2RX_CSI2RX_CFG_NUM_LANES_csi2rx_cfg_num_lanes_MASK MIPI_CSI2RX_CFG_NUM_LANES_CFG_NUM_LANES_MASK
+#endif
+
+#ifndef MIPI_CSI2RX_CSI2RX_IRQ_MASK_csi2rx_irq_mask_MASK
+#define MIPI_CSI2RX_CSI2RX_IRQ_MASK_csi2rx_irq_mask_MASK MIPI_CSI2RX_IRQ_MASK_IRQ_MASK_MASK
+#endif
+
+/*! @brief CSI2RX data lanes. */
+enum _csi2rx_data_lane
+{
+ kCSI2RX_DataLane0 = (1U << 0U), /*!< Data lane 0. */
+ kCSI2RX_DataLane1 = (1U << 1U), /*!< Data lane 1. */
+ kCSI2RX_DataLane2 = (1U << 2U), /*!< Data lane 2. */
+ kCSI2RX_DataLane3 = (1U << 3U) /*!< Data lane 3. */
+};
+
+/*! @brief CSI2RX payload type. */
+enum _csi2rx_payload
+{
+ kCSI2RX_PayloadGroup0Null = (1U << 0U), /*!< NULL. */
+ kCSI2RX_PayloadGroup0Blank = (1U << 1U), /*!< Blank. */
+ kCSI2RX_PayloadGroup0Embedded = (1U << 2U), /*!< Embedded. */
+ kCSI2RX_PayloadGroup0YUV420_8Bit = (1U << 10U), /*!< Legacy YUV420 8 bit. */
+ kCSI2RX_PayloadGroup0YUV422_8Bit = (1U << 14U), /*!< YUV422 8 bit. */
+ kCSI2RX_PayloadGroup0YUV422_10Bit = (1U << 15U), /*!< YUV422 10 bit. */
+ kCSI2RX_PayloadGroup0RGB444 = (1U << 16U), /*!< RGB444. */
+ kCSI2RX_PayloadGroup0RGB555 = (1U << 17U), /*!< RGB555. */
+ kCSI2RX_PayloadGroup0RGB565 = (1U << 18U), /*!< RGB565. */
+ kCSI2RX_PayloadGroup0RGB666 = (1U << 19U), /*!< RGB666. */
+ kCSI2RX_PayloadGroup0RGB888 = (1U << 20U), /*!< RGB888. */
+ kCSI2RX_PayloadGroup0Raw6 = (1U << 24U), /*!< Raw 6. */
+ kCSI2RX_PayloadGroup0Raw7 = (1U << 25U), /*!< Raw 7. */
+ kCSI2RX_PayloadGroup0Raw8 = (1U << 26U), /*!< Raw 8. */
+ kCSI2RX_PayloadGroup0Raw10 = (1U << 27U), /*!< Raw 10. */
+ kCSI2RX_PayloadGroup0Raw12 = (1U << 28U), /*!< Raw 12. */
+ kCSI2RX_PayloadGroup0Raw14 = (1U << 29U), /*!< Raw 14. */
+ kCSI2RX_PayloadGroup1UserDefined1 = (1U << 0U), /*!< User defined 8-bit data type 1, 0x30. */
+ kCSI2RX_PayloadGroup1UserDefined2 = (1U << 1U), /*!< User defined 8-bit data type 2, 0x31. */
+ kCSI2RX_PayloadGroup1UserDefined3 = (1U << 2U), /*!< User defined 8-bit data type 3, 0x32. */
+ kCSI2RX_PayloadGroup1UserDefined4 = (1U << 3U), /*!< User defined 8-bit data type 4, 0x33. */
+ kCSI2RX_PayloadGroup1UserDefined5 = (1U << 4U), /*!< User defined 8-bit data type 5, 0x34. */
+ kCSI2RX_PayloadGroup1UserDefined6 = (1U << 5U), /*!< User defined 8-bit data type 6, 0x35. */
+ kCSI2RX_PayloadGroup1UserDefined7 = (1U << 6U), /*!< User defined 8-bit data type 7, 0x36. */
+ kCSI2RX_PayloadGroup1UserDefined8 = (1U << 7U) /*!< User defined 8-bit data type 8, 0x37. */
+};
+
+/*! @brief CSI2RX configuration. */
+typedef struct _csi2rx_config
+{
+ uint8_t laneNum; /*!< Number of active lanes used for receiving data. */
+ uint8_t tHsSettle_EscClk; /*!< Number of rx_clk_esc clock periods for T_HS_SETTLE.
+ The T_HS_SETTLE should be in the range of
+ 85ns + 6UI to 145ns + 10UI. */
+} csi2rx_config_t;
+
+/*! @brief MIPI CSI2RX bit errors. */
+enum _csi2rx_bit_error
+{
+ kCSI2RX_BitErrorEccTwoBit = (1U << 0U), /*!< ECC two bit error has occurred. */
+ kCSI2RX_BitErrorEccOneBit = (1U << 1U) /*!< ECC one bit error has occurred. */
+};
+
+/*! @brief MIPI CSI2RX PPI error types. */
+typedef enum _csi2rx_ppi_error
+{
+ kCSI2RX_PpiErrorSotHs, /*!< CSI2RX DPHY PPI error ErrSotHS. */
+ kCSI2RX_PpiErrorSotSyncHs, /*!< CSI2RX DPHY PPI error ErrSotSync_HS. */
+ kCSI2RX_PpiErrorEsc, /*!< CSI2RX DPHY PPI error ErrEsc. */
+ kCSI2RX_PpiErrorSyncEsc, /*!< CSI2RX DPHY PPI error ErrSyncEsc. */
+ kCSI2RX_PpiErrorControl, /*!< CSI2RX DPHY PPI error ErrControl. */
+} csi2rx_ppi_error_t;
+
+/*! @brief MIPI CSI2RX interrupt. */
+enum _csi2rx_interrupt
+{
+ kCSI2RX_InterruptCrcError = (1U << 0U), /* CRC error. */
+ kCSI2RX_InterruptEccOneBitError = (1U << 1U), /* One bit ECC error. */
+ kCSI2RX_InterruptEccTwoBitError = (1U << 2U), /* One bit ECC error. */
+ kCSI2RX_InterruptUlpsStatusChange = (1U << 3U), /* ULPS status changed. */
+ kCSI2RX_InterruptErrorSotHs = (1U << 4U), /* D-PHY ErrSotHS occurred. */
+ kCSI2RX_InterruptErrorSotSyncHs = (1U << 5U), /* D-PHY ErrSotSync_HS occurred. */
+ kCSI2RX_InterruptErrorEsc = (1U << 6U), /* D-PHY ErrEsc occurred. */
+ kCSI2RX_InterruptErrorSyncEsc = (1U << 7U), /* D-PHY ErrSyncEsc occurred. */
+ kCSI2RX_InterruptErrorControl = (1U << 8U), /* D-PHY ErrControl occurred. */
+};
+
+/*! @brief MIPI CSI2RX D-PHY ULPS state. */
+enum _csi2rx_ulps_status
+{
+ kCSI2RX_ClockLaneUlps = (1U << 0U), /*!< Clock lane is in ULPS state. */
+ kCSI2RX_DataLane0Ulps = (1U << 1U), /*!< Data lane 0 is in ULPS state. */
+ kCSI2RX_DataLane1Ulps = (1U << 2U), /*!< Data lane 1 is in ULPS state. */
+ kCSI2RX_DataLane2Ulps = (1U << 3U), /*!< Data lane 2 is in ULPS state. */
+ kCSI2RX_DataLane3Ulps = (1U << 4U), /*!< Data lane 3 is in ULPS state. */
+ kCSI2RX_ClockLaneMark = (1U << 5U), /*!< Clock lane is in mark state. */
+ kCSI2RX_DataLane0Mark = (1U << 6U), /*!< Data lane 0 is in mark state. */
+ kCSI2RX_DataLane1Mark = (1U << 7U), /*!< Data lane 1 is in mark state. */
+ kCSI2RX_DataLane2Mark = (1U << 8U), /*!< Data lane 2 is in mark state. */
+ kCSI2RX_DataLane3Mark = (1U << 9U), /*!< Data lane 3 is in mark state. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Enables and configures the CSI2RX peripheral module.
+ *
+ * @param base CSI2RX peripheral address.
+ * @param config CSI2RX module configuration structure.
+ */
+void CSI2RX_Init(MIPI_CSI2RX_Type *base, const csi2rx_config_t *config);
+
+/*!
+ * @brief Disables the CSI2RX peripheral module.
+ *
+ * @param base CSI2RX peripheral address.
+ */
+void CSI2RX_Deinit(MIPI_CSI2RX_Type *base);
+
+/*!
+ * @brief Gets the MIPI CSI2RX bit error status.
+ *
+ * This function gets the RX bit error status, the return value could be compared
+ * with @ref _csi2rx_bit_error. If one bit ECC error detected, the return value
+ * could be passed to the function @ref CSI2RX_GetEccBitErrorPosition to get the
+ * position of the ECC error bit.
+ *
+ * Example:
+ * @code
+ uint32_t bitError;
+ uint32_t bitErrorPosition;
+
+ bitError = CSI2RX_GetBitError(MIPI_CSI2RX);
+
+ if (kCSI2RX_BitErrorEccTwoBit & bitError)
+ {
+ Two bits error;
+ }
+ else if (kCSI2RX_BitErrorEccOneBit & bitError)
+ {
+ One bits error;
+ bitErrorPosition = CSI2RX_GetEccBitErrorPosition(bitError);
+ }
+ @endcode
+ *
+ * @param base CSI2RX peripheral address.
+ * @return The RX bit error status.
+ */
+static inline uint32_t CSI2RX_GetBitError(MIPI_CSI2RX_Type *base)
+{
+ return CSI2RX_REG_BIT_ERR(base);
+}
+
+/*!
+ * @brief Get ECC one bit error bit position.
+ *
+ * If @ref CSI2RX_GetBitError detects ECC one bit error, this function could
+ * extract the error bit position from the return value of @ref CSI2RX_GetBitError.
+ *
+ * @param bitError The bit error returned by @ref CSI2RX_GetBitError.
+ * @return The position of error bit.
+ */
+static inline uint32_t CSI2RX_GetEccBitErrorPosition(uint32_t bitError)
+{
+ return (bitError >> 2U) & 0x1FU;
+}
+
+/*!
+ * @brief Gets the MIPI CSI2RX D-PHY ULPS status.
+ *
+ * Example to check whether data lane 0 is in ULPS status.
+ * @code
+ uint32_t status = CSI2RX_GetUlpsStatus(MIPI_CSI2RX);
+
+ if (kCSI2RX_DataLane0Ulps & status)
+ {
+ Data lane 0 is in ULPS status.
+ }
+ @endcode
+ *
+ * @param base CSI2RX peripheral address.
+ * @return The MIPI CSI2RX D-PHY ULPS status, it is OR'ed value or @ref _csi2rx_ulps_status.
+ */
+static inline uint32_t CSI2RX_GetUlpsStatus(MIPI_CSI2RX_Type *base)
+{
+ return CSI2RX_REG_ULPS_STATUS(base);
+}
+
+/*!
+ * @brief Gets the MIPI CSI2RX D-PHY PPI error lanes.
+ *
+ * This function checks the PPI error occurred on which data lanes, the returned
+ * value is OR'ed value of @ref csi2rx_ppi_error_t. For example, if the ErrSotHS
+ * is detected, to check the ErrSotHS occurred on which data lanes, use like this:
+ *
+ * @code
+ uint32_t errorDataLanes = CSI2RX_GetPpiErrorDataLanes(MIPI_CSI2RX, kCSI2RX_PpiErrorSotHs);
+
+ if (kCSI2RX_DataLane0 & errorDataLanes)
+ {
+ ErrSotHS occurred on data lane 0.
+ }
+
+ if (kCSI2RX_DataLane1 & errorDataLanes)
+ {
+ ErrSotHS occurred on data lane 1.
+ }
+ @endcode
+ *
+ * @param base CSI2RX peripheral address.
+ * @param errorType What kind of error to check.
+ * @return The data lane mask that error @p errorType occurred.
+ */
+static inline uint32_t CSI2RX_GetPpiErrorDataLanes(MIPI_CSI2RX_Type *base, csi2rx_ppi_error_t errorType)
+{
+ uint32_t errorLanes;
+
+ if (kCSI2RX_PpiErrorSotHs == errorType)
+ {
+ errorLanes = CSI2RX_REG_PPI_ERRSOT_HS(base);
+ }
+ else if (kCSI2RX_PpiErrorSotSyncHs == errorType)
+ {
+ errorLanes = CSI2RX_REG_PPI_ERRSOTSYNC_HS(base);
+ }
+ else if (kCSI2RX_PpiErrorEsc == errorType)
+ {
+ errorLanes = CSI2RX_REG_PPI_ERRESC(base);
+ }
+ else if (kCSI2RX_PpiErrorSyncEsc == errorType)
+ {
+ errorLanes = CSI2RX_REG_PPI_ERRSYNCESC(base);
+ }
+ else
+ {
+ errorLanes = CSI2RX_REG_PPI_ERRCONTROL(base);
+ }
+
+ return errorLanes;
+}
+
+/*!
+ * @brief Enable the MIPI CSI2RX interrupts.
+ *
+ * This function enables the MIPI CSI2RX interrupts. The interrupts to enable
+ * are passed in as an OR'ed value of @ref _csi2rx_interrupt. For example, to enable
+ * one bit and two bit ECC error interrupts, use like this:
+ *
+ * @code
+ CSI2RX_EnableInterrupts(MIPI_CSI2RX, kCSI2RX_InterruptEccOneBitError | kCSI2RX_InterruptEccTwoBitError);
+ @endcode
+ *
+ * @param base CSI2RX peripheral address.
+ * @param mask OR'ed value of @ref _csi2rx_interrupt.
+ */
+static inline void CSI2RX_EnableInterrupts(MIPI_CSI2RX_Type *base, uint32_t mask)
+{
+ CSI2RX_REG_IRQ_MASK(base) &= ~mask;
+}
+
+/*!
+ * @brief Disable the MIPI CSI2RX interrupts.
+ *
+ * This function disables the MIPI CSI2RX interrupts. The interrupts to disable
+ * are passed in as an OR'ed value of @ref _csi2rx_interrupt. For example, to disable
+ * one bit and two bit ECC error interrupts, use like this:
+ *
+ * @code
+ CSI2RX_DisableInterrupts(MIPI_CSI2RX, kCSI2RX_InterruptEccOneBitError | kCSI2RX_InterruptEccTwoBitError);
+ @endcode
+ *
+ * @param base CSI2RX peripheral address.
+ * @param mask OR'ed value of @ref _csi2rx_interrupt.
+ */
+static inline void CSI2RX_DisableInterrupts(MIPI_CSI2RX_Type *base, uint32_t mask)
+{
+ CSI2RX_REG_IRQ_MASK(base) |= mask;
+}
+
+/*!
+ * @brief Get the MIPI CSI2RX interrupt status.
+ *
+ * This function returns the MIPI CSI2RX interrupts status as an OR'ed value
+ * of @ref _csi2rx_interrupt.
+ *
+ * @param base CSI2RX peripheral address.
+ * @return OR'ed value of @ref _csi2rx_interrupt.
+ */
+static inline uint32_t CSI2RX_GetInterruptStatus(MIPI_CSI2RX_Type *base)
+{
+ return CSI2RX_REG_IRQ_STATUS(base);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ *@}
+ */
+
+#endif /* _FSL_MIPI_CSI2RX_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c
new file mode 100644
index 0000000000..7973e38b9b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c
@@ -0,0 +1,1433 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_mipi_dsi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mipi_dsi_split"
+#endif
+
+/* The timeout cycles to wait for DSI state machine idle. */
+#ifndef FSL_MIPI_DSI_IDLE_TIMEOUT
+#define FSL_MIPI_DSI_IDLE_TIMEOUT 0x1000U
+#endif
+
+/* PLL CN should be in the range of 1 to 32. */
+#define DSI_DPHY_PLL_CN_MIN 1U
+#define DSI_DPHY_PLL_CN_MAX 32U
+
+/* PLL refClk / CN should be in the range of 24M to 30M. */
+#define DSI_DPHY_PLL_REFCLK_CN_MIN 24000000U
+#define DSI_DPHY_PLL_REFCLK_CN_MAX 30000000U
+
+/* PLL CM should be in the range of 16 to 255. */
+#define DSI_DPHY_PLL_CM_MIN 16U
+#define DSI_DPHY_PLL_CM_MAX 255U
+
+/* PLL VCO output frequency max value is 1.5GHz, VCO output is (refClk / CN ) * CM. */
+#define DSI_DPHY_PLL_VCO_MAX 1500000000U
+#define DSI_DPHY_PLL_VCO_MIN (DSI_DPHY_PLL_REFCLK_CN_MIN * DSI_DPHY_PLL_CM_MIN)
+
+#define PKT_CONTROL_WORD_COUNT(wc) ((uint32_t)(wc) << 0U)
+#define PKT_CONTROL_VC(vc) ((uint32_t)(vc) << 16U)
+#define PKT_CONTROL_HEADER_TYPE(ht) ((uint32_t)(ht) << 18U)
+#define PKT_CONTROL_HS_MASK (1UL << 24U)
+#define PKT_CONTROL_BTA_MASK (1UL << 25U)
+#define PKT_CONTROL_BTA_ONLY_MASK (1UL << 26U)
+
+/* Macro used for D-PHY timing setting. */
+#define DSI_THS_ZERO_BYTE_CLK_BASE 6U
+#define DSI_TCLK_ZERO_BYTE_CLK_BASE 3U
+#define DSI_THS_PREPARE_HALF_ESC_CLK_BASE 2U
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE 2U
+
+#define DSI_THS_PREPARE_HALF_ESC_CLK_MIN (DSI_THS_PREPARE_HALF_ESC_CLK_BASE)
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN (DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE)
+
+#define DSI_THS_PREPARE_HALF_ESC_CLK_MAX (5U)
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX (3U)
+
+/* Convert ns to byte clock. */
+#define DSI_NS_TO_BYTE_CLK(ns, byte_clk_khz) ((ns) * (byte_clk_khz) / 1000000U)
+/* Convert ns+UI to byte clock. */
+#define DSI_NS_UI_TO_BYTE_CLK(ns, UI, byte_clk_khz) ((((ns) * (byte_clk_khz)) + ((UI)*125000U)) / 1000000U)
+
+/* Packet overhead for HSA, HFP, HBP */
+#define DSI_HSA_OVERHEAD_BYTE 10UL /* HSS + HSA header + HSA CRC. */
+#define DSI_HFP_OVERHEAD_BYTE 12UL /* RGB data packet CRC + HFP header + HFP CRC. */
+#define DSI_HBP_OVERHEAD_BYTE 10UL /* HSE + HBP header + HBP CRC + RGB data packet header */
+
+#define DSI_INT_STATUS_TRIGGER_MASK \
+ ((uint32_t)kDSI_InterruptGroup1ResetTriggerReceived | (uint32_t)kDSI_InterruptGroup1TearTriggerReceived | \
+ (uint32_t)kDSI_InterruptGroup1AckTriggerReceived)
+#define DSI_INT_STATUS_ERROR_REPORT_MASK (0xFFFFU << 9U)
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+#if (defined(FSL_FEATURE_LDB_COMBO_PHY) && (0 != FSL_FEATURE_LDB_COMBO_PHY))
+typedef MIPI_DSI_LVDS_COMBO_CSR_Type MIPI_DSI_CSR_Type;
+#define MIPI_DSI_CSR_ULPS_CTRL(csr) ((csr)->ULPS_CTRL)
+#define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK
+#define MIPI_DSI_CSR_PXL2DPI(csr) ((csr)->PXL2DPI_CTRL)
+#else
+#define MIPI_DSI_CSR_ULPS_CTRL(csr) ((csr)->TX_ULPS_ENABLE)
+#define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_TX_ULPS_ENABLE_TX_ULPS_ENABLE_MASK
+#define MIPI_DSI_CSR_PXL2DPI(csr) ((csr)->PXL2DPI_CONFIG)
+#endif
+
+#define DSI_GET_CSR(dsi_base) ((MIPI_DSI_CSR_Type *)(((uint32_t)(dsi_base)) - (uint32_t)FSL_FEATURE_DSI_CSR_OFFSET))
+#endif
+
+/*! @brief Typedef for MIPI DSI interrupt handler. */
+typedef void (*dsi_isr_t)(const MIPI_DSI_Type *base, dsi_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if defined(DSI_HOST_DSI_IRQS)
+/* Array of DSI IRQ number. */
+static const IRQn_Type s_dsiIRQ[] = DSI_HOST_DSI_IRQS;
+#endif
+/*! @brief Pointers to MIPI DSI bases for each instance. */
+static DSI_HOST_Type *const s_dsiBases[] = DSI_HOST_BASE_PTRS;
+/*! @brief MIPI DSI internal handle pointer array */
+static dsi_handle_t *s_dsiHandle[ARRAY_SIZE(s_dsiBases)];
+/*! @brief Pointer to IRQ handler. */
+static dsi_isr_t s_dsiIsr;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to MIPI DSI clocks for each instance. */
+static const clock_ip_name_t s_dsiClocks[] = MIPI_DSI_HOST_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the MIPI DSI host controller instance from peripheral base address.
+ *
+ * @param base MIPI DSI peripheral base address.
+ * @return MIPI DSI instance.
+ */
+static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base);
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+/*!
+ * @brief Convert the D-PHY PLL CN to the value could be set to register.
+ *
+ * @param cn The CN value.
+ * @return The register value.
+ */
+static uint8_t DSI_EncodeDphyPllCn(uint8_t cn);
+
+/*!
+ * @brief Convert the D-PHY PLL CM to the value could be set to register.
+ *
+ * @param cm The CM value.
+ * @return The register value.
+ */
+static uint8_t DSI_EncodeDphyPllCm(uint8_t cm);
+
+/*!
+ * @brief Calculate the D-PHY PLL dividers to generate the desired output frequency.
+ *
+ * Calculate the PLL dividers to generate the most close desired output PLL frequency.
+ *
+ * txHsBitClk_Hz = refClkFreq_Hz * CM / (CN * CO).
+ * CM: 16 ~ 255
+ * CN: 1 ~ 32
+ * CO: 1, 2, 4, 8
+ *
+ * @param cn The CN value, convert using @ref DSI_EncodeDphyPllCn before setting to register.
+ * @param cm The CM value, convert using @ref DSI_EncodeDphyPllCm before setting to register.
+ * @param co The CO value, could set to register directly.
+ * @param refClkFreq_Hz The D-PHY input reference clock frequency (REF_CLK).
+ * @param desiredOutFreq_Hz Desired PLL output frequency.
+ * @return The actually output frequency using the returned dividers. If could not
+ * find suitable dividers, return 0.
+ */
+static uint32_t DSI_DphyGetPllDivider(
+ uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz);
+#endif
+
+/*!
+ * @brief Clear the RX FIFO.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ */
+static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base);
+
+/*!
+ * @brief Handle the DSI transfer result.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param xfer The transfer definition.
+ * @param intFlags1 Interrupt flag group 1.
+ * @param intFlags2 Interrupt flag group 2.
+ * @retval kStatus_Success No error happens.
+ * @retval kStatus_Timeout Hardware timeout detected.
+ * @retval kStatus_DSI_RxDataError RX data error.
+ * @retval kStatus_DSI_ErrorReportReceived Error Report packet received.
+ * @retval kStatus_DSI_Fail Transfer failed for other reasons.
+ */
+static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
+ uint32_t intFlags1,
+ uint32_t intFlags2,
+ dsi_transfer_t *xfer);
+
+/*!
+ * @brief Prepare for the DSI APB transfer.
+ *
+ * This function fills TX data to DSI TX FIFO and sets the packet control
+ * register. Packet transfer could start using @ref DSI_SendApbPacket after
+ * this function.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param xfer The transfer definition.
+ * @retval kStatus_Success It is ready to start transfer.
+ * @retval kStatus_DSI_NotSupported The transfer format is not supported.
+ */
+static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer);
+
+/*!
+ * @brief Convert time from nano-second to count of byte clock.
+ *
+ * @param ns Time in nano-second.
+ * @param byteclk_khz Byte clock frequency in kHz.
+ * @return Time in byte clock.
+ */
+static uint32_t DSI_NsToByteClk(uint32_t ns, uint32_t byteclk_khz)
+{
+ return (ns * byteclk_khz) / 1000000UL;
+}
+
+/*!
+ * @brief Convert the time to count of byte clock.
+ *
+ * The time is the sum of nano-second specified by ns and count of UI.
+ *
+ * @param ns Time in nano-second.
+ * @param UI Count of UI.
+ * @param byteclk_khz Byte clock frequency in kHz.
+ * @return Time in byte clock.
+ */
+static uint32_t DSI_NsUiToByteClk(uint32_t ns, uint32_t UI, uint32_t byteclk_khz)
+{
+ return ((ns * byteclk_khz) + (UI * 125000UL)) / 1000000UL;
+}
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dsiBases); instance++)
+ {
+ if (s_dsiBases[instance] == base->host)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dsiBases));
+
+ return instance;
+}
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+static uint8_t DSI_EncodeDphyPllCn(uint8_t cn)
+{
+ uint8_t ret = 0U;
+
+ assert((cn >= 1U) && (cn <= 32U));
+
+ if (1U == cn)
+ {
+ ret = 0x1FU;
+ }
+ else
+ {
+ ret = (uint8_t)((0x65BD44E0UL >> ((uint32_t)cn - 2U)) & 0x1FU);
+ }
+
+ return ret;
+}
+
+static uint8_t DSI_EncodeDphyPllCm(uint8_t cm)
+{
+ uint8_t ret = 0U;
+
+ assert(cm >= 16U);
+
+ if (cm <= 31U)
+ {
+ ret = 0xE0U | cm;
+ }
+ else if (cm <= 63U)
+ {
+ ret = 0xC0U | (cm & 0x1FU);
+ }
+ else if (cm <= 127U)
+ {
+ ret = 0x80U | (cm & 0x3FU);
+ }
+ else
+ {
+ ret = cm & 0xCFU;
+ }
+
+ return ret;
+}
+
+static uint32_t DSI_DphyGetPllDivider(
+ uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz)
+{
+ uint32_t cnCur;
+ uint32_t cmCur;
+ uint32_t coShiftCur;
+ uint32_t pllFreqCur;
+ uint32_t diffCur;
+ uint32_t vcoFreq;
+ uint32_t refClk_CN;
+ uint32_t diff = 0xFFFFFFFFU;
+ uint32_t pllFreqCandidate = 0U;
+
+ /* CO available values are 1, 2, 4, 8, so the shift values are 0, 1, 2, 3. */
+ for (coShiftCur = 0U; coShiftCur <= 3U; coShiftCur++)
+ {
+ /* Desired VCO output frequency. */
+ vcoFreq = desiredOutFreq_Hz << coShiftCur;
+
+ /* If desired VCO output frequency is too small, try larger CO value. */
+ if (vcoFreq < DSI_DPHY_PLL_VCO_MIN)
+ {
+ continue;
+ }
+
+ /* If desired VCO output frequency is too large, search finished. */
+ if (vcoFreq > DSI_DPHY_PLL_VCO_MAX)
+ {
+ break;
+ }
+
+ /* Now search the best CN and CM to generate disired VCO output frequency. */
+ for (cnCur = DSI_DPHY_PLL_CN_MIN; cnCur <= DSI_DPHY_PLL_CN_MAX; cnCur++)
+ {
+ /* REF_CLK / CN. */
+ refClk_CN = refClkFreq_Hz / cnCur;
+
+ /* If desired REF_CLK / CN frequency is too large, try larger CN value. */
+ if (refClk_CN > DSI_DPHY_PLL_REFCLK_CN_MAX)
+ {
+ continue;
+ }
+
+ /* If desired REF_CLK / CN frequency is too small, stop search. */
+ if (refClk_CN < DSI_DPHY_PLL_REFCLK_CN_MIN)
+ {
+ break;
+ }
+
+ /* Get the CM most close. */
+ cmCur = (vcoFreq + (refClk_CN / 2U)) / refClk_CN;
+
+ /* If calculated value is (DSI_DPHY_PLL_CM_MAX + 1), use DSI_DPHY_PLL_CM_MAX. */
+ if ((DSI_DPHY_PLL_CM_MAX + 1U) == cmCur)
+ {
+ cmCur = DSI_DPHY_PLL_CM_MAX;
+ }
+
+ if ((cmCur < DSI_DPHY_PLL_CM_MIN) || (cmCur > DSI_DPHY_PLL_CM_MAX))
+ {
+ continue;
+ }
+
+ /* Output frequency using current dividers. */
+ pllFreqCur = (refClk_CN * cmCur) >> coShiftCur;
+
+ if (pllFreqCur > desiredOutFreq_Hz)
+ {
+ diffCur = (pllFreqCur - desiredOutFreq_Hz);
+ }
+ else
+ {
+ diffCur = (desiredOutFreq_Hz - pllFreqCur);
+ }
+
+ /* If the dividers is better. */
+ if (diffCur < diff)
+ {
+ diff = diffCur;
+ *cm = cmCur;
+ *cn = cnCur;
+ *co = coShiftCur;
+ pllFreqCandidate = pllFreqCur;
+
+ /* If the output PLL frequency is exactly the disired value, return directly. */
+ if (0U == diff)
+ {
+ break;
+ }
+ }
+ }
+
+ /* If the output PLL frequency is exactly the disired value, return directly. */
+ if (0U == diff)
+ {
+ break;
+ }
+ }
+
+ return pllFreqCandidate;
+}
+#endif
+
+static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base)
+{
+ volatile uint32_t dummy = 0U;
+ uint32_t level = base->apb->PKT_FIFO_RD_LEVEL;
+
+ while (0U != (level--))
+ {
+ dummy = base->apb->PKT_RX_PAYLOAD;
+ }
+
+ (void)dummy;
+}
+
+/*!
+ * brief Initializes an MIPI DSI host with the user configuration.
+ *
+ * This function initializes the MIPI DSI host with the configuration, it should
+ * be called first before other MIPI DSI driver functions.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to a user-defined configuration structure.
+ */
+void DSI_Init(const MIPI_DSI_Type *base, const dsi_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ (void)CLOCK_EnableClock(s_dsiClocks[DSI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ DSI_HOST_Type *host = base->host;
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+ MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
+ if (config->enableTxUlps)
+ {
+ MIPI_DSI_CSR_ULPS_CTRL(csr) = MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK;
+ }
+ else
+ {
+ MIPI_DSI_CSR_ULPS_CTRL(csr) = 0U;
+ }
+#endif
+
+ host->CFG_NUM_LANES = config->numLanes - 1UL;
+
+ if (config->enableNonContinuousHsClk)
+ {
+ host->CFG_NONCONTINUOUS_CLK = 0x01U;
+ }
+ else
+ {
+ host->CFG_NONCONTINUOUS_CLK = 0x00U;
+ }
+
+ if (config->autoInsertEoTp)
+ {
+ host->CFG_AUTOINSERT_EOTP = 0x01U;
+ }
+ else
+ {
+ host->CFG_AUTOINSERT_EOTP = 0x00U;
+ }
+
+ host->CFG_EXTRA_CMDS_AFTER_EOTP = config->numExtraEoTp;
+ host->CFG_HTX_TO_COUNT = config->htxTo_ByteClk;
+ host->CFG_LRX_H_TO_COUNT = config->lrxHostTo_ByteClk;
+ host->CFG_BTA_H_TO_COUNT = config->btaTo_ByteClk;
+
+ DSI_ApbClearRxFifo(base);
+
+ /* Disable all interrupts by default, user could enable
+ * the desired interrupts later.
+ */
+ base->apb->IRQ_MASK = 0xFFFFFFFFU;
+ base->apb->IRQ_MASK2 = 0xFFFFFFFFU;
+}
+
+/*!
+ * brief Deinitializes an MIPI DSI host.
+ *
+ * This function should be called after all bother MIPI DSI driver functions.
+ *
+ * param base MIPI DSI host peripheral base address.
+ */
+void DSI_Deinit(const MIPI_DSI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ (void)CLOCK_DisableClock(s_dsiClocks[DSI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Get the default configuration to initialize the MIPI DSI host.
+ *
+ * The default value is:
+ * code
+ config->numLanes = 4;
+ config->enableNonContinuousHsClk = false;
+ config->enableTxUlps = false;
+ config->autoInsertEoTp = true;
+ config->numExtraEoTp = 0;
+ config->htxTo_ByteClk = 0;
+ config->lrxHostTo_ByteClk = 0;
+ config->btaTo_ByteClk = 0;
+ endcode
+ *
+ * param config Pointer to a user-defined configuration structure.
+ */
+void DSI_GetDefaultConfig(dsi_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->numLanes = 4;
+ config->enableNonContinuousHsClk = false;
+ config->enableTxUlps = false;
+ config->autoInsertEoTp = true;
+ config->numExtraEoTp = 0;
+ config->htxTo_ByteClk = 0;
+ config->lrxHostTo_ByteClk = 0;
+ config->btaTo_ByteClk = 0;
+}
+
+/*!
+ * brief Configure the DPI interface core.
+ *
+ * This function sets the DPI interface configuration, it should be used in
+ * video mode.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to the DPI interface configuration.
+ * param numLanes Lane number, should be same with the setting in ref dsi_dpi_config_t.
+ * param dpiPixelClkFreq_Hz The DPI pixel clock frequency in Hz.
+ * param dsiHsBitClkFreq_Hz The DSI high speed bit clock frequency in Hz. It is
+ * the same with DPHY PLL output.
+ */
+void DSI_SetDpiConfig(const MIPI_DSI_Type *base,
+ const dsi_dpi_config_t *config,
+ uint8_t numLanes,
+ uint32_t dpiPixelClkFreq_Hz,
+ uint32_t dsiHsBitClkFreq_Hz)
+{
+ assert(NULL != config);
+
+ /* coefficient DPI event size to number of DSI bytes. */
+ uint32_t coff = (numLanes * dsiHsBitClkFreq_Hz) / (dpiPixelClkFreq_Hz * 8U);
+
+ DSI_HOST_DPI_INTFC_Type *dpi = base->dpi;
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+ MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
+ MIPI_DSI_CSR_PXL2DPI(csr) = (uint32_t)config->dpiColorCoding;
+#endif
+
+ dpi->PIXEL_PAYLOAD_SIZE = config->pixelPayloadSize;
+ dpi->INTERFACE_COLOR_CODING = (uint32_t)config->dpiColorCoding;
+ dpi->PIXEL_FORMAT = (uint32_t)config->pixelPacket;
+ dpi->VIDEO_MODE = (uint32_t)config->videoMode;
+
+ if (kDSI_DpiBllpLowPower == config->bllpMode)
+ {
+ dpi->BLLP_MODE = 0x1U;
+ dpi->USE_NULL_PKT_BLLP = 0x0U;
+ }
+ else if (kDSI_DpiBllpBlanking == config->bllpMode)
+ {
+ dpi->BLLP_MODE = 0x0U;
+ dpi->USE_NULL_PKT_BLLP = 0x0U;
+ }
+ else
+ {
+ dpi->BLLP_MODE = 0x0U;
+ dpi->USE_NULL_PKT_BLLP = 0x1U;
+ }
+
+ if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiVsyncActiveHigh))
+ {
+ dpi->VSYNC_POLARITY = 0x01U;
+ }
+ else
+ {
+ dpi->VSYNC_POLARITY = 0x00U;
+ }
+
+ if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiHsyncActiveHigh))
+ {
+ dpi->HSYNC_POLARITY = 0x01U;
+ }
+ else
+ {
+ dpi->HSYNC_POLARITY = 0x00U;
+ }
+
+ dpi->HFP = config->hfp * coff - DSI_HFP_OVERHEAD_BYTE;
+ dpi->HBP = config->hbp * coff - DSI_HBP_OVERHEAD_BYTE;
+ dpi->HSA = config->hsw * coff - DSI_HSA_OVERHEAD_BYTE;
+ dpi->PIXEL_FIFO_SEND_LEVEL = config->pixelPayloadSize;
+
+ dpi->VBP = config->vbp;
+ dpi->VFP = config->vfp;
+
+ dpi->VACTIVE = config->panelHeight - 1UL;
+
+ /* TODO: Configure VC if it is available. */
+}
+
+/*!
+ * brief Initializes the D-PHY
+ *
+ * This function configures the D-PHY timing and setups the D-PHY PLL based on
+ * user configuration. The configuration structure could be got by the function
+ * ref DSI_GetDphyDefaultConfig.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to the D-PHY configuration.
+ * param refClkFreq_Hz The REFCLK frequency in Hz.
+ * return The actual D-PHY PLL output frequency. If could not configure the
+ * PLL to the target frequency, the return value is 0.
+ */
+uint32_t DSI_InitDphy(const MIPI_DSI_Type *base, const dsi_dphy_config_t *config, uint32_t refClkFreq_Hz)
+{
+ assert(NULL != config);
+
+ DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *dphy = base->dphy;
+ DSI_HOST_Type *host = base->host;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+ uint32_t cn;
+ uint32_t cm;
+ uint32_t co;
+ uint32_t outputPllFreq;
+
+ outputPllFreq = DSI_DphyGetPllDivider(&cn, &cm, &co, refClkFreq_Hz, config->txHsBitClk_Hz);
+
+ /* If could not find dividers for the output PLL frequency. */
+ if (0U == outputPllFreq)
+ {
+ return 0U;
+ }
+
+ /* Set the DPHY parameters. */
+ dphy->CN = (uint32_t)DSI_EncodeDphyPllCn((uint8_t)cn);
+ dphy->CM = (uint32_t)DSI_EncodeDphyPllCm((uint8_t)cm);
+ dphy->CO = co;
+#endif
+
+ /* Set the timing parameters. */
+ dphy->M_PRG_HS_PREPARE = (uint32_t)config->tHsPrepare_HalfEscClk - DSI_THS_PREPARE_HALF_ESC_CLK_BASE;
+ dphy->MC_PRG_HS_PREPARE = (uint32_t)config->tClkPrepare_HalfEscClk - DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE;
+ dphy->M_PRG_HS_ZERO = (uint32_t)config->tHsZero_ByteClk - DSI_THS_ZERO_BYTE_CLK_BASE;
+ dphy->MC_PRG_HS_ZERO = (uint32_t)config->tClkZero_ByteClk - DSI_TCLK_ZERO_BYTE_CLK_BASE;
+ dphy->M_PRG_HS_TRAIL = config->tHsTrail_ByteClk;
+ dphy->MC_PRG_HS_TRAIL = config->tClkTrail_ByteClk;
+
+ host->CFG_T_PRE = config->tClkPre_ByteClk;
+ host->CFG_T_POST = config->tClkPost_ByteClk;
+ host->CFG_TX_GAP = config->tHsExit_ByteClk;
+ host->CFG_TWAKEUP = config->tWakeup_EscClk;
+
+#if defined(MIPI_RTERM_SEL_dphy_rterm_sel_MASK)
+ dphy->RTERM_SEL = MIPI_RTERM_SEL_dphy_rterm_sel_MASK;
+#endif
+#if defined(MIPI_TX_RCAL_dphy_tx_rcal_MASK)
+ dphy->TX_RCAL = 1;
+#endif
+ dphy->RXLPRP = 1;
+ dphy->RXCDRP = 1;
+
+ /* Auto power down the inactive lanes. */
+ dphy->AUTO_PD_EN = 0x1U;
+
+ dphy->TST = 0x25U;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
+ /* Power up the PLL. */
+ dphy->PD_PLL = 0U;
+
+ /* Wait for the PLL lock. */
+ while (0UL == dphy->LOCK)
+ {
+ }
+#endif
+
+ /* Power up the DPHY. */
+ dphy->PD_TX = 0U;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
+ return outputPllFreq;
+#else
+ return config->txHsBitClk_Hz;
+#endif
+}
+
+/*!
+ * brief Deinitializes the D-PHY
+ *
+ * Power down the D-PHY PLL and shut down D-PHY.
+ *
+ * param base MIPI DSI host peripheral base address.
+ */
+void DSI_DeinitDphy(const MIPI_DSI_Type *base)
+{
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+ /* Power down the PLL. */
+ base->dphy->PD_PLL = 1U;
+#endif
+
+ /* Power down the DPHY. */
+ base->dphy->PD_TX = 1U;
+}
+
+/*!
+ * brief Get the default D-PHY configuration.
+ *
+ * Gets the default D-PHY configuration, the timing parameters are set according
+ * to D-PHY specification. User could use the configuration directly, or change
+ * some parameters according to the special device.
+ *
+ * param config Pointer to the D-PHY configuration.
+ * param txHsBitClk_Hz High speed bit clock in Hz.
+ * param txEscClk_Hz Esc clock in Hz.
+ */
+void DSI_GetDphyDefaultConfig(dsi_dphy_config_t *config, uint32_t txHsBitClk_Hz, uint32_t txEscClk_Hz)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ uint32_t byteClkFreq_kHz = txHsBitClk_Hz / 8U / 1000U;
+ uint32_t txEscClk_kHz = txEscClk_Hz / 1000U;
+
+ config->txHsBitClk_Hz = txHsBitClk_Hz;
+
+ /* THS-EXIT in byte clock. At least 100ns. */
+ config->tHsExit_ByteClk = (uint8_t)(DSI_NsToByteClk(100U, byteClkFreq_kHz) + 1U);
+
+ /* T-WAKEUP. At least 1ms. */
+ config->tWakeup_EscClk = (txEscClk_Hz / 1000U) + 1U;
+
+ /* THS-PREPARE. 40ns+4*UI to 85ns+6*UI. */
+ config->tHsPrepare_HalfEscClk =
+ (uint8_t)(((40U * txEscClk_kHz * 2U) / 1000000U) + (4U * txEscClk_Hz * 2U / txHsBitClk_Hz) + 1U);
+ if (config->tHsPrepare_HalfEscClk < DSI_THS_PREPARE_HALF_ESC_CLK_MIN)
+ {
+ config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MIN;
+ }
+ else if (config->tHsPrepare_HalfEscClk > DSI_THS_PREPARE_HALF_ESC_CLK_MAX)
+ {
+ config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MAX;
+ }
+ else
+ {
+ /* For MISRA check. */
+ }
+
+ /* TCLK-PREPARE. 38ns to 95ns. */
+ config->tClkPrepare_HalfEscClk = (uint8_t)((38U * txEscClk_kHz * 2U) / 1000000U + 1U);
+ if (config->tClkPrepare_HalfEscClk < DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN)
+ {
+ config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN;
+ }
+ else if (config->tClkPrepare_HalfEscClk > DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX)
+ {
+ config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX;
+ }
+ else
+ {
+ /* For MISRA check. */
+ }
+
+ /* THS-ZERO, At least 105ns+6*UI. */
+ config->tHsZero_ByteClk = (uint8_t)(DSI_NsUiToByteClk(105U, 6U, byteClkFreq_kHz) + 1U);
+ if (config->tHsZero_ByteClk < DSI_THS_ZERO_BYTE_CLK_BASE)
+ {
+ config->tHsZero_ByteClk = DSI_THS_ZERO_BYTE_CLK_BASE;
+ }
+
+ /* TCLK-ZERO, At least 262ns. */
+ config->tClkZero_ByteClk = (uint8_t)(DSI_NsToByteClk(262U, byteClkFreq_kHz) + 1U);
+ if (config->tClkZero_ByteClk < DSI_TCLK_ZERO_BYTE_CLK_BASE)
+ {
+ config->tClkZero_ByteClk = DSI_TCLK_ZERO_BYTE_CLK_BASE;
+ }
+
+ /* THS-TRAIL, 60ns+4*UI to 105ns+12UI. */
+ /* Due to IP design, extra 4*UI should be added. */
+ config->tHsTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 8U, byteClkFreq_kHz) + 1U);
+
+ /* TCLK-TRAIL, at least 60ns. */
+ /* Due to IP design, extra 4*UI should be added. */
+ config->tClkTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 4U, byteClkFreq_kHz) + 1U);
+
+ /*
+ * T_LPX + T_CLK-PREPARE + T_CLK-ZERO + T_CLK-PRE
+ * T_LPX >= 50ns
+ * T_CLK-PREPARE >= 38ns
+ * T_CLK-ZERO >= 262ns
+ * T_CLK-PRE >= 8*UI
+ */
+ config->tClkPre_ByteClk = (uint8_t)(DSI_NsUiToByteClk(88U, 8U, byteClkFreq_kHz) + 1U) + config->tClkZero_ByteClk;
+
+ /*
+ * T_CLK-POST + T_CLK-TRAIL
+ * T_CLK-POST >= 60ns + 52*UI.
+ * T_CLK-TRAIL >= 60ns
+ */
+ config->tClkPost_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 52U, byteClkFreq_kHz) + 1U) + config->tClkTrail_ByteClk;
+}
+
+/*!
+ * brief Configure the APB packet to send.
+ *
+ * This function configures the next APB packet transfer. After configuration,
+ * the packet transfer could be started with function ref DSI_SendApbPacket.
+ * If the packet is long packet, Use ref DSI_WriteApbTxPayload to fill the payload
+ * before start transfer.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param wordCount For long packet, this is the byte count of the payload.
+ * For short packet, this is (data1 << 8) | data0.
+ * param virtualChannel Virtual channel.
+ * param dataType The packet data type, (DI).
+ * param flags The transfer control flags, see ref _dsi_transfer_flags.
+ */
+void DSI_SetApbPacketControl(
+ const MIPI_DSI_Type *base, uint16_t wordCount, uint8_t virtualChannel, dsi_tx_data_type_t dataType, uint8_t flags)
+{
+ uint32_t pktCtrl = PKT_CONTROL_WORD_COUNT(wordCount) | PKT_CONTROL_HEADER_TYPE(dataType);
+
+#if defined(DSI_HOST_PKT_CONTROL_VC)
+ pktCtrl |= (uint32_t)DSI_HOST_PKT_CONTROL_VC(virtualChannel);
+#endif
+
+ if (0U != (flags & (uint8_t)kDSI_TransferUseHighSpeed))
+ {
+ pktCtrl |= PKT_CONTROL_HS_MASK;
+ }
+
+ if (0U != (flags & (uint8_t)kDSI_TransferPerformBTA))
+ {
+ pktCtrl |= PKT_CONTROL_BTA_MASK;
+ }
+
+ base->apb->PKT_CONTROL = pktCtrl;
+}
+
+/*!
+ * brief Fill the long APB packet payload.
+ *
+ * Write the long packet payload to TX FIFO.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param payload Pointer to the payload.
+ * param payloadSize Payload size in byte.
+ */
+void DSI_WriteApbTxPayload(const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize)
+{
+ DSI_WriteApbTxPayloadExt(base, payload, payloadSize, false, 0U);
+}
+
+void DSI_WriteApbTxPayloadExt(
+ const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize, bool sendDscCmd, uint8_t dscCmd)
+{
+ uint32_t firstWord;
+ uint16_t i;
+ uint16_t payloadSizeLocal = payloadSize;
+ const uint8_t *payloadLocal = payload;
+
+ DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
+
+ if (sendDscCmd)
+ {
+ payloadSizeLocal += 1U;
+ }
+
+ assert(payloadSizeLocal <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
+
+ /* The first 4-byte. */
+ if (sendDscCmd)
+ {
+ firstWord = dscCmd;
+ }
+ else
+ {
+ firstWord = *payloadLocal;
+ payloadLocal++;
+ }
+
+ payloadSizeLocal--;
+
+ for (i = 1U; i < 4U; i++)
+ {
+ if (payloadSizeLocal > 0U)
+ {
+ firstWord |= ((uint32_t)(*payloadLocal) << (i << 3U));
+ payloadLocal++;
+ payloadSizeLocal--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ apb->TX_PAYLOAD = firstWord;
+
+ /* Write the payloadLocal to the FIFO. */
+ for (i = 0; i < (payloadSizeLocal / 4U); i++)
+ {
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[3] << 24U) | ((uint32_t)payloadLocal[2] << 16U) |
+ ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ payloadLocal = &payloadLocal[4];
+ }
+
+ /* Write the remaining data. */
+ switch (payloadSizeLocal & 0x03U)
+ {
+ case 3:
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[2] << 16U) | ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ break;
+ case 2:
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ break;
+ case 1:
+ apb->TX_PAYLOAD = payloadLocal[0];
+ break;
+ default:
+ /* For MISRA 2012 16.4 */
+ break;
+ }
+}
+
+static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
+{
+ /* The receive data size should be smaller than the RX FIRO. */
+ assert(xfer->rxDataSize <= FSL_DSI_RX_MAX_PAYLOAD_BYTE);
+ assert(xfer->txDataSize <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
+
+ uint8_t txDataIndex;
+ uint16_t wordCount;
+ uint32_t intFlags1;
+ uint32_t intFlags2;
+ uint32_t txDataSize;
+
+ status_t status;
+
+ if (xfer->rxDataSize > FSL_DSI_RX_MAX_PAYLOAD_BYTE)
+ {
+ status = kStatus_DSI_NotSupported;
+ }
+ else
+ {
+ if (xfer->rxDataSize != 0U)
+ {
+ xfer->flags |= (uint8_t)kDSI_TransferPerformBTA;
+ }
+
+ /* ========================== Prepare TX. ========================== */
+ /* If xfer->sendDscCmd is true, then the DSC command is not included in the
+ xfer->txData, but specified by xfer->dscCmd.
+ */
+ if (xfer->sendDscCmd)
+ {
+ txDataSize = (uint32_t)xfer->txDataSize + 1U;
+ }
+ else
+ {
+ txDataSize = (uint32_t)xfer->txDataSize;
+ }
+
+ /* Short packet. */
+ if (txDataSize <= 2U)
+ {
+ if (0U == txDataSize)
+ {
+ wordCount = 0U;
+ }
+ else
+ {
+ txDataIndex = 0;
+
+ if (xfer->sendDscCmd)
+ {
+ wordCount = xfer->dscCmd;
+ }
+ else
+ {
+ wordCount = xfer->txData[txDataIndex++];
+ }
+
+ if (2U == txDataSize)
+ {
+ wordCount |= ((uint16_t)xfer->txData[txDataIndex] << 8U);
+ }
+ }
+ }
+ /* Long packet. */
+ else
+ {
+ wordCount = (uint16_t)txDataSize;
+ DSI_WriteApbTxPayloadExt(base, xfer->txData, xfer->txDataSize, xfer->sendDscCmd, xfer->dscCmd);
+ }
+
+ DSI_SetApbPacketControl(base, wordCount, xfer->virtualChannel, xfer->txDataType, xfer->flags);
+
+ /* Clear the interrupt flags set by previous transfer. */
+ DSI_GetAndClearInterruptStatus(base, &intFlags1, &intFlags2);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Read the long APB packet payload.
+ *
+ * Read the long packet payload from RX FIFO. This function reads directly but
+ * does not check the RX FIFO status. Upper layer should make sure there are
+ * available data.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param payload Pointer to the payload.
+ * param payloadSize Payload size in byte.
+ */
+void DSI_ReadApbRxPayload(const MIPI_DSI_Type *base, uint8_t *payload, uint16_t payloadSize)
+{
+ uint32_t tmp;
+ uint16_t i;
+ uint8_t *payloadLocal = payload;
+
+ for (i = 0; i < payloadSize / 4U; i++)
+ {
+ tmp = base->apb->PKT_RX_PAYLOAD;
+ payloadLocal[0] = (uint8_t)(tmp & 0xFFU);
+ payloadLocal[1] = (uint8_t)((tmp >> 8U) & 0xFFU);
+ payloadLocal[2] = (uint8_t)((tmp >> 16U) & 0xFFU);
+ payloadLocal[3] = (uint8_t)((tmp >> 24U) & 0xFFU);
+ payloadLocal = &payloadLocal[4];
+ }
+
+ /* Read out the remaining data. */
+ if (0U != (payloadSize & 0x03U))
+ {
+ tmp = base->apb->PKT_RX_PAYLOAD;
+
+ for (i = 0; i < (payloadSize & 0x3U); i++)
+ {
+ payloadLocal[i] = (uint8_t)(tmp & 0xFFU);
+ tmp >>= 8U;
+ }
+ }
+}
+
+/*!
+ * brief APB data transfer using blocking method.
+ *
+ * Perform APB data transfer using blocking method. This function waits until all
+ * data send or received, or timeout happens.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param xfer Pointer to the transfer structure.
+ * retval kStatus_Success Data transfer finished with no error.
+ * retval kStatus_Timeout Transfer failed because of timeout.
+ * retval kStatus_DSI_RxDataError RX data error, user could use ref DSI_GetRxErrorStatus
+ * to check the error details.
+ * retval kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
+ * ref DSI_GetAndClearHostStatus to check the error report status.
+ * retval kStatus_DSI_NotSupported Transfer format not supported.
+ * retval kStatus_DSI_Fail Transfer failed for other reasons.
+ */
+status_t DSI_TransferBlocking(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
+{
+ status_t status;
+ uint32_t intFlags1Old;
+ uint32_t intFlags2Old;
+ uint32_t intFlags1New;
+ uint32_t intFlags2New;
+
+ DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
+
+ /* Wait for the APB state idle. */
+ while (0U != (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ }
+
+ status = DSI_PrepareApbTransfer(base, xfer);
+
+ if (kStatus_Success == status)
+ {
+ DSI_SendApbPacket(base);
+
+ /* Make sure the transfer is started. */
+ while (true)
+ {
+ DSI_GetAndClearInterruptStatus(base, &intFlags1Old, &intFlags2Old);
+
+ if (0U != (intFlags1Old & (uint32_t)kDSI_InterruptGroup1ApbNotIdle))
+ {
+ break;
+ }
+ }
+
+ /* Wait for transfer finished. */
+ while (true)
+ {
+ /* Transfer completed. */
+ if (0U == (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ break;
+ }
+
+ /* Time out. */
+ if (0U != (base->host->RX_ERROR_STATUS &
+ ((uint32_t)kDSI_RxErrorHtxTo | (uint32_t)kDSI_RxErrorLrxTo | (uint32_t)kDSI_RxErrorBtaTo)))
+ {
+ status = kStatus_Timeout;
+ break;
+ }
+ }
+
+ DSI_GetAndClearInterruptStatus(base, &intFlags1New, &intFlags2New);
+
+ if (kStatus_Success == status)
+ {
+ status = DSI_HandleResult(base, intFlags1Old | intFlags1New, intFlags2Old | intFlags2New, xfer);
+ }
+ }
+
+ return status;
+}
+
+static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
+ uint32_t intFlags1,
+ uint32_t intFlags2,
+ dsi_transfer_t *xfer)
+{
+ uint32_t rxPktHeader;
+ uint16_t actualRxByteCount;
+ dsi_rx_data_type_t rxDataType;
+ bool readRxDataFromPayload;
+
+ /* If hardware detect timeout. */
+ if (0U != (((uint32_t)kDSI_InterruptGroup1HtxTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
+ (uint32_t)kDSI_InterruptGroup1BtaTo) &
+ intFlags1))
+ {
+ return kStatus_Timeout;
+ }
+
+ /* If received data error. */
+ if (0U != (((uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError) & intFlags2))
+ {
+ return kStatus_DSI_RxDataError;
+ }
+
+ /* If BTA is performed. */
+ if (0U != (xfer->flags & (uint32_t)kDSI_TransferPerformBTA))
+ {
+ if (0U != (intFlags1 & DSI_INT_STATUS_ERROR_REPORT_MASK))
+ {
+ return kStatus_DSI_ErrorReportReceived;
+ }
+
+ if (0U != ((uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived & intFlags1))
+ {
+ rxPktHeader = DSI_GetRxPacketHeader(base);
+ rxDataType = DSI_GetRxPacketType(rxPktHeader);
+
+ /* If received error report. */
+ if (kDSI_RxDataAckAndErrorReport == rxDataType)
+ {
+ return kStatus_DSI_ErrorReportReceived;
+ }
+ else
+ {
+ if ((kDSI_RxDataGenShortRdResponseOneByte == rxDataType) ||
+ (kDSI_RxDataDcsShortRdResponseOneByte == rxDataType))
+ {
+ readRxDataFromPayload = false;
+ actualRxByteCount = 1U;
+ }
+ else if ((kDSI_RxDataGenShortRdResponseTwoByte == rxDataType) ||
+ (kDSI_RxDataDcsShortRdResponseTwoByte == rxDataType))
+ {
+ readRxDataFromPayload = false;
+ actualRxByteCount = 2U;
+ }
+ else if ((kDSI_RxDataGenLongRdResponse == rxDataType) || (kDSI_RxDataDcsLongRdResponse == rxDataType))
+ {
+ readRxDataFromPayload = true;
+ actualRxByteCount = DSI_GetRxPacketWordCount(rxPktHeader);
+ }
+ else
+ {
+ readRxDataFromPayload = false;
+ xfer->rxDataSize = 0U;
+ actualRxByteCount = 0U;
+ }
+
+ xfer->rxDataSize = MIN(xfer->rxDataSize, actualRxByteCount);
+
+ if (xfer->rxDataSize > 0U)
+ {
+ if (readRxDataFromPayload)
+ {
+ DSI_ReadApbRxPayload(base, xfer->rxData, xfer->rxDataSize);
+ }
+ else
+ {
+ xfer->rxData[0] = (uint8_t)(rxPktHeader & 0xFFU);
+
+ if (2U == xfer->rxDataSize)
+ {
+ xfer->rxData[1] = (uint8_t)((rxPktHeader >> 8U) & 0xFFU);
+ }
+ }
+ }
+
+ return kStatus_Success;
+ }
+ }
+
+ return kStatus_Success;
+ }
+ else
+ {
+ /* Tx Done. */
+ if (0U != ((uint32_t)kDSI_InterruptGroup1ApbTxDone & intFlags1))
+ {
+ return kStatus_Success;
+ }
+ }
+
+ return kStatus_Fail;
+}
+
+/*!
+ * brief Create the MIPI DSI handle.
+ *
+ * This function initializes the MIPI DSI handle which can be used for other transactional APIs.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle Handle pointer.
+ * param callback Callback function.
+ * param userData User data.
+ */
+status_t DSI_TransferCreateHandle(const MIPI_DSI_Type *base,
+ dsi_handle_t *handle,
+ dsi_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = DSI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Initialize the handle */
+ s_dsiHandle[instance] = handle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->isBusy = false;
+ handle->dsi = base;
+ s_dsiIsr = DSI_TransferHandleIRQ;
+
+#if defined(DSI_HOST_DSI_IRQS)
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(s_dsiIRQ[instance]);
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief APB data transfer using interrupt method.
+ *
+ * Perform APB data transfer using interrupt method, when transfer finished,
+ * upper layer could be informed through callback function.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the transfer structure.
+ *
+ * retval kStatus_Success Data transfer started successfully.
+ * retval kStatus_DSI_Busy Failed to start transfer because DSI is busy with pervious transfer.
+ * retval kStatus_DSI_NotSupported Transfer format not supported.
+ */
+status_t DSI_TransferNonBlocking(const MIPI_DSI_Type *base, dsi_handle_t *handle, dsi_transfer_t *xfer)
+{
+ status_t status;
+
+ if (handle->isBusy)
+ {
+ status = kStatus_DSI_Busy;
+ }
+ else if (0U != (base->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ status = kStatus_DSI_Busy;
+ }
+ else
+ {
+ handle->xfer = *xfer;
+
+ status = DSI_PrepareApbTransfer(base, &handle->xfer);
+
+ if (kStatus_Success == status)
+ {
+ DSI_SendApbPacket(base);
+ handle->isBusy = true;
+
+ /* Enable the interrupts. */
+ if (0U != (handle->xfer.flags & (uint32_t)kDSI_TransferPerformBTA))
+ {
+ DSI_EnableInterrupts(
+ base,
+ DSI_INT_STATUS_TRIGGER_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
+ (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo |
+ (uint32_t)kDSI_InterruptGroup1AckTriggerReceived,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+ }
+ else
+ {
+ DSI_EnableInterrupts(base,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | (uint32_t)kDSI_InterruptGroup1HtxTo, 0U);
+ }
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Abort current APB data transfer.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferAbort(const MIPI_DSI_Type *base, dsi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ if (handle->isBusy)
+ {
+ /* Disable the interrupts. */
+ DSI_DisableInterrupts(base,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
+ DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
+ (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
+ (uint32_t)kDSI_InterruptGroup1HtxTo,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+
+ /* Reset transfer info. */
+ (void)memset(&handle->xfer, 0, sizeof(handle->xfer));
+
+ /* Reset the state to idle. */
+ handle->isBusy = false;
+ }
+}
+
+/*!
+ * brief Interrupt handler for the DSI.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferHandleIRQ(const MIPI_DSI_Type *base, dsi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ status_t status;
+ uint32_t intFlags1;
+ uint32_t intFlags2;
+ uint32_t timeout;
+ const MIPI_DSI_Type *dsi = handle->dsi;
+
+ /* If no transfer in progress, return directly. */
+ if (handle->isBusy)
+ {
+ /* Make sure the transfer is completed. */
+ timeout = FSL_MIPI_DSI_IDLE_TIMEOUT;
+ while (0U != (timeout--))
+ {
+ if (0U == (dsi->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ break;
+ }
+ }
+
+ if (0U == timeout)
+ {
+ DSI_TransferAbort(dsi, handle);
+ status = kStatus_Timeout;
+ }
+ else
+ {
+ /* Disable the interrupts. */
+ DSI_DisableInterrupts(
+ dsi,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
+ DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
+ (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+
+ DSI_GetAndClearInterruptStatus(dsi, &intFlags1, &intFlags2);
+
+ status = DSI_HandleResult(dsi, intFlags1, intFlags2, &handle->xfer);
+ handle->isBusy = false;
+ }
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(dsi, handle, status, handle->userData);
+ }
+ }
+
+ return;
+}
+
+#if defined(DSI_HOST)
+void MIPI_DSI_DriverIRQHandler(void);
+void MIPI_DSI_DriverIRQHandler(void)
+{
+ /* The first parameter is not used, use the peripheral address defined in
+ * handle.
+ */
+ s_dsiIsr(NULL, s_dsiHandle[0]);
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.h b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.h
new file mode 100644
index 0000000000..25aff2bd89
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.h
@@ -0,0 +1,824 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_MIPI_DSI_H_
+#define _FSL_MIPI_DSI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup mipi_dsi
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_MIPI_DSI_DRIVER_VERSION (MAKE_VERSION(2, 2, 3))
+/*@}*/
+
+/* The max APB transfer size. */
+#define FSL_DSI_TX_MAX_PAYLOAD_BYTE (64U * 4U)
+#define FSL_DSI_RX_MAX_PAYLOAD_BYTE (64U * 4U)
+
+/*! @brief MIPI DSI structure definition. */
+typedef struct
+{
+ DSI_HOST_Type *host; /*!< Pointer to HOST registers. */
+ DSI_HOST_APB_PKT_IF_Type *apb; /*!< Pointer to APB registers. */
+ DSI_HOST_DPI_INTFC_Type *dpi; /*!< Pointer to DPI registers. */
+ DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *dphy; /*!< Pointer to DPHY registers. */
+} MIPI_DSI_Type;
+
+/*! @brief Error codes for the MIPI DSI driver. */
+enum
+{
+ kStatus_DSI_Busy = MAKE_STATUS((int32_t)kStatusGroup_MIPI_DSI, 0), /*!< DSI is busy. */
+ kStatus_DSI_RxDataError = MAKE_STATUS((int32_t)kStatusGroup_MIPI_DSI, 1), /*!< Read data error. */
+ kStatus_DSI_ErrorReportReceived =
+ MAKE_STATUS((int32_t)kStatusGroup_MIPI_DSI, 2), /*!< Error report package received. */
+ kStatus_DSI_NotSupported = MAKE_STATUS((int32_t)kStatusGroup_MIPI_DSI, 3), /*!< The transfer type not supported. */
+};
+
+/*! @brief MIPI DSI controller configuration. */
+typedef struct _dsi_config
+{
+ uint8_t numLanes; /*!< Number of lanes. */
+ bool enableNonContinuousHsClk; /*!< In enabled, the high speed clock will enter
+ low power mode between transmissions. */
+ bool enableTxUlps; /*!< Enable the TX ULPS. */
+ bool autoInsertEoTp; /*!< Insert an EoTp short package when switching from HS to LP. */
+ uint8_t numExtraEoTp; /*!< How many extra EoTp to send after the end of a packet. */
+ uint32_t htxTo_ByteClk; /*!< HS TX timeout count (HTX_TO) in byte clock. */
+ uint32_t lrxHostTo_ByteClk; /*!< LP RX host timeout count (LRX-H_TO) in byte clock. */
+ uint32_t btaTo_ByteClk; /*!< Bus turn around timeout count (TA_TO) in byte clock. */
+} dsi_config_t;
+
+/*! @brief MIPI DPI interface color coding. */
+typedef enum _dsi_dpi_color_coding
+{
+ kDSI_Dpi16BitConfig1 = 0U, /*!< 16-bit configuration 1. RGB565: XXXXXXXX_RRRRRGGG_GGGBBBBB. */
+ kDSI_Dpi16BitConfig2 = 1U, /*!< 16-bit configuration 2. RGB565: XXXRRRRR_XXGGGGGG_XXXBBBBB. */
+ kDSI_Dpi16BitConfig3 = 2U, /*!< 16-bit configuration 3. RGB565: XXRRRRRX_XXGGGGGG_XXBBBBBX. */
+ kDSI_Dpi18BitConfig1 = 3U, /*!< 18-bit configuration 1. RGB666: XXXXXXRR_RRRRGGGG_GGBBBBBB. */
+ kDSI_Dpi18BitConfig2 = 4U, /*!< 18-bit configuration 2. RGB666: XXRRRRRR_XXGGGGGG_XXBBBBBB. */
+ kDSI_Dpi24Bit = 5U, /*!< 24-bit. */
+} dsi_dpi_color_coding_t;
+
+/*! @brief MIPI DSI pixel packet type send through DPI interface. */
+typedef enum _dsi_dpi_pixel_packet
+{
+ kDSI_PixelPacket16Bit = 0U, /*!< 16 bit RGB565. */
+ kDSI_PixelPacket18Bit = 1U, /*!< 18 bit RGB666 packed. */
+ kDSI_PixelPacket18BitLoosely = 2U, /*!< 18 bit RGB666 loosely packed into three bytes. */
+ kDSI_PixelPacket24Bit = 3U, /*!< 24 bit RGB888, each pixel uses three bytes. */
+} dsi_dpi_pixel_packet_t;
+
+/*! @brief _dsi_dpi_polarity_flag DPI signal polarity. */
+enum
+{
+ kDSI_DpiVsyncActiveLow = 0U, /*!< VSYNC active low. */
+ kDSI_DpiHsyncActiveLow = 0U, /*!< HSYNC active low. */
+ kDSI_DpiVsyncActiveHigh = (1U << 0U), /*!< VSYNC active high. */
+ kDSI_DpiHsyncActiveHigh = (1U << 1U), /*!< HSYNC active high. */
+};
+
+/*! @brief DPI video mode. */
+typedef enum _dsi_dpi_video_mode
+{
+ kDSI_DpiNonBurstWithSyncPulse = 0U, /*!< Non-Burst mode with Sync Pulses. */
+ kDSI_DpiNonBurstWithSyncEvent = 1U, /*!< Non-Burst mode with Sync Events. */
+ kDSI_DpiBurst = 2U, /*!< Burst mode. */
+} dsi_dpi_video_mode_t;
+
+/*! @brief Behavior in BLLP (Blanking or Low-Power Interval). */
+typedef enum _dsi_dpi_bllp_mode
+{
+ kDSI_DpiBllpLowPower, /*!< LP mode used in BLLP periods. */
+ kDSI_DpiBllpBlanking, /*!< Blanking packets used in BLLP periods. */
+ kDSI_DpiBllpNull, /*!< Null packets used in BLLP periods. */
+} dsi_dpi_bllp_mode_t;
+
+/*! @brief MIPI DSI controller DPI interface configuration. */
+typedef struct _dsi_dpi_config
+{
+ uint16_t pixelPayloadSize; /*!< Maximum number of pixels that should be sent
+ as one DSI packet. Recommended that the line size
+ (in pixels) is evenly divisible by this parameter. */
+ dsi_dpi_color_coding_t dpiColorCoding; /*!< DPI color coding. */
+ dsi_dpi_pixel_packet_t pixelPacket; /*!< Pixel packet format. */
+
+ dsi_dpi_video_mode_t videoMode; /*!< Video mode. */
+ dsi_dpi_bllp_mode_t bllpMode; /*!< Behavior in BLLP. */
+
+ uint8_t polarityFlags; /*!< OR'ed value of _dsi_dpi_polarity_flag controls signal polarity. */
+ uint16_t hfp; /*!< Horizontal front porch, in dpi pixel clock. */
+ uint16_t hbp; /*!< Horizontal back porch, in dpi pixel clock. */
+ uint16_t hsw; /*!< Horizontal sync width, in dpi pixel clock. */
+ uint8_t vfp; /*!< Number of lines in vertical front porch. */
+ uint8_t vbp; /*!< Number of lines in vertical back porch. */
+ uint16_t panelHeight; /*!< Line number in vertical active area. */
+
+ uint8_t virtualChannel; /*!< Virtual channel. */
+} dsi_dpi_config_t;
+
+/*! @brief MIPI DSI D-PHY configuration. */
+typedef struct _dsi_dphy_config
+{
+ uint32_t txHsBitClk_Hz; /*!< The generated HS TX bit clock in Hz. */
+
+ uint8_t tClkPre_ByteClk; /*!< TLPX + TCLK-PREPARE + TCLK-ZERO + TCLK-PRE in byte clock.
+ Set how long the controller
+ will wait after enabling clock lane for HS before
+ enabling data lanes for HS. */
+ uint8_t tClkPost_ByteClk; /*!< TCLK-POST + T_CLK-TRAIL in byte clock. Set how long the controller
+ will wait before putting clock lane into LP mode after
+ data lanes detected in stop state. */
+ uint8_t tHsExit_ByteClk; /*!< THS-EXIT in byte clock. Set how long the controller
+ will wait after the clock lane has been put into LP
+ mode before enabling clock lane for HS again. */
+ uint32_t tWakeup_EscClk; /*!< Number of clk_esc clock periods to keep a clock
+ or data lane in Mark-1 state after exiting ULPS. */
+ uint8_t tHsPrepare_HalfEscClk; /*!< THS-PREPARE in clk_esc/2. Set how long
+ to drive the LP-00 state before HS transmissions,
+ available values are 2, 3, 4, 5. */
+ uint8_t tClkPrepare_HalfEscClk; /*!< TCLK-PREPARE in clk_esc/2. Set how long
+ to drive the LP-00 state before HS transmissions,
+ available values are 2, 3. */
+ uint8_t tHsZero_ByteClk; /*!< THS-ZERO in clk_byte. Set how long that controller
+ drives data lane HS-0 state before transmit
+ the Sync sequence. Available values are 6, 7, ..., 37. */
+ uint8_t tClkZero_ByteClk; /*!< TCLK-ZERO in clk_byte. Set how long that controller
+ drives clock lane HS-0 state before transmit
+ the Sync sequence. Available values are 3, 4, ..., 66. */
+ uint8_t tHsTrail_ByteClk; /*!< THS-TRAIL + 4*UI in clk_byte. Set the time
+ of the flipped differential state after last payload
+ data bit of HS transmission burst. Available values
+ are 0, 1, ..., 15. */
+ uint8_t tClkTrail_ByteClk; /*!< TCLK-TRAIL + 4*UI in clk_byte. Set the time
+ of the flipped differential state after last payload
+ data bit of HS transmission burst. Available values
+ are 0, 1, ..., 15. */
+} dsi_dphy_config_t;
+
+/*! @brief _dsi_apb_status Status of APB to packet interface. */
+enum
+{
+ kDSI_ApbNotIdle = (1UL << 0U), /*!< State machine not idle */
+ kDSI_ApbTxDone = (1UL << 1U), /*!< Tx packet done */
+ kDSI_ApbRxControl = (1UL << 2U), /*!< DPHY direction 0 - tx had control, 1 - rx has control */
+ kDSI_ApbTxOverflow = (1UL << 3U), /*!< TX fifo overflow */
+ kDSI_ApbTxUnderflow = (1UL << 4U), /*!< TX fifo underflow */
+ kDSI_ApbRxOverflow = (1UL << 5U), /*!< RX fifo overflow */
+ kDSI_ApbRxUnderflow = (1UL << 6U), /*!< RX fifo underflow */
+ kDSI_ApbRxHeaderReceived = (1UL << 7U), /*!< RX packet header has been received */
+ kDSI_ApbRxPacketReceived = (1UL << 8U), /*!< All RX packet payload data has been received */
+};
+
+/*! @brief _dsi_rx_error_status Host receive error status. */
+enum
+{
+ kDSI_RxErrorEccOneBit = (1UL << 0U), /*!< ECC single bit error detected. */
+ kDSI_RxErrorEccMultiBit = (1UL << 1U), /*!< ECC multi bit error detected. */
+ kDSI_RxErrorCrc = (1UL << 7U), /*!< CRC error detected. */
+ kDSI_RxErrorHtxTo = (1UL << 8U), /*!< High Speed forward TX timeout detected. */
+ kDSI_RxErrorLrxTo = (1UL << 9U), /*!< Reverse Low power data receive timeout detected. */
+ kDSI_RxErrorBtaTo = (1UL << 10U) /*!< BTA timeout detected. */
+};
+
+/*! @brief DSI host controller status (status_out) */
+enum _dsi_host_status
+{
+ kDSI_HostSoTError = (1UL << 0U), /*!< SoT error from peripheral error report. */
+ kDSI_HostSoTSyncError = (1UL << 1U), /*!< SoT Sync error from peripheral error report. */
+ kDSI_HostEoTSyncError = (1UL << 2U), /*!< EoT Sync error from peripheral error report. */
+ kDSI_HostEscEntryCmdError = (1UL << 3U), /*!< Escape Mode Entry Command Error from peripheral error report. */
+ kDSI_HostLpTxSyncError = (1UL << 4U), /*!< Low-power transmit Sync Error from peripheral error report. */
+ kDSI_HostPeriphToError = (1UL << 5U), /*!< Peripheral timeout error from peripheral error report. */
+ kDSI_HostFalseControlError = (1UL << 6U), /*!< False control error from peripheral error report. */
+ kDSI_HostContentionDetected = (1UL << 7U), /*!< Contention detected from peripheral error report. */
+ kDSI_HostEccErrorOneBit = (1UL << 8U), /*!< Single bit ECC error (corrected) from peripheral error report. */
+ kDSI_HostEccErrorMultiBit = (1UL << 9U), /*!< Multi bit ECC error (not corrected) from peripheral error report. */
+ kDSI_HostChecksumError = (1UL << 10U), /*!< Checksum error from peripheral error report. */
+ kDSI_HostInvalidDataType = (1UL << 11U), /*!< DSI data type not recognized. */
+ kDSI_HostInvalidVcId = (1UL << 12U), /*!< DSI VC ID invalid. */
+ kDSI_HostInvalidTxLength = (1UL << 13U), /*!< Invalid transmission length. */
+ kDSI_HostProtocalViolation = (1UL << 15U), /*!< DSI protocal violation. */
+ kDSI_HostResetTriggerReceived = (1UL << 16U), /*!< Reset trigger received. */
+ kDSI_HostTearTriggerReceived = (1UL << 17U), /*!< Tear effect trigger receive. */
+ kDSI_HostAckTriggerReceived = (1UL << 18U), /*!< Acknowledge trigger message received. */
+};
+
+/*! @brief _dsi_interrupt DSI interrupt. */
+enum
+{
+ kDSI_InterruptGroup1ApbNotIdle = (1UL << 0U), /*!< State machine not idle */
+ kDSI_InterruptGroup1ApbTxDone = (1UL << 1U), /*!< Tx packet done */
+ kDSI_InterruptGroup1ApbRxControl = (1UL << 2U), /*!< DPHY direction 0 - tx control, 1 - rx control */
+ kDSI_InterruptGroup1ApbTxOverflow = (1UL << 3U), /*!< TX fifo overflow */
+ kDSI_InterruptGroup1ApbTxUnderflow = (1UL << 4U), /*!< TX fifo underflow */
+ kDSI_InterruptGroup1ApbRxOverflow = (1UL << 5U), /*!< RX fifo overflow */
+ kDSI_InterruptGroup1ApbRxUnderflow = (1UL << 6U), /*!< RX fifo underflow */
+ kDSI_InterruptGroup1ApbRxHeaderReceived = (1UL << 7U), /*!< RX packet header has been received */
+ kDSI_InterruptGroup1ApbRxPacketReceived = (1UL << 8U), /*!< All RX packet payload data has been received */
+ kDSI_InterruptGroup1SoTError = (1UL << 9U), /*!< SoT error from peripheral error report. */
+ kDSI_InterruptGroup1SoTSyncError = (1UL << 10U), /*!< SoT Sync error from peripheral error report. */
+ kDSI_InterruptGroup1EoTSyncError = (1UL << 11U), /*!< EoT Sync error from peripheral error report. */
+ kDSI_InterruptGroup1EscEntryCmdError = (1UL << 12U), /*!< Escape Mode Entry Command Error
+ from peripheral error report. */
+ kDSI_InterruptGroup1LpTxSyncError = (1UL << 13U), /*!< Low-power transmit Sync Error from
+ peripheral error report. */
+ kDSI_InterruptGroup1PeriphToError = (1UL << 14U), /*!< Peripheral timeout error from
+ peripheral error report. */
+ kDSI_InterruptGroup1FalseControlError = (1UL << 15U), /*!< False control error from peripheral error report. */
+ kDSI_InterruptGroup1ContentionDetected = (1UL << 16U), /*!< Contention detected from peripheral error report. */
+ kDSI_InterruptGroup1EccErrorOneBit = (1UL << 17U), /*!< Single bit ECC error (corrected) from
+ peripheral error report. */
+ kDSI_InterruptGroup1EccErrorMultiBit = (1UL << 18U), /*!< Multi bit ECC error (not corrected) from
+ peripheral error report. */
+ kDSI_InterruptGroup1ChecksumError = (1UL << 19U), /*!< Checksum error from peripheral error report. */
+ kDSI_InterruptGroup1InvalidDataType = (1UL << 20U), /*!< DSI data type not recognized. */
+ kDSI_InterruptGroup1InvalidVcId = (1UL << 21U), /*!< DSI VC ID invalid. */
+ kDSI_InterruptGroup1InvalidTxLength = (1UL << 22U), /*!< Invalid transmission length. */
+ kDSI_InterruptGroup1ProtocalViolation = (1UL << 24U), /*!< DSI protocal violation. */
+ kDSI_InterruptGroup1ResetTriggerReceived = (1UL << 25U), /*!< Reset trigger received. */
+ kDSI_InterruptGroup1TearTriggerReceived = (1UL << 26U), /*!< Tear effect trigger receive. */
+ kDSI_InterruptGroup1AckTriggerReceived = (1UL << 27U), /*!< Acknowledge trigger message received. */
+ kDSI_InterruptGroup1HtxTo = (1UL << 29U), /*!< High speed TX timeout. */
+ kDSI_InterruptGroup1LrxTo = (1UL << 30U), /*!< Low power RX timeout. */
+ kDSI_InterruptGroup1BtaTo = (1UL << 31U), /*!< Host BTA timeout. */
+ kDSI_InterruptGroup2EccOneBit = (1UL << 0U), /*!< Sinle bit ECC error. */
+ kDSI_InterruptGroup2EccMultiBit = (1UL << 1U), /*!< Multi bit ECC error. */
+ kDSI_InterruptGroup2CrcError = (1UL << 2U), /*!< CRC error. */
+};
+
+/*! @brief DSI TX data type. */
+typedef enum _dsi_tx_data_type
+{
+ kDSI_TxDataVsyncStart = 0x01U, /*!< V Sync start. */
+ kDSI_TxDataVsyncEnd = 0x11U, /*!< V Sync end. */
+ kDSI_TxDataHsyncStart = 0x21U, /*!< H Sync start. */
+ kDSI_TxDataHsyncEnd = 0x31U, /*!< H Sync end. */
+ kDSI_TxDataEoTp = 0x08U, /*!< End of transmission packet. */
+ kDSI_TxDataCmOff = 0x02U, /*!< Color mode off. */
+ kDSI_TxDataCmOn = 0x12U, /*!< Color mode on. */
+ kDSI_TxDataShutDownPeriph = 0x22U, /*!< Shut down peripheral. */
+ kDSI_TxDataTurnOnPeriph = 0x32U, /*!< Turn on peripheral. */
+ kDSI_TxDataGenShortWrNoParam = 0x03U, /*!< Generic Short WRITE, no parameters. */
+ kDSI_TxDataGenShortWrOneParam = 0x13U, /*!< Generic Short WRITE, one parameter. */
+ kDSI_TxDataGenShortWrTwoParam = 0x23U, /*!< Generic Short WRITE, two parameter. */
+ kDSI_TxDataGenShortRdNoParam = 0x04U, /*!< Generic Short READ, no parameters. */
+ kDSI_TxDataGenShortRdOneParam = 0x14U, /*!< Generic Short READ, one parameter. */
+ kDSI_TxDataGenShortRdTwoParam = 0x24U, /*!< Generic Short READ, two parameter. */
+ kDSI_TxDataDcsShortWrNoParam = 0x05U, /*!< DCS Short WRITE, no parameters. */
+ kDSI_TxDataDcsShortWrOneParam = 0x15U, /*!< DCS Short WRITE, one parameter. */
+ kDSI_TxDataDcsShortRdNoParam = 0x06U, /*!< DCS Short READ, no parameters. */
+ kDSI_TxDataSetMaxReturnPktSize = 0x37U, /*!< Set the Maximum Return Packet Size. */
+
+ kDSI_TxDataNull = 0x09U, /*!< Null Packet, no data. */
+ kDSI_TxDataBlanking = 0x19U, /*!< Blanking Packet, no data. */
+ kDSI_TxDataGenLongWr = 0x29U, /*!< Generic long write. */
+ kDSI_TxDataDcsLongWr = 0x39U, /*!< DCS Long Write/write_LUT Command Packet. */
+ kDSI_TxDataLooselyPackedPixel20BitYCbCr = 0x0CU, /*!< Loosely Packed Pixel Stream, 20-bit YCbCr, 4:2:2 Format. */
+ kDSI_TxDataPackedPixel24BitYCbCr = 0x1CU, /*!< Packed Pixel Stream, 24-bit YCbCr, 4:2:2 Format. */
+ kDSI_TxDataPackedPixel16BitYCbCr = 0x2CU, /*!< Packed Pixel Stream, 16-bit YCbCr, 4:2:2 Format. */
+ kDSI_TxDataPackedPixel30BitRGB = 0x0DU, /*!< Packed Pixel Stream, 30-bit RGB, 10-10-10 Format. */
+ kDSI_TxDataPackedPixel36BitRGB = 0x1DU, /*!< Packed Pixel Stream, 36-bit RGB, 12-12-12 Format. */
+ kDSI_TxDataPackedPixel12BitYCrCb = 0x3DU, /*!< Packed Pixel Stream, 12-bit YCbCr, 4:2:0 Format. */
+ kDSI_TxDataPackedPixel16BitRGB = 0x0EU, /*!< Packed Pixel Stream, 16-bit RGB, 5-6-5 Format. */
+ kDSI_TxDataPackedPixel18BitRGB = 0x1EU, /*!< Packed Pixel Stream, 18-bit RGB, 6-6-6 Format. */
+ kDSI_TxDataLooselyPackedPixel18BitRGB = 0x2EU, /*!< Loosely Packed Pixel Stream, 18-bit RGB, 6-6-6 Format. */
+ kDSI_TxDataPackedPixel24BitRGB = 0x3EU, /*!< Packed Pixel Stream, 24-bit RGB, 8-8-8 Format. */
+} dsi_tx_data_type_t;
+
+/*! @brief DSI RX data type. */
+typedef enum _dsi_rx_data_type
+{
+ kDSI_RxDataAckAndErrorReport = 0x02U, /*!< Acknowledge and Error Report */
+ kDSI_RxDataEoTp = 0x08U, /*!< End of Transmission packet. */
+ kDSI_RxDataGenShortRdResponseOneByte = 0x11U, /*!< Generic Short READ Response, 1 byte returned. */
+ kDSI_RxDataGenShortRdResponseTwoByte = 0x12U, /*!< Generic Short READ Response, 2 byte returned. */
+ kDSI_RxDataGenLongRdResponse = 0x1AU, /*!< Generic Long READ Response. */
+ kDSI_RxDataDcsLongRdResponse = 0x1CU, /*!< DCS Long READ Response. */
+ kDSI_RxDataDcsShortRdResponseOneByte = 0x21U, /*!< DCS Short READ Response, 1 byte returned. */
+ kDSI_RxDataDcsShortRdResponseTwoByte = 0x22U, /*!< DCS Short READ Response, 2 byte returned. */
+} dsi_rx_data_type_t;
+
+/*! @brief _dsi_transfer_flags DSI transfer control flags. */
+enum
+{
+ kDSI_TransferUseHighSpeed = (1U << 0U), /*!< Use high speed mode or not. */
+ kDSI_TransferPerformBTA = (1U << 1U), /*!< Perform BTA or not. */
+};
+
+/*! @brief Structure for the data transfer. */
+typedef struct _dsi_transfer
+{
+ uint8_t virtualChannel; /*!< Virtual channel. */
+ dsi_tx_data_type_t txDataType; /*!< TX data type. */
+ uint8_t flags; /*!< Flags to control the transfer, see _dsi_transfer_flags. */
+ const uint8_t *txData; /*!< The TX data buffer. */
+ uint8_t *rxData; /*!< The TX data buffer. */
+ uint16_t txDataSize; /*!< Size of the TX data. */
+ uint16_t rxDataSize; /*!< Size of the RX data. */
+ bool sendDscCmd; /*!< If set to true, the DSC command is specified by @ref dscCmd, otherwise
+ the DSC command is included in the @ref txData. */
+ uint8_t dscCmd; /*!< The DSC command to send, only valid when @ref sendDscCmd is true. */
+} dsi_transfer_t;
+
+/*! @brief MIPI DSI transfer handle. */
+typedef struct _dsi_handle dsi_handle_t;
+
+/*!
+ * @brief MIPI DSI callback for finished transfer.
+ *
+ * When transfer finished, one of these status values will be passed to the user:
+ * - @ref kStatus_Success Data transfer finished with no error.
+ * - @ref kStatus_Timeout Transfer failed because of timeout.
+ * - @ref kStatus_DSI_RxDataError RX data error, user could use @ref DSI_GetRxErrorStatus
+ * to check the error details.
+ * - @ref kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
+ * @ref DSI_GetAndClearHostStatus to check the error report status.
+ * - @ref kStatus_Fail Transfer failed for other reasons.
+ */
+typedef void (*dsi_callback_t)(const MIPI_DSI_Type *base, dsi_handle_t *handle, status_t status, void *userData);
+
+/*! @brief MIPI DSI transfer handle structure */
+struct _dsi_handle
+{
+ volatile bool isBusy; /*!< MIPI DSI is busy with APB data transfer. */
+ dsi_transfer_t xfer; /*!< Transfer information. */
+ dsi_callback_t callback; /*!< DSI callback */
+ void *userData; /*!< Callback parameter */
+ const MIPI_DSI_Type *dsi; /*!< Pointer to MIPI DSI peripheral. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name MIPI_DSI host initialization.
+ * @{
+ */
+
+/*!
+ * @brief Initializes an MIPI DSI host with the user configuration.
+ *
+ * This function initializes the MIPI DSI host with the configuration, it should
+ * be called first before other MIPI DSI driver functions.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param config Pointer to a user-defined configuration structure.
+ */
+void DSI_Init(const MIPI_DSI_Type *base, const dsi_config_t *config);
+
+/*!
+ * @brief Deinitializes an MIPI DSI host.
+ *
+ * This function should be called after all bother MIPI DSI driver functions.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ */
+void DSI_Deinit(const MIPI_DSI_Type *base);
+
+/*!
+ * @brief Get the default configuration to initialize the MIPI DSI host.
+ *
+ * The default value is:
+ * @code
+ config->numLanes = 4;
+ config->enableNonContinuousHsClk = false;
+ config->enableTxUlps = false;
+ config->autoInsertEoTp = true;
+ config->numExtraEoTp = 0;
+ config->htxTo_ByteClk = 0;
+ config->lrxHostTo_ByteClk = 0;
+ config->btaTo_ByteClk = 0;
+ @endcode
+ *
+ * @param config Pointer to a user-defined configuration structure.
+ */
+void DSI_GetDefaultConfig(dsi_config_t *config);
+
+/*! @} */
+
+/*!
+ * @name DPI interface
+ * @{
+ */
+
+/*!
+ * @brief Configure the DPI interface core.
+ *
+ * This function sets the DPI interface configuration, it should be used in
+ * video mode.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param config Pointer to the DPI interface configuration.
+ * @param numLanes Lane number, should be same with the setting in @ref dsi_dpi_config_t.
+ * @param dpiPixelClkFreq_Hz The DPI pixel clock frequency in Hz.
+ * @param dsiHsBitClkFreq_Hz The DSI high speed bit clock frequency in Hz. It is
+ * the same with DPHY PLL output.
+ */
+void DSI_SetDpiConfig(const MIPI_DSI_Type *base,
+ const dsi_dpi_config_t *config,
+ uint8_t numLanes,
+ uint32_t dpiPixelClkFreq_Hz,
+ uint32_t dsiHsBitClkFreq_Hz);
+
+/*! @} */
+
+/*!
+ * @name D-PHY configuration.
+ * @{
+ */
+
+/*!
+ * @brief Initializes the D-PHY
+ *
+ * This function configures the D-PHY timing and setups the D-PHY PLL based on
+ * user configuration. The configuration structure could be got by the function
+ * @ref DSI_GetDphyDefaultConfig.
+ *
+ * For some platforms there is not dedicated D-PHY PLL, indicated by the macro
+ * FSL_FEATURE_MIPI_DSI_NO_DPHY_PLL. For these platforms, the @p refClkFreq_Hz
+ * is useless.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param config Pointer to the D-PHY configuration.
+ * @param refClkFreq_Hz The REFCLK frequency in Hz.
+ * @return The actual D-PHY PLL output frequency. If could not configure the
+ * PLL to the target frequency, the return value is 0.
+ */
+uint32_t DSI_InitDphy(const MIPI_DSI_Type *base, const dsi_dphy_config_t *config, uint32_t refClkFreq_Hz);
+
+/*!
+ * @brief Deinitializes the D-PHY
+ *
+ * Power down the D-PHY PLL and shut down D-PHY.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ */
+void DSI_DeinitDphy(const MIPI_DSI_Type *base);
+
+/*!
+ * @brief Get the default D-PHY configuration.
+ *
+ * Gets the default D-PHY configuration, the timing parameters are set according
+ * to D-PHY specification. User could use the configuration directly, or change
+ * some parameters according to the special device.
+ *
+ * @param config Pointer to the D-PHY configuration.
+ * @param txHsBitClk_Hz High speed bit clock in Hz.
+ * @param txEscClk_Hz Esc clock in Hz.
+ */
+void DSI_GetDphyDefaultConfig(dsi_dphy_config_t *config, uint32_t txHsBitClk_Hz, uint32_t txEscClk_Hz);
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enable the interrupts.
+ *
+ * The interrupts to enable are passed in as OR'ed mask value of _dsi_interrupt.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param intGroup1 Interrupts to enable in group 1.
+ * @param intGroup2 Interrupts to enable in group 2.
+ */
+static inline void DSI_EnableInterrupts(const MIPI_DSI_Type *base, uint32_t intGroup1, uint32_t intGroup2)
+{
+ base->apb->IRQ_MASK &= ~intGroup1;
+ base->apb->IRQ_MASK2 &= ~intGroup2;
+}
+
+/*!
+ * @brief Disable the interrupts.
+ *
+ * The interrupts to disable are passed in as OR'ed mask value of _dsi_interrupt.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param intGroup1 Interrupts to disable in group 1.
+ * @param intGroup2 Interrupts to disable in group 2.
+ */
+static inline void DSI_DisableInterrupts(const MIPI_DSI_Type *base, uint32_t intGroup1, uint32_t intGroup2)
+{
+ base->apb->IRQ_MASK |= intGroup1;
+ base->apb->IRQ_MASK2 |= intGroup2;
+}
+
+/*!
+ * @brief Get and clear the interrupt status.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param intGroup1 Group 1 interrupt status.
+ * @param intGroup2 Group 2 interrupt status.
+ */
+static inline void DSI_GetAndClearInterruptStatus(const MIPI_DSI_Type *base, uint32_t *intGroup1, uint32_t *intGroup2)
+{
+ *intGroup2 = base->apb->IRQ_STATUS2;
+ *intGroup1 = base->apb->IRQ_STATUS;
+}
+
+/*! @} */
+
+/*!
+ * @name MIPI DSI APB
+ * @{
+ */
+
+/*!
+ * @brief Configure the APB packet to send.
+ *
+ * This function configures the next APB packet transfer. After configuration,
+ * the packet transfer could be started with function @ref DSI_SendApbPacket.
+ * If the packet is long packet, Use @ref DSI_WriteApbTxPayload to fill the payload
+ * before start transfer.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param wordCount For long packet, this is the byte count of the payload.
+ * For short packet, this is (data1 << 8) | data0.
+ * @param virtualChannel Virtual channel.
+ * @param dataType The packet data type, (DI).
+ * @param flags The transfer control flags, see _dsi_transfer_flags.
+ */
+void DSI_SetApbPacketControl(
+ const MIPI_DSI_Type *base, uint16_t wordCount, uint8_t virtualChannel, dsi_tx_data_type_t dataType, uint8_t flags);
+
+/*!
+ * @brief Fill the long APB packet payload.
+ *
+ * Write the long packet payload to TX FIFO.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param payload Pointer to the payload.
+ * @param payloadSize Payload size in byte.
+ */
+void DSI_WriteApbTxPayload(const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize);
+
+/*!
+ * @brief Extended function to fill the payload to TX FIFO.
+ *
+ * Write the long packet payload to TX FIFO. This function could be used in two ways
+ *
+ * 1. Include the DSC command in parameter @p payload. In this case, the DSC command
+ * is the first byte of @p payload. The parameter @p sendDscCmd is set to false,
+ * the @p dscCmd is not used. This function is the same as @ref DSI_WriteApbTxPayload
+ * when used in this way.
+ *
+ * 2. The DSC command in not in parameter @p payload, but specified by parameter @p dscCmd.
+ * In this case, the parameter @p sendDscCmd is set to true, the @p dscCmd is the DSC
+ * command to send. The @p payload is sent after @p dscCmd.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param payload Pointer to the payload.
+ * @param payloadSize Payload size in byte.
+ * @param sendDscCmd If set to true, the DSC command is specified by @p dscCmd,
+ * otherwise the DSC command is included in the @p payload.
+ * @param dscCmd The DSC command to send, only used when @p sendDscCmd is true.
+ */
+void DSI_WriteApbTxPayloadExt(
+ const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize, bool sendDscCmd, uint8_t dscCmd);
+
+/*!
+ * @brief Read the long APB packet payload.
+ *
+ * Read the long packet payload from RX FIFO. This function reads directly but
+ * does not check the RX FIFO status. Upper layer should make sure there are
+ * available data.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param payload Pointer to the payload.
+ * @param payloadSize Payload size in byte.
+ */
+void DSI_ReadApbRxPayload(const MIPI_DSI_Type *base, uint8_t *payload, uint16_t payloadSize);
+
+/*!
+ * @brief Trigger the controller to send out APB packet.
+ *
+ * Send the packet set by @ref DSI_SetApbPacketControl.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ */
+static inline void DSI_SendApbPacket(const MIPI_DSI_Type *base)
+{
+ base->apb->SEND_PACKET = 0x1U;
+}
+
+/*!
+ * @brief Get the APB status.
+ *
+ * The return value is OR'ed value of _dsi_apb_status.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @return The APB status.
+ */
+static inline uint32_t DSI_GetApbStatus(const MIPI_DSI_Type *base)
+{
+ return base->apb->PKT_STATUS;
+}
+
+/*!
+ * @brief Get the error status during data transfer.
+ *
+ * The return value is OR'ed value of _dsi_rx_error_status.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @return The error status.
+ */
+static inline uint32_t DSI_GetRxErrorStatus(const MIPI_DSI_Type *base)
+{
+ return base->host->RX_ERROR_STATUS;
+}
+
+/*!
+ * @brief Get the one-bit RX ECC error position.
+ *
+ * When one-bit ECC RX error detected using @ref DSI_GetRxErrorStatus, this
+ * function could be used to get the error bit position.
+ *
+ * @code
+ uint8_t eccErrorPos;
+ uint32_t rxErrorStatus = DSI_GetRxErrorStatus(MIPI_DSI);
+ if (kDSI_RxErrorEccOneBit & rxErrorStatus)
+ {
+ eccErrorPos = DSI_GetEccRxErrorPosition(rxErrorStatus);
+ }
+ @endcode
+ *
+ * @param rxErrorStatus The error status returned by @ref DSI_GetRxErrorStatus.
+ * @return The 1-bit ECC error position.
+ */
+static inline uint8_t DSI_GetEccRxErrorPosition(uint32_t rxErrorStatus)
+{
+ return (uint8_t)((rxErrorStatus >> 2U) & 0x1FU);
+}
+
+/*!
+ * @brief Get and clear the DSI host status.
+ *
+ * The host status are returned as mask value of @ref _dsi_host_status.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @return The DSI host status.
+ */
+static inline uint32_t DSI_GetAndClearHostStatus(const MIPI_DSI_Type *base)
+{
+ return base->host->CFG_STATUS_OUT;
+}
+
+/*!
+ * @brief Get the RX packet header.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @return The RX packet header.
+ */
+static inline uint32_t DSI_GetRxPacketHeader(const MIPI_DSI_Type *base)
+{
+ return base->apb->PKT_RX_PKT_HEADER;
+}
+
+/*!
+ * @brief Extract the RX packet type from the packet header.
+ *
+ * Extract the RX packet type from the packet header get by @ref DSI_GetRxPacketHeader.
+ *
+ * @param rxPktHeader The RX packet header get by @ref DSI_GetRxPacketHeader.
+ * @return The RX packet type.
+ */
+static inline dsi_rx_data_type_t DSI_GetRxPacketType(uint32_t rxPktHeader)
+{
+ return (dsi_rx_data_type_t)(uint8_t)((rxPktHeader >> 16U) & 0x3FU);
+}
+
+/*!
+ * @brief Extract the RX packet word count from the packet header.
+ *
+ * Extract the RX packet word count from the packet header get by @ref DSI_GetRxPacketHeader.
+ *
+ * @param rxPktHeader The RX packet header get by @ref DSI_GetRxPacketHeader.
+ * @return For long packet, return the payload word count (byte). For short packet,
+ * return the (data0 << 8) | data1.
+ */
+static inline uint16_t DSI_GetRxPacketWordCount(uint32_t rxPktHeader)
+{
+ return (uint16_t)(rxPktHeader & 0xFFFFU);
+}
+
+/*!
+ * @brief Extract the RX packet virtual channel from the packet header.
+ *
+ * Extract the RX packet virtual channel from the packet header get by @ref DSI_GetRxPacketHeader.
+ *
+ * @param rxPktHeader The RX packet header get by @ref DSI_GetRxPacketHeader.
+ * @return The virtual channel.
+ */
+static inline uint8_t DSI_GetRxPacketVirtualChannel(uint32_t rxPktHeader)
+{
+ return (uint8_t)((rxPktHeader >> 22U) & 0x3U);
+}
+
+/*!
+ * @brief APB data transfer using blocking method.
+ *
+ * Perform APB data transfer using blocking method. This function waits until all
+ * data send or received, or timeout happens.
+ *
+ * When using this API to read data, the actually read data count could be got
+ * from xfer->rxDataSize.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param xfer Pointer to the transfer structure.
+ * @retval kStatus_Success Data transfer finished with no error.
+ * @retval kStatus_Timeout Transfer failed because of timeout.
+ * @retval kStatus_DSI_RxDataError RX data error, user could use @ref DSI_GetRxErrorStatus
+ * to check the error details.
+ * @retval kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
+ * @ref DSI_GetAndClearHostStatus to check the error report status.
+ * @retval kStatus_DSI_NotSupported Transfer format not supported.
+ * @retval kStatus_DSI_Fail Transfer failed for other reasons.
+ */
+status_t DSI_TransferBlocking(const MIPI_DSI_Type *base, dsi_transfer_t *xfer);
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Create the MIPI DSI handle.
+ *
+ * This function initializes the MIPI DSI handle which can be used for other transactional APIs.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param handle Handle pointer.
+ * @param callback Callback function.
+ * @param userData User data.
+ */
+status_t DSI_TransferCreateHandle(const MIPI_DSI_Type *base,
+ dsi_handle_t *handle,
+ dsi_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief APB data transfer using interrupt method.
+ *
+ * Perform APB data transfer using interrupt method, when transfer finished,
+ * upper layer could be informed through callback function.
+ *
+ * When using this API to read data, the actually read data count could be got
+ * from handle->xfer->rxDataSize after read finished.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param handle pointer to dsi_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the transfer structure.
+ *
+ * @retval kStatus_Success Data transfer started successfully.
+ * @retval kStatus_DSI_Busy Failed to start transfer because DSI is busy with pervious transfer.
+ * @retval kStatus_DSI_NotSupported Transfer format not supported.
+ */
+status_t DSI_TransferNonBlocking(const MIPI_DSI_Type *base, dsi_handle_t *handle, dsi_transfer_t *xfer);
+
+/*!
+ * @brief Abort current APB data transfer.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferAbort(const MIPI_DSI_Type *base, dsi_handle_t *handle);
+
+/*!
+ * @brief Interrupt handler for the DSI.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferHandleIRQ(const MIPI_DSI_Type *base, dsi_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @} */
+
+#endif /* _FSL_MIPI_DSI_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.c b/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.c
new file mode 100644
index 0000000000..40b8dfd0f1
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_mu.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mu"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to mu clocks for each instance. */
+static const clock_ip_name_t s_muClocks[] = MU_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointers to mu bases for each instance. */
+static MU_Type *const s_muBases[] = MU_BASE_PTRS;
+
+/******************************************************************************
+ * Code
+ *****************************************************************************/
+static uint32_t MU_GetInstance(MU_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < (sizeof(s_muBases) / sizeof(s_muBases[0])); instance++)
+ {
+ if (s_muBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < (sizeof(s_muBases) / sizeof(s_muBases[0])));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the MU module.
+ *
+ * This function enables the MU clock only.
+ *
+ * param base MU peripheral base address.
+ */
+void MU_Init(MU_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ (void)CLOCK_EnableClock(s_muClocks[MU_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief De-initializes the MU module.
+ *
+ * This function disables the MU clock only.
+ *
+ * param base MU peripheral base address.
+ */
+void MU_Deinit(MU_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ (void)CLOCK_DisableClock(s_muClocks[MU_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Blocks to send a message.
+ *
+ * This function waits until the TX register is empty and sends the message.
+ *
+ * param base MU peripheral base address.
+ * param regIndex TX register index.
+ * param msg Message to send.
+ */
+void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg)
+{
+ assert(regIndex < MU_TR_COUNT);
+
+ /* Wait TX register to be empty. */
+ while (0U == (base->SR & (((uint32_t)kMU_Tx0EmptyFlag) >> regIndex)))
+ {
+ ; /* Intentional empty while*/
+ }
+
+ base->TR[regIndex] = msg;
+}
+
+/*!
+ * brief Blocks to receive a message.
+ *
+ * This function waits until the RX register is full and receives the message.
+ *
+ * param base MU peripheral base address.
+ * param regIndex RX register index.
+ * return The received message.
+ */
+uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex)
+{
+ assert(regIndex < MU_TR_COUNT);
+
+ /* Wait RX register to be full. */
+ while (0U == (base->SR & (((uint32_t)kMU_Rx0FullFlag) >> regIndex)))
+ {
+ ; /* Intentional empty while*/
+ }
+
+ return base->RR[regIndex];
+}
+
+/*!
+ * brief Blocks setting the 3-bit MU flags reflect on the other MU side.
+ *
+ * This function blocks setting the 3-bit MU flags. Every time the 3-bit MU flags are changed,
+ * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are
+ * updating to the other side. After the 3-bit MU flags are updated, the status flag
+ * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period,
+ * the flags cannot be changed. This function waits for the MU status flag
+ * \c kMU_FlagsUpdatingFlag cleared and sets the 3-bit MU flags.
+ *
+ * param base MU peripheral base address.
+ * param flags The 3-bit MU flags to set.
+ */
+void MU_SetFlags(MU_Type *base, uint32_t flags)
+{
+ /* Wait for update finished. */
+ while (0U != (base->SR & ((uint32_t)MU_SR_FUP_MASK)))
+ {
+ ; /* Intentional empty while*/
+ }
+
+ MU_SetFlagsNonBlocking(base, flags);
+}
+
+/*!
+ * brief Triggers interrupts to the other core.
+ *
+ * This function triggers the specific interrupts to the other core. The interrupts
+ * to trigger are passed in as bit mask. See \ref _mu_interrupt_trigger.
+ * The MU should not trigger an interrupt to the other core when the previous interrupt
+ * has not been processed by the other core. This function checks whether the
+ * previous interrupts have been processed. If not, it returns an error.
+ *
+ * code
+ * if (kStatus_Success != MU_TriggerInterrupts(base, kMU_GenInt0InterruptTrigger | kMU_GenInt2InterruptTrigger))
+ * {
+ * Previous general purpose interrupt 0 or general purpose interrupt 2
+ * has not been processed by the other core.
+ * }
+ * endcode
+ *
+ * param base MU peripheral base address.
+ * param mask Bit mask of the interrupts to trigger. See _mu_interrupt_trigger.
+ * retval kStatus_Success Interrupts have been triggered successfully.
+ * retval kStatus_Fail Previous interrupts have not been accepted.
+ */
+status_t MU_TriggerInterrupts(MU_Type *base, uint32_t mask)
+{
+ status_t status = kStatus_Success;
+ uint32_t reg = base->CR;
+
+ /* Previous interrupt has been accepted. */
+ if (0U == (reg & mask))
+ {
+ /* All interrupts have been accepted, trigger now. */
+ reg = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | mask;
+ base->CR = reg;
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if !(defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
+/*!
+ * brief Boots the core at B side.
+ *
+ * This function sets the B side core's boot configuration and releases the
+ * core from reset.
+ *
+ * param base MU peripheral base address.
+ * param mode Core B boot mode.
+ * note Only MU side A can use this function.
+ */
+void MU_BootCoreB(MU_Type *base, mu_core_boot_mode_t mode)
+{
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ /* Clean the reset de-assert pending flag. */
+ base->SR = MU_SR_RDIP_MASK;
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
+ uint32_t reg = base->CCR;
+
+ reg = (reg & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK)) | MU_CCR_BOOT(mode);
+
+ base->CCR = reg;
+#else
+ uint32_t reg = base->CR;
+
+ reg = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_HR_MASK | MU_CR_RSTH_MASK | MU_CR_BBOOT_MASK)) |
+ MU_CR_BBOOT(mode);
+
+ base->CR = reg;
+#endif
+}
+
+/*!
+ * brief Boots the other core.
+ *
+ * This function boots the other core with a boot configuration.
+ *
+ * param base MU peripheral base address.
+ * param mode The other core boot mode.
+ */
+void MU_BootOtherCore(MU_Type *base, mu_core_boot_mode_t mode)
+{
+ /*
+ * MU_BootOtherCore and MU_BootCoreB are the same, MU_BootCoreB is kept
+ * for compatible with older platforms.
+ */
+ MU_BootCoreB(base, mode);
+}
+#endif /* FSL_FEATURE_MU_NO_RSTH */
+
+#if !(defined(FSL_FEATURE_MU_NO_HR) && FSL_FEATURE_MU_NO_HR)
+#if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
+/*!
+ * brief Hardware reset the other core.
+ *
+ * This function resets the other core, the other core could mask the
+ * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset
+ * mask feature is only available for some platforms.
+ * This function could be used together with MU_BootOtherCore to control the
+ * other core reset workflow.
+ *
+ * Example 1: Reset the other core, and no hold reset
+ * code
+ * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
+ * endcode
+ * In this example, the core at MU side B will reset with the specified boot mode.
+ *
+ * Example 2: Reset the other core and hold it, then boot the other core later.
+ * code
+ * Here the other core enters reset, and the reset is hold
+ * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
+ * Current core boot the other core when necessary.
+ * MU_BootOtherCore(MU_A, bootMode);
+ * endcode
+ *
+ * param base MU peripheral base address.
+ * param waitReset Wait the other core enters reset.
+ * - true: Wait until the other core enters reset, if the other
+ * core has masked the hardware reset, then this function will
+ * be blocked.
+ * - false: Don't wait the reset.
+ * param holdReset Hold the other core reset or not.
+ * - true: Hold the other core in reset, this function returns
+ * directly when the other core enters reset.
+ * - false: Don't hold the other core in reset, this function
+ * waits until the other core out of reset.
+ * param bootMode Boot mode of the other core, if p holdReset is true, this
+ * parameter is useless.
+ */
+void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode)
+{
+#if (defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
+ /* If MU does not support hold reset, then the parameter must be false. */
+ assert(false == holdReset);
+#endif
+ uint32_t ccr = base->CCR & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK);
+
+ ccr |= MU_CCR_BOOT(bootMode);
+
+ if (holdReset)
+ {
+ ccr |= MU_CCR_RSTH_MASK;
+ }
+
+ /* Clean the reset assert pending flag. */
+ base->SR = (MU_SR_RAIP_MASK | MU_SR_RDIP_MASK);
+
+ /* Set CCR[HR] to trigger hardware reset. */
+ base->CCR = ccr | MU_CCR_HR_MASK;
+
+ /* If wait the other core enters reset. */
+ if (waitReset)
+ {
+ /* Wait for the other core go to reset. */
+ while (0U == (base->SR & MU_SR_RAIP_MASK))
+ {
+ ; /* Intentional empty while*/
+ }
+
+ if (!holdReset)
+ {
+ /* Clear CCR[HR]. */
+ base->CCR = ccr;
+
+ /* Wait for the other core out of reset. */
+ while (0U == (base->SR & MU_SR_RDIP_MASK))
+ {
+ ; /* Intentional empty while*/
+ }
+ }
+ }
+}
+#else /* FSL_FEATURE_MU_HAS_CCR */
+/*!
+ * brief Hardware reset the other core.
+ *
+ * This function resets the other core, the other core could mask the
+ * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset
+ * mask feature is only available for some platforms.
+ * This function could be used together with MU_BootOtherCore to control the
+ * other core reset workflow.
+ *
+ * Example 1: Reset the other core, and no hold reset
+ * code
+ * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
+ * endcode
+ * In this example, the core at MU side B will reset with the specified boot mode.
+ *
+ * Example 2: Reset the other core and hold it, then boot the other core later.
+ * code
+ * Here the other core enters reset, and the reset is hold
+ * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
+ * Current core boot the other core when necessary.
+ * MU_BootOtherCore(MU_A, bootMode);
+ * endcode
+ *
+ * param base MU peripheral base address.
+ * param waitReset Wait the other core enters reset.
+ * - true: Wait until the other core enters reset, if the other
+ * core has masked the hardware reset, then this function will
+ * be blocked.
+ * - false: Don't wait the reset.
+ * param holdReset Hold the other core reset or not.
+ * - true: Hold the other core in reset, this function returns
+ * directly when the other core enters reset.
+ * - false: Don't hold the other core in reset, this function
+ * waits until the other core out of reset.
+ * param bootMode Boot mode of the other core, if p holdReset is true, this
+ * parameter is useless.
+ */
+void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode)
+{
+#if (defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
+ /* If MU does not support hold reset, then the parameter must be false. */
+ assert(false == holdReset);
+#endif
+ uint32_t resetFlag = 0;
+
+ uint32_t cr = base->CR & ~(MU_CR_HR_MASK | MU_CR_RSTH_MASK | MU_CR_BOOT_MASK | MU_CR_GIRn_MASK | MU_CR_NMI_MASK);
+
+ cr |= MU_CR_BOOT(bootMode);
+
+ if (holdReset)
+ {
+ cr |= MU_CR_RSTH_MASK;
+ }
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ resetFlag |= MU_SR_RAIP_MASK;
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ resetFlag |= MU_SR_RDIP_MASK;
+#endif
+ /* Clean the reset assert pending flag. */
+ base->SR = resetFlag;
+
+ /* Set CR[HR] to trigger hardware reset. */
+ base->CR = cr | MU_CR_HR_MASK;
+
+ /* If wait the other core enters reset. */
+ if (waitReset)
+ {
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ /* Wait for the other core go to reset. */
+ while (0U == (base->SR & MU_SR_RAIP_MASK))
+ {
+ ; /* Intentional empty while*/
+ }
+#endif
+
+ if (!holdReset)
+ {
+ /* Clear CR[HR]. */
+ base->CR = cr;
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ /* Wait for the other core out of reset. */
+ while (0U == (base->SR & MU_SR_RDIP_MASK))
+ {
+ ; /* Intentional empty while*/
+ }
+#endif
+ }
+ }
+}
+#endif /* FSL_FEATURE_MU_HAS_CCR */
+#endif /* FSL_FEATURE_MU_NO_HR */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.h b/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.h
new file mode 100644
index 0000000000..5fed306c84
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mu/fsl_mu.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_MU_H_
+#define _FSL_MU_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup mu
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/* Compatibility Macros */
+#ifndef MU_CR_NMI_MASK
+#define MU_CR_NMI_MASK 0U
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_INT) && FSL_FEATURE_MU_HAS_RESET_INT)
+
+#ifndef FSL_FEATURE_MU_HAS_RESET_ASSERT_INT
+#define FSL_FEATURE_MU_HAS_RESET_ASSERT_INT 1
+#endif
+
+#ifndef FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT
+#define FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT 1
+#endif
+
+#endif /* FSL_FEATURE_MU_HAS_RESET_INT */
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief MU driver version. */
+#define FSL_MU_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+
+/*!
+ * @brief MU status flags.
+ */
+enum _mu_status_flags
+{
+ kMU_Tx0EmptyFlag = (1U << (MU_SR_TEn_SHIFT + 3U)), /*!< TX0 empty. */
+ kMU_Tx1EmptyFlag = (1U << (MU_SR_TEn_SHIFT + 2U)), /*!< TX1 empty. */
+ kMU_Tx2EmptyFlag = (1U << (MU_SR_TEn_SHIFT + 1U)), /*!< TX2 empty. */
+ kMU_Tx3EmptyFlag = (1U << (MU_SR_TEn_SHIFT + 0U)), /*!< TX3 empty. */
+
+ kMU_Rx0FullFlag = (1U << (MU_SR_RFn_SHIFT + 3U)), /*!< RX0 full. */
+ kMU_Rx1FullFlag = (1U << (MU_SR_RFn_SHIFT + 2U)), /*!< RX1 full. */
+ kMU_Rx2FullFlag = (1U << (MU_SR_RFn_SHIFT + 1U)), /*!< RX2 full. */
+ kMU_Rx3FullFlag = (1U << (MU_SR_RFn_SHIFT + 0U)), /*!< RX3 full. */
+
+ kMU_GenInt0Flag = (1U << (MU_SR_GIPn_SHIFT + 3U)), /*!< General purpose interrupt 0 pending. */
+ kMU_GenInt1Flag = (1U << (MU_SR_GIPn_SHIFT + 2U)), /*!< General purpose interrupt 1 pending. */
+ kMU_GenInt2Flag = (1U << (MU_SR_GIPn_SHIFT + 1U)), /*!< General purpose interrupt 2 pending. */
+ kMU_GenInt3Flag = (1U << (MU_SR_GIPn_SHIFT + 0U)), /*!< General purpose interrupt 3 pending. */
+
+ kMU_EventPendingFlag = MU_SR_EP_MASK, /*!< MU event pending. */
+ kMU_FlagsUpdatingFlag = MU_SR_FUP_MASK, /*!< MU flags update is on-going. */
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ kMU_ResetAssertInterruptFlag = MU_SR_RAIP_MASK, /*!< The other core reset assert interrupt pending. */
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT)
+ kMU_ResetDeassertInterruptFlag = MU_SR_RDIP_MASK, /*!< The other core reset de-assert interrupt pending. */
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_SR_RS) && FSL_FEATURE_MU_HAS_SR_RS)
+ kMU_OtherSideInResetFlag = MU_SR_RS_MASK, /*!< The other side is in reset. */
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_SR_MURIP) && FSL_FEATURE_MU_HAS_SR_MURIP)
+ kMU_MuResetInterruptFlag = MU_SR_MURIP_MASK, /*!< The other side initializes MU reset. */
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_SR_HRIP) && FSL_FEATURE_MU_HAS_SR_HRIP)
+ kMU_HardwareResetInterruptFlag = MU_SR_HRIP_MASK, /*!< Current side has been hardware reset by the other side. */
+#endif
+};
+
+/*!
+ * @brief MU interrupt source to enable.
+ */
+enum _mu_interrupt_enable
+{
+ kMU_Tx0EmptyInterruptEnable = (1U << (MU_CR_TIEn_SHIFT + 3U)), /*!< TX0 empty. */
+ kMU_Tx1EmptyInterruptEnable = (1U << (MU_CR_TIEn_SHIFT + 2U)), /*!< TX1 empty. */
+ kMU_Tx2EmptyInterruptEnable = (1U << (MU_CR_TIEn_SHIFT + 1U)), /*!< TX2 empty. */
+ kMU_Tx3EmptyInterruptEnable = (1U << (MU_CR_TIEn_SHIFT + 0U)), /*!< TX3 empty. */
+
+ kMU_Rx0FullInterruptEnable = (1U << (MU_CR_RIEn_SHIFT + 3U)), /*!< RX0 full. */
+ kMU_Rx1FullInterruptEnable = (1U << (MU_CR_RIEn_SHIFT + 2U)), /*!< RX1 full. */
+ kMU_Rx2FullInterruptEnable = (1U << (MU_CR_RIEn_SHIFT + 1U)), /*!< RX2 full. */
+ kMU_Rx3FullInterruptEnable = (1U << (MU_CR_RIEn_SHIFT + 0U)), /*!< RX3 full. */
+
+ kMU_GenInt0InterruptEnable = (int)(1U << (MU_CR_GIEn_SHIFT + 3U)), /*!< General purpose interrupt 0. */
+ kMU_GenInt1InterruptEnable = (1U << (MU_CR_GIEn_SHIFT + 2U)), /*!< General purpose interrupt 1. */
+ kMU_GenInt2InterruptEnable = (1U << (MU_CR_GIEn_SHIFT + 1U)), /*!< General purpose interrupt 2. */
+ kMU_GenInt3InterruptEnable = (1U << (MU_CR_GIEn_SHIFT + 0U)), /*!< General purpose interrupt 3. */
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ kMU_ResetAssertInterruptEnable = MU_CR_RAIE_MASK, /*!< The other core reset assert interrupt. */
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ kMU_ResetDeassertInterruptEnable = MU_CR_RDIE_MASK, /*!< The other core reset de-assert interrupt. */
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_SR_MURIP) && FSL_FEATURE_MU_HAS_SR_MURIP)
+ kMU_MuResetInterruptEnable = MU_CR_MURIE_MASK, /*!< The other side initializes MU reset. The interrupt
+ is ORed with the general purpose interrupt 3. The
+ general purpose interrupt 3 is issued when the other side
+ set the MU reset and this interrupt is enabled. */
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_SR_HRIP) && FSL_FEATURE_MU_HAS_SR_HRIP)
+ kMU_HardwareResetInterruptEnable = MU_CR_HRIE_MASK, /*!< Current side has been hardware reset by the other side. */
+#endif
+};
+
+/*!
+ * @brief MU interrupt that could be triggered to the other core.
+ */
+enum _mu_interrupt_trigger
+{
+#if !(defined(FSL_FEATURE_MU_NO_NMI) && FSL_FEATURE_MU_NO_NMI)
+ kMU_NmiInterruptTrigger = MU_CR_NMI_MASK, /*!< NMI interrupt. */
+#endif
+ kMU_GenInt0InterruptTrigger = (1U << (MU_CR_GIRn_SHIFT + 3U)), /*!< General purpose interrupt 0. */
+ kMU_GenInt1InterruptTrigger = (1U << (MU_CR_GIRn_SHIFT + 2U)), /*!< General purpose interrupt 1. */
+ kMU_GenInt2InterruptTrigger = (1U << (MU_CR_GIRn_SHIFT + 1U)), /*!< General purpose interrupt 2. */
+ kMU_GenInt3InterruptTrigger = (1U << (MU_CR_GIRn_SHIFT + 0U)) /*!< General purpose interrupt 3. */
+};
+
+/*!
+ * @brief MU message register.
+ */
+typedef enum _mu_msg_reg_index
+{
+ kMU_MsgReg0 = 0,
+ kMU_MsgReg1,
+ kMU_MsgReg2,
+ kMU_MsgReg3,
+} mu_msg_reg_index_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name MU initialization.
+ * @{
+ */
+/*!
+ * @brief Initializes the MU module.
+ *
+ * This function enables the MU clock only.
+ *
+ * @param base MU peripheral base address.
+ */
+void MU_Init(MU_Type *base);
+
+/*!
+ * @brief De-initializes the MU module.
+ *
+ * This function disables the MU clock only.
+ *
+ * @param base MU peripheral base address.
+ */
+void MU_Deinit(MU_Type *base);
+
+/* @} */
+
+/*!
+ * @name MU Message
+ * @{
+ */
+
+/*!
+ * @brief Writes a message to the TX register.
+ *
+ * This function writes a message to the specific TX register. It does not check
+ * whether the TX register is empty or not. The upper layer should make sure the TX
+ * register is empty before calling this function. This function can be used
+ * in ISR for better performance.
+ *
+ * @code
+ * while (!(kMU_Tx0EmptyFlag & MU_GetStatusFlags(base))) { } Wait for TX0 register empty.
+ * MU_SendMsgNonBlocking(base, kMU_MsgReg0, MSG_VAL); Write message to the TX0 register.
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param regIndex TX register index, see @ref mu_msg_reg_index_t.
+ * @param msg Message to send.
+ */
+static inline void MU_SendMsgNonBlocking(MU_Type *base, uint32_t regIndex, uint32_t msg)
+{
+ assert(regIndex < MU_TR_COUNT);
+
+ base->TR[regIndex] = msg;
+}
+
+/*!
+ * @brief Blocks to send a message.
+ *
+ * This function waits until the TX register is empty and sends the message.
+ *
+ * @param base MU peripheral base address.
+ * @param regIndex MU message register, see @ref mu_msg_reg_index_t
+ * @param msg Message to send.
+ */
+void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg);
+
+/*!
+ * @brief Reads a message from the RX register.
+ *
+ * This function reads a message from the specific RX register. It does not check
+ * whether the RX register is full or not. The upper layer should make sure the RX
+ * register is full before calling this function. This function can be used
+ * in ISR for better performance.
+ *
+ * @code
+ * uint32_t msg;
+ * while (!(kMU_Rx0FullFlag & MU_GetStatusFlags(base)))
+ * {
+ * } Wait for the RX0 register full.
+ *
+ * msg = MU_ReceiveMsgNonBlocking(base, kMU_MsgReg0); Read message from RX0 register.
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param RX register index, see @ref mu_msg_reg_index_t.
+ * @return The received message.
+ */
+static inline uint32_t MU_ReceiveMsgNonBlocking(MU_Type *base, uint32_t regIndex)
+{
+ assert(regIndex < MU_TR_COUNT);
+
+ return base->RR[regIndex];
+}
+
+/*!
+ * @brief Blocks to receive a message.
+ *
+ * This function waits until the RX register is full and receives the message.
+ *
+ * @param base MU peripheral base address.
+ * @param regIndex MU message register, see @ref mu_msg_reg_index_t
+ * @return The received message.
+ */
+uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex);
+
+/* @} */
+
+/*!
+ * @name MU Flags
+ * @{
+ */
+
+/*!
+ * @brief Sets the 3-bit MU flags reflect on the other MU side.
+ *
+ * This function sets the 3-bit MU flags directly. Every time the 3-bit MU flags are changed,
+ * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are
+ * updating to the other side. After the 3-bit MU flags are updated, the status flag
+ * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period,
+ * the flags cannot be changed. The upper layer should make sure the status flag
+ * \c kMU_FlagsUpdatingFlag is cleared before calling this function.
+ *
+ * @code
+ * while (kMU_FlagsUpdatingFlag & MU_GetStatusFlags(base))
+ * {
+ * } Wait for previous MU flags updating.
+ *
+ * MU_SetFlagsNonBlocking(base, 0U); Set the mU flags.
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param flags The 3-bit MU flags to set.
+ */
+static inline void MU_SetFlagsNonBlocking(MU_Type *base, uint32_t flags)
+{
+ uint32_t reg = base->CR;
+ reg = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_Fn_MASK)) | MU_CR_Fn(flags);
+ base->CR = reg;
+}
+
+/*!
+ * @brief Blocks setting the 3-bit MU flags reflect on the other MU side.
+ *
+ * This function blocks setting the 3-bit MU flags. Every time the 3-bit MU flags are changed,
+ * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are
+ * updating to the other side. After the 3-bit MU flags are updated, the status flag
+ * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period,
+ * the flags cannot be changed. This function waits for the MU status flag
+ * \c kMU_FlagsUpdatingFlag cleared and sets the 3-bit MU flags.
+ *
+ * @param base MU peripheral base address.
+ * @param flags The 3-bit MU flags to set.
+ */
+void MU_SetFlags(MU_Type *base, uint32_t flags);
+
+/*!
+ * @brief Gets the current value of the 3-bit MU flags set by the other side.
+ *
+ * This function gets the current 3-bit MU flags on the current side.
+ *
+ * @param base MU peripheral base address.
+ * @return flags Current value of the 3-bit flags.
+ */
+static inline uint32_t MU_GetFlags(MU_Type *base)
+{
+ return (base->SR & MU_SR_Fn_MASK) >> MU_SR_Fn_SHIFT;
+}
+
+/* @} */
+
+/*!
+ * @name Status and Interrupt.
+ * @{
+ */
+
+/*!
+ * @brief Gets the MU status flags.
+ *
+ * This function returns the bit mask of the MU status flags. See _mu_status_flags.
+ *
+ * @code
+ * uint32_t flags;
+ * flags = MU_GetStatusFlags(base); Get all status flags.
+ * if (kMU_Tx0EmptyFlag & flags)
+ * {
+ * The TX0 register is empty. Message can be sent.
+ * MU_SendMsgNonBlocking(base, kMU_MsgReg0, MSG0_VAL);
+ * }
+ * if (kMU_Tx1EmptyFlag & flags)
+ * {
+ * The TX1 register is empty. Message can be sent.
+ * MU_SendMsgNonBlocking(base, kMU_MsgReg1, MSG1_VAL);
+ * }
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @return Bit mask of the MU status flags, see _mu_status_flags.
+ */
+static inline uint32_t MU_GetStatusFlags(MU_Type *base)
+{
+ return (base->SR & (MU_SR_TEn_MASK | MU_SR_RFn_MASK | MU_SR_GIPn_MASK | MU_SR_EP_MASK | MU_SR_FUP_MASK
+#if (defined(FSL_FEATURE_MU_HAS_SR_RS) && FSL_FEATURE_MU_HAS_SR_RS)
+ | MU_SR_RS_MASK
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ | MU_SR_RAIP_MASK
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ | MU_SR_RDIP_MASK
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_SR_MURIP) && FSL_FEATURE_MU_HAS_SR_MURIP)
+ | MU_SR_MURIP_MASK
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_SR_HRIP) && FSL_FEATURE_MU_HAS_SR_HRIP)
+ | MU_SR_HRIP_MASK
+#endif
+ ));
+}
+
+/*!
+ * @brief Gets the MU IRQ pending status.
+ *
+ * This function returns the bit mask of the pending MU IRQs.
+ *
+ * @param base MU peripheral base address.
+ * @return Bit mask of the MU IRQs pending.
+ */
+static inline uint32_t MU_GetInterruptsPending(MU_Type *base)
+{
+ uint32_t irqMask = base->CR & (MU_CR_GIEn_MASK | MU_CR_TIEn_MASK | MU_CR_RIEn_MASK);
+ return (base->SR & irqMask);
+}
+
+/*!
+ * @brief Clears the specific MU status flags.
+ *
+ * This function clears the specific MU status flags. The flags to clear should
+ * be passed in as bit mask. See _mu_status_flags.
+ *
+ * @code
+ * Clear general interrupt 0 and general interrupt 1 pending flags.
+ * MU_ClearStatusFlags(base, kMU_GenInt0Flag | kMU_GenInt1Flag);
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param mask Bit mask of the MU status flags. See _mu_status_flags. The following
+ * flags are cleared by hardware, this function could not clear them.
+ * - kMU_Tx0EmptyFlag
+ * - kMU_Tx1EmptyFlag
+ * - kMU_Tx2EmptyFlag
+ * - kMU_Tx3EmptyFlag
+ * - kMU_Rx0FullFlag
+ * - kMU_Rx1FullFlag
+ * - kMU_Rx2FullFlag
+ * - kMU_Rx3FullFlag
+ * - kMU_EventPendingFlag
+ * - kMU_FlagsUpdatingFlag
+ * - kMU_OtherSideInResetFlag
+ */
+static inline void MU_ClearStatusFlags(MU_Type *base, uint32_t mask)
+{
+ /* regMask is the mask of w1c status bits. */
+ uint32_t regMask = MU_SR_GIPn_MASK;
+
+#if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ regMask |= MU_SR_RAIP_MASK;
+#endif
+#if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
+ regMask |= MU_SR_RDIP_MASK;
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_SR_MURIP) && FSL_FEATURE_MU_HAS_SR_MURIP)
+ regMask |= MU_SR_MURIP_MASK;
+#endif
+
+#if (defined(FSL_FEATURE_MU_HAS_SR_HRIP) && FSL_FEATURE_MU_HAS_SR_HRIP)
+ regMask |= MU_SR_HRIP_MASK;
+#endif
+
+ base->SR = (mask & regMask);
+}
+
+/*!
+ * @brief Enables the specific MU interrupts.
+ *
+ * This function enables the specific MU interrupts. The interrupts to enable
+ * should be passed in as bit mask. See _mu_interrupt_enable.
+ *
+ * @code
+ * Enable general interrupt 0 and TX0 empty interrupt.
+ * MU_EnableInterrupts(base, kMU_GenInt0InterruptEnable | kMU_Tx0EmptyInterruptEnable);
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param mask Bit mask of the MU interrupts. See _mu_interrupt_enable.
+ */
+static inline void MU_EnableInterrupts(MU_Type *base, uint32_t mask)
+{
+ uint32_t reg = base->CR;
+ reg = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | mask;
+ base->CR = reg;
+}
+
+/*!
+ * @brief Disables the specific MU interrupts.
+ *
+ * This function disables the specific MU interrupts. The interrupts to disable
+ * should be passed in as bit mask. See _mu_interrupt_enable.
+ *
+ * @code
+ * Disable general interrupt 0 and TX0 empty interrupt.
+ * MU_DisableInterrupts(base, kMU_GenInt0InterruptEnable | kMU_Tx0EmptyInterruptEnable);
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param mask Bit mask of the MU interrupts. See _mu_interrupt_enable.
+ */
+static inline void MU_DisableInterrupts(MU_Type *base, uint32_t mask)
+{
+ uint32_t reg = base->CR;
+ reg &= ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | mask);
+ base->CR = reg;
+}
+
+/*!
+ * @brief Triggers interrupts to the other core.
+ *
+ * This function triggers the specific interrupts to the other core. The interrupts
+ * to trigger are passed in as bit mask. See \ref _mu_interrupt_trigger.
+ * The MU should not trigger an interrupt to the other core when the previous interrupt
+ * has not been processed by the other core. This function checks whether the
+ * previous interrupts have been processed. If not, it returns an error.
+ *
+ * @code
+ * if (kStatus_Success != MU_TriggerInterrupts(base, kMU_GenInt0InterruptTrigger | kMU_GenInt2InterruptTrigger))
+ * {
+ * Previous general purpose interrupt 0 or general purpose interrupt 2
+ * has not been processed by the other core.
+ * }
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param mask Bit mask of the interrupts to trigger. See _mu_interrupt_trigger.
+ * @retval kStatus_Success Interrupts have been triggered successfully.
+ * @retval kStatus_Fail Previous interrupts have not been accepted.
+ */
+status_t MU_TriggerInterrupts(MU_Type *base, uint32_t mask);
+
+#if !(defined(FSL_FEATURE_MU_NO_NMI) && FSL_FEATURE_MU_NO_NMI)
+/*!
+ * @brief Clear non-maskable interrupt (NMI) sent by the other core.
+ *
+ * This function clears non-maskable interrupt (NMI) sent by the other core.
+ *
+ * @param base MU peripheral base address.
+ */
+static inline void MU_ClearNmi(MU_Type *base)
+{
+ base->SR = MU_SR_NMIC_MASK;
+}
+#endif /* FSL_FEATURE_MU_NO_NMI */
+
+/* @} */
+
+/*!
+ * @name MU misc functions
+ * @{
+ */
+
+#if !(defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
+/*!
+ * @brief Boots the core at B side.
+ *
+ * This function sets the B side core's boot configuration and releases the
+ * core from reset.
+ *
+ * @param base MU peripheral base address.
+ * @param mode Core B boot mode.
+ * @note Only MU side A can use this function.
+ */
+void MU_BootCoreB(MU_Type *base, mu_core_boot_mode_t mode);
+
+/*!
+ * @brief Holds the core reset of B side.
+ *
+ * This function causes the core of B side to be held in reset following any reset event.
+ *
+ * @param base MU peripheral base address.
+ * @note Only A side could call this function.
+ */
+static inline void MU_HoldCoreBReset(MU_Type *base)
+{
+#if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
+ base->CCR |= MU_CCR_RSTH_MASK;
+#else /* FSL_FEATURE_MU_HAS_CCR */
+ uint32_t reg = base->CR;
+ reg = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | MU_CR_RSTH_MASK;
+ base->CR = reg;
+#endif /* FSL_FEATURE_MU_HAS_CCR */
+}
+
+/*!
+ * @brief Boots the other core.
+ *
+ * This function boots the other core with a boot configuration.
+ *
+ * @param base MU peripheral base address.
+ * @param mode The other core boot mode.
+ */
+void MU_BootOtherCore(MU_Type *base, mu_core_boot_mode_t mode);
+
+/*!
+ * @brief Holds the other core reset.
+ *
+ * This function causes the other core to be held in reset following any reset event.
+ *
+ * @param base MU peripheral base address.
+ */
+static inline void MU_HoldOtherCoreReset(MU_Type *base)
+{
+ /*
+ * MU_HoldOtherCoreReset and MU_HoldCoreBReset are the same, MU_HoldCoreBReset
+ * is kept for compatible with older platforms.
+ */
+ MU_HoldCoreBReset(base);
+}
+#endif /* FSL_FEATURE_MU_NO_RSTH */
+
+#if !(defined(FSL_FEATURE_MU_NO_MUR) && FSL_FEATURE_MU_NO_MUR)
+/*!
+ * @brief Resets the MU for both A side and B side.
+ *
+ * This function resets the MU for both A side and B side. Before reset, it is
+ * recommended to interrupt processor B, because this function may affect the
+ * ongoing processor B programs.
+ *
+ * @param base MU peripheral base address.
+ * @note For some platforms, only MU side A could use this function, check
+ * reference manual for details.
+ */
+static inline void MU_ResetBothSides(MU_Type *base)
+{
+ uint32_t reg = base->CR;
+ reg = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | MU_CR_MUR_MASK;
+ base->CR = reg;
+
+#if (defined(FSL_FEATURE_MU_HAS_SR_RS) && FSL_FEATURE_MU_HAS_SR_RS)
+ /* Wait for the other side out of reset. */
+ while (0U != (base->SR & MU_SR_RS_MASK))
+ {
+ }
+#endif /* FSL_FEATURE_MU_HAS_SR_RS */
+}
+#endif /* FSL_FEATURE_MU_NO_MUR */
+
+#if (defined(FSL_FEATURE_MU_HAS_HRM) && FSL_FEATURE_MU_HAS_HRM)
+/*!
+ * @brief Mask hardware reset by the other core.
+ *
+ * The other core could call MU_HardwareResetOtherCore() to reset current core.
+ * To mask the reset, call this function and pass in true.
+ *
+ * @param base MU peripheral base address.
+ * @param mask Pass true to mask the hardware reset, pass false to unmask it.
+ */
+static inline void MU_MaskHardwareReset(MU_Type *base, bool mask)
+{
+#if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
+ if (mask)
+ {
+ base->CCR |= MU_CCR_HRM_MASK;
+ }
+ else
+ {
+ base->CCR &= ~MU_CCR_HRM_MASK;
+ }
+#else /* FSL_FEATURE_MU_HAS_CCR */
+ if (mask)
+ {
+ base->CR |= MU_CR_HRM_MASK;
+ }
+ else
+ {
+ base->CR &= ~MU_CR_HRM_MASK;
+ }
+#endif /* FSL_FEATURE_MU_HAS_CCR */
+}
+#endif /* FSL_FEATURE_MU_HAS_HRM */
+
+#if !(defined(FSL_FEATURE_MU_NO_HR) && FSL_FEATURE_MU_NO_HR)
+/*!
+ * @brief Hardware reset the other core.
+ *
+ * This function resets the other core, the other core could mask the
+ * hardware reset by calling MU_MaskHardwareReset. The hardware reset
+ * mask feature is only available for some platforms.
+ * This function could be used together with MU_BootOtherCore to control the
+ * other core reset workflow.
+ *
+ * Example 1: Reset the other core, and no hold reset
+ * @code
+ * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
+ * @endcode
+ * In this example, the core at MU side B will reset with the specified boot mode.
+ *
+ * Example 2: Reset the other core and hold it, then boot the other core later.
+ * @code
+ * Here the other core enters reset, and the reset is hold
+ * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
+ * Current core boot the other core when necessary.
+ * MU_BootOtherCore(MU_A, bootMode);
+ * @endcode
+ *
+ * @param base MU peripheral base address.
+ * @param waitReset Wait the other core enters reset.
+ * - true: Wait until the other core enters reset, if the other
+ * core has masked the hardware reset, then this function will
+ * be blocked.
+ * - false: Don't wait the reset.
+ * @param holdReset Hold the other core reset or not.
+ * - true: Hold the other core in reset, this function returns
+ * directly when the other core enters reset.
+ * - false: Don't hold the other core in reset, this function
+ * waits until the other core out of reset.
+ * @param bootMode Boot mode of the other core, if @p holdReset is true, this
+ * parameter is useless.
+ */
+void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode);
+#endif /* FSL_FEATURE_MU_NO_HR */
+
+#if !(defined(FSL_FEATURE_MU_NO_CLKE) && FSL_FEATURE_MU_NO_CLKE)
+/*!
+ * @brief Enables or disables the clock on the other core.
+ *
+ * This function enables or disables the platform clock on the other core when
+ * that core enters a stop mode. If disabled, the platform clock for the other
+ * core is disabled when it enters stop mode. If enabled, the platform clock
+ * keeps running on the other core in stop mode, until this core also enters
+ * stop mode.
+ *
+ * @param base MU peripheral base address.
+ * @param enable Enable or disable the clock on the other core.
+ */
+static inline void MU_SetClockOnOtherCoreEnable(MU_Type *base, bool enable)
+{
+#if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
+ if (enable)
+ {
+ base->CCR |= MU_CCR_CLKE_MASK;
+ }
+ else
+ {
+ base->CCR &= ~MU_CCR_CLKE_MASK;
+ }
+#else /* FSL_FEATURE_MU_HAS_CCR */
+ uint32_t reg = base->CR;
+
+ reg &= ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK);
+
+ if (enable)
+ {
+ reg |= MU_CR_CLKE_MASK;
+ }
+ else
+ {
+ reg &= ~MU_CR_CLKE_MASK;
+ }
+
+ base->CR = reg;
+#endif /* FSL_FEATURE_MU_HAS_CCR */
+}
+#endif /* FSL_FEATURE_MU_NO_CLKE */
+
+#if !(defined(FSL_FEATURE_MU_NO_PM) && FSL_FEATURE_MU_NO_PM)
+/*!
+ * @brief Gets the power mode of the other core.
+ *
+ * This function gets the power mode of the other core.
+ *
+ * @param base MU peripheral base address.
+ * @return Power mode of the other core.
+ */
+static inline mu_power_mode_t MU_GetOtherCorePowerMode(MU_Type *base)
+{
+ uint32_t ret = (base->SR & MU_SR_PM_MASK) >> MU_SR_PM_SHIFT;
+
+ return (mu_power_mode_t)ret;
+}
+#endif /* FSL_FEATURE_MU_NO_PM */
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+/*@}*/
+
+#endif /* _FSL_MU_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c
new file mode 100644
index 0000000000..4c15d6974d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_ocotp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.ocotp"
+#endif
+
+#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS
+#define OCOTP_STATUS_READ_DED_MASK \
+ (OCOTP_OUT_STATUS0_DED0_MASK | OCOTP_OUT_STATUS0_DED1_MASK | OCOTP_OUT_STATUS0_DED2_MASK | \
+ OCOTP_OUT_STATUS0_DED3_MASK)
+#endif
+
+/* Wait time should be not less than 150ns . */
+#define OCOTP_TIMING_WAIT_NS (uint64_t)150
+/* Relex time should be not less than 100ns . */
+#define OCOTP_TIMING_RELEX_NS (uint64_t)100
+/* Program time should be rang from 9000ns~11000ns. */
+#define OCOTP_TIMING_PROGRAM_NS (uint64_t)10000
+/* Read time should be less than 40ns. */
+#define OCOTP_TIMING_READ_NS (uint64_t)40
+
+/* Unlock key is 0x3E77. */
+#define OCOTP_WRITE_UNLOCK_KEY (0x3E77)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+/*!
+ * @brief Set read timing configuration.
+ *
+ * @param base OCOTP peripheral base addess.
+ * @param timingConfig configuration of timing.
+ */
+static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig);
+
+/*!
+ * @brief Set write timing configuration.
+ *
+ * @param base OCOTP peripheral base addess.
+ * @param timingConfig configuration of timing.
+ */
+static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+/* Timing configuration for OCOTP controller. */
+static ocotp_timing_t s_timingConfig;
+#endif
+
+/*******************************************************************************
+ * Code
+ *******************************************************************************/
+/* Reload the shadow register. */
+status_t OCOTP_ReloadShadowRegister(OCOTP_Type *base)
+{
+ assert(NULL != base);
+
+ status_t status = kStatus_Success;
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ /* Set the read timing. */
+ OCOTP_SetReadTiming(base, s_timingConfig);
+
+ /* Wait for the OCOTP controller not busy. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+#endif
+
+#if defined(OCOTP_OUT_STATUS0_DED_RELOAD_MASK)
+ /* Clear reload error status. */
+ base->OUT_STATUS0_CLR = OCOTP_OUT_STATUS0_DED_RELOAD_MASK;
+#endif
+
+ /* Set reload bit. */
+ base->CTRL_SET = OCOTP_CTRL_RELOAD_SHADOWS(1);
+
+ /* Wait for the OCOTP controller not busy. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+ /* Wait for shadow register reload complete. this bit will be auto clear by OCOTP once operation is complete. */
+ while (OCOTP_CTRL_RELOAD_SHADOWS_MASK == (base->CTRL & OCOTP_CTRL_RELOAD_SHADOWS_MASK))
+ {
+ }
+
+#if defined(OCOTP_OUT_STATUS0_DED_RELOAD_MASK)
+ if ((base->OUT_STATUS0 & OCOTP_OUT_STATUS0_DED_RELOAD_MASK) != 0U)
+ {
+ status = kStatus_OCOTP_ReloadError;
+ }
+#endif
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig)
+{
+ uint32_t timingValue = base->TIMING;
+
+ timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_READ_MASK | OCOTP_TIMING_WAIT_MASK);
+ timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_READ(timingConfig.strobe_read) |
+ OCOTP_TIMING_WAIT(timingConfig.wait);
+ base->TIMING = timingValue;
+}
+
+static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig)
+{
+ uint32_t timingValue = base->TIMING;
+
+ timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_PROG_MASK | OCOTP_TIMING_WAIT_MASK);
+ timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_PROG(timingConfig.strobe_prog) |
+ OCOTP_TIMING_WAIT(timingConfig.wait);
+
+ base->TIMING = timingValue;
+}
+#endif
+
+/* Initializes OCOTP controller. */
+void OCOTP_Init(OCOTP_Type *base, uint32_t srcClock_Hz)
+{
+ assert(NULL != base);
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ assert(0UL != srcClock_Hz);
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable OCOTP clock */
+ CLOCK_EnableClock(kCLOCK_Ocotp);
+#endif
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ /* tWait time shoule be higher than OCOTP_TIMING_WAIT_NS. */
+ s_timingConfig.wait = (uint32_t)((OCOTP_TIMING_WAIT_NS * srcClock_Hz + 1000000000U) / 1000000000U - 1U);
+
+ /* tRelax time shoule be higher than OCOTP_TIMING_RELEX_NS. */
+ s_timingConfig.relax = (uint32_t)((OCOTP_TIMING_RELEX_NS * srcClock_Hz + 1000000000U) / 1000000000U - 1U);
+
+ /* tStrobe_prog time should be close to OCOTP_TIMING_PROGRAM_NS, only add half of 1000000000. */
+ s_timingConfig.strobe_prog = (uint32_t)((OCOTP_TIMING_PROGRAM_NS * srcClock_Hz + 500000000U) / 1000000000U) +
+ 2U * (s_timingConfig.relax + 1U) - 1U;
+
+ /* tStrobe_read time should be higher than OCOTP_TIMING_READ_NS. */
+ s_timingConfig.strobe_read = (uint32_t)((OCOTP_TIMING_READ_NS * srcClock_Hz + 1000000000U) / 1000000000U) +
+ 2U * (s_timingConfig.relax + 1U) - 1U;
+#endif
+}
+
+/* De-init OCOTP controller. */
+void OCOTP_Deinit(OCOTP_Type *base)
+{
+ assert(NULL != base);
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ s_timingConfig.wait = 0UL;
+ s_timingConfig.relax = 0UL;
+ s_timingConfig.strobe_prog = 0UL;
+ s_timingConfig.strobe_read = 0UL;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable OCOTP clock */
+ CLOCK_DisableClock(kCLOCK_Ocotp);
+#endif
+}
+
+/* Read the fuse shadow register. */
+uint32_t OCOTP_ReadFuseShadowRegister(OCOTP_Type *base, uint32_t address)
+{
+ assert(NULL != base);
+
+ uint32_t data = 0U;
+
+ (void)OCOTP_ReadFuseShadowRegisterExt(base, address, &data, 1);
+
+ return data;
+}
+
+status_t OCOTP_ReadFuseShadowRegisterExt(OCOTP_Type *base, uint32_t address, uint32_t *data, uint8_t fuseWords)
+{
+ assert((fuseWords > 0U) && (fuseWords <= OCOTP_READ_FUSE_DATA_COUNT));
+ assert(NULL != data);
+
+ status_t status = kStatus_Success;
+
+#if (OCOTP_READ_FUSE_DATA_COUNT > 1U)
+ uint32_t i;
+#endif
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ /* Set the read timing. */
+ OCOTP_SetReadTiming(base, s_timingConfig);
+
+ /* Wait for busy bit is cleared. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+#endif
+
+#if defined(OCOTP_STATUS_READ_DED_MASK)
+ /* Clear error flags. */
+ base->OUT_STATUS0_CLR = OCOTP_STATUS_READ_DED_MASK;
+#endif
+
+ /* Write requested address to register. */
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK;
+ base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address);
+
+ /* Set OCOTP auto read enable. */
+#if defined(OCOTP_READ_CTRL_READ_NUM_MASK)
+ base->READ_CTRL = (base->READ_CTRL & ~(OCOTP_READ_CTRL_READ_NUM_MASK)) |
+ OCOTP_READ_CTRL_READ_NUM((uint32_t)fuseWords - 1U) | OCOTP_READ_CTRL_READ_FUSE_MASK;
+#else
+ base->READ_CTRL |= OCOTP_READ_CTRL_READ_FUSE_MASK;
+#endif
+
+ /* Wait for busy bit is cleared, and no error occurred on controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+
+ status = kStatus_OCOTP_AccessError;
+ }
+
+#if defined(OCOTP_STATUS_READ_DED_MASK)
+ if ((base->OUT_STATUS0 & OCOTP_STATUS_READ_DED_MASK) != 0U)
+ {
+ status = kStatus_Fail;
+ }
+#endif
+
+#if (OCOTP_READ_FUSE_DATA_COUNT == 1U)
+ *data = base->READ_FUSE_DATA;
+#else
+ for (i = 0; i < fuseWords; i++)
+ {
+ data[i] = base->READ_FUSE_DATAS[i].READ_FUSE_DATA;
+ }
+#endif
+
+ return status;
+}
+
+/* Write the fuse shadow register. */
+status_t OCOTP_WriteFuseShadowRegister(OCOTP_Type *base, uint32_t address, uint32_t data)
+{
+ return OCOTP_WriteFuseShadowRegisterWithLock(base, address, data, false);
+}
+
+status_t OCOTP_WriteFuseShadowRegisterWithLock(OCOTP_Type *base, uint32_t address, uint32_t data, bool lock)
+{
+ assert(NULL != base);
+
+ status_t status = kStatus_Success;
+
+#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS
+ uint32_t regStatus;
+#endif
+
+#if !(defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK)
+ if (lock)
+ {
+ return kStatus_InvalidArgument;
+ }
+#endif
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+ /* Set write timing for OCOTP controller. */
+ OCOTP_SetWriteTiming(base, s_timingConfig);
+
+ /* Wait for busy bit is cleared. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+#endif
+
+#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS
+ /* Clear errors. */
+ base->OUT_STATUS0_CLR = (OCOTP_OUT_STATUS0_PROGFAIL_MASK | OCOTP_OUT_STATUS0_LOCKED_MASK);
+#endif
+
+ /* Write requested address and unlock key to register. */
+#if (defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK)
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK | OCOTP_CTRL_WR_UNLOCK_MASK | OCOTP_CTRL_WORDLOCK_MASK;
+#else
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK | OCOTP_CTRL_WR_UNLOCK_MASK;
+#endif
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK)
+ if (lock)
+ {
+ base->CTRL_SET =
+ OCOTP_CTRL_SET_ADDR(address) | OCOTP_CTRL_WR_UNLOCK(OCOTP_WRITE_UNLOCK_KEY) | OCOTP_CTRL_WORDLOCK_MASK;
+ }
+ else
+#endif
+ {
+ base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address) | OCOTP_CTRL_WR_UNLOCK(OCOTP_WRITE_UNLOCK_KEY);
+ }
+
+ /* Write data to register. */
+ base->DATA = data;
+
+ /* Wait for busy bit is cleared, and no error occurred on controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+
+ status = kStatus_OCOTP_AccessError;
+ }
+
+#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS
+ regStatus = base->OUT_STATUS0;
+
+ if ((regStatus & OCOTP_OUT_STATUS0_PROGFAIL_MASK) != 0U)
+ {
+ status = kStatus_OCOTP_ProgramFail;
+ }
+ else if ((regStatus & OCOTP_OUT_STATUS0_LOCKED_MASK) != 0U)
+ {
+ status = kStatus_OCOTP_Locked;
+ }
+ else
+ {
+ /* For MISRA rules. */
+ }
+#endif
+
+ if (kStatus_Success == status)
+ {
+ /* Reload the fuse register. */
+ status = OCOTP_ReloadShadowRegister(base);
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h
new file mode 100644
index 0000000000..73a405a12a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_OCOTP_H_
+#define _FSL_OCOTP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup ocotp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+/*! @name Driver version */
+/*@{*/
+/*! @brief OCOTP driver version. */
+#define FSL_OCOTP_DRIVER_VERSION (MAKE_VERSION(2, 1, 3))
+/*@}*/
+
+#ifndef OCOTP_READ_FUSE_DATA_COUNT
+#define OCOTP_READ_FUSE_DATA_COUNT (1U)
+#endif
+
+/*! @brief _ocotp_status Error codes for the OCOTP driver. */
+enum
+{
+ kStatus_OCOTP_AccessError = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 0), /*!< eFuse and shadow register access error. */
+ kStatus_OCOTP_CrcFail = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 1), /*!< CRC check failed. */
+ kStatus_OCOTP_ReloadError =
+ MAKE_STATUS(kStatusGroup_SDK_OCOTP, 2), /*!< Error happens during reload shadow register. */
+ kStatus_OCOTP_ProgramFail = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 3), /*!< Fuse programming failed. */
+ kStatus_OCOTP_Locked = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 4), /*!< Fuse is locked and cannot be programmed. */
+};
+
+#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL)
+/*! @brief OCOTP timing structure.
+ * Note that, these value are used for calcalating the read/write timings.
+ * And the values should statisfy below rules:
+ *
+ * Tsp_rd=(WAIT+1)/ipg_clk_freq should be >= 150ns;
+ * Tsp_pgm=(RELAX+1)/ipg_clk_freq should be >= 100ns;
+ * Trd = ((STROBE_READ+1)- 2*(RELAX_READ+1)) /ipg_clk_freq,
+ * The Trd is required to be larger than 40 ns.
+ * Tpgm = ((STROBE_PROG+1)- 2*(RELAX_PROG+1)) /ipg_clk_freq;
+ * The Tpgm should be configured within the range of 9000 ns < Tpgm < 11000 ns;
+ */
+typedef struct _ocotp_timing
+{
+ uint32_t wait; /*!< Wait time value to fill in the TIMING register. */
+ uint32_t relax; /*!< Relax time value to fill in the TIMING register. */
+ uint32_t strobe_prog; /*!< Storbe program time value to fill in the TIMING register. */
+ uint32_t strobe_read; /*!< Storbe read time value to fill in the TIMING register. */
+} ocotp_timing_t;
+#endif /* FSL_FEATURE_OCOTP_HAS_TIMING_CTRL */
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes OCOTP controller.
+ *
+ * @param base OCOTP peripheral base address.
+ * @param srcClock_Hz source clock frequency in unit of Hz. When the macro
+ * FSL_FEATURE_OCOTP_HAS_TIMING_CTRL is defined as 0, this parameter is not used,
+ * application could pass in 0 in this case.
+ */
+void OCOTP_Init(OCOTP_Type *base, uint32_t srcClock_Hz);
+
+/*!
+ * @brief De-initializes OCOTP controller.
+ *
+ * @retval kStatus_Success upon successful execution, error status otherwise.
+ */
+void OCOTP_Deinit(OCOTP_Type *base);
+
+/*!
+ * @brief Checking the BUSY bit in CTRL register.
+ * Checking this BUSY bit will help confirm if the OCOTP controller is ready for access.
+ *
+ * @param base OCOTP peripheral base address.
+ * @retval true for bit set and false for cleared.
+ */
+static inline bool OCOTP_CheckBusyStatus(OCOTP_Type *base)
+{
+ return ((OCOTP_CTRL_BUSY_MASK == (base->CTRL & OCOTP_CTRL_BUSY_MASK)) ? (true) : (false));
+}
+
+/*!
+ * @brief Checking the ERROR bit in CTRL register.
+ *
+ * @param base OCOTP peripheral base address.
+ * @retval true for bit set and false for cleared.
+ */
+static inline bool OCOTP_CheckErrorStatus(OCOTP_Type *base)
+{
+ return ((OCOTP_CTRL_ERROR_MASK == (base->CTRL & OCOTP_CTRL_ERROR_MASK)) ? (true) : (false));
+}
+
+/*!
+ * @brief Clear the error bit if this bit is set.
+ *
+ * @param base OCOTP peripheral base address.
+ */
+static inline void OCOTP_ClearErrorStatus(OCOTP_Type *base)
+{
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ERROR_MASK;
+}
+
+/*!
+ * @brief Reload the shadow register.
+ * This function will help reload the shadow register without reseting the OCOTP module.
+ * Please make sure the OCOTP has been initialized before calling this API.
+ *
+ * @param base OCOTP peripheral base addess.
+ * @retval kStatus_Success Reload success.
+ * @retval kStatus_OCOTP_ReloadError Reload failed.
+ */
+status_t OCOTP_ReloadShadowRegister(OCOTP_Type *base);
+
+/*!
+ * @brief Read the fuse shadow register with the fuse addess.
+ *
+ * @deprecated Use @ref OCOTP_ReadFuseShadowRegisterExt instead of this function.
+ *
+ * @param base OCOTP peripheral base address.
+ * @param address the fuse address to be read from.
+ * @return The read out data.
+ */
+uint32_t OCOTP_ReadFuseShadowRegister(OCOTP_Type *base, uint32_t address);
+
+/*!
+ * @brief Read the fuse shadow register from the fuse addess.
+ *
+ * This function reads fuse from @p address, how many words to read is specified
+ * by the parameter @p fuseWords. This function could read at most
+ * OCOTP_READ_FUSE_DATA_COUNT fuse word one time.
+ *
+ * @param base OCOTP peripheral base address.
+ * @param address the fuse address to be read from.
+ * @param data Data array to save the readout fuse value.
+ * @param fuseWords How many words to read.
+ * @retval kStatus_Success Read success.
+ * @retval kStatus_Fail Error occurs during read.
+ */
+status_t OCOTP_ReadFuseShadowRegisterExt(OCOTP_Type *base, uint32_t address, uint32_t *data, uint8_t fuseWords);
+
+/*!
+ * @brief Write the fuse shadow register with the fuse addess and data.
+ * Please make sure the wrtie address is not locked while calling this API.
+ *
+ * @param base OCOTP peripheral base address.
+ * @param address the fuse address to be written.
+ * @param data the value will be writen to fuse address.
+ * @retval write status, kStatus_Success for success and kStatus_Fail for failed.
+ */
+status_t OCOTP_WriteFuseShadowRegister(OCOTP_Type *base, uint32_t address, uint32_t data);
+
+/*!
+ * @brief Write the fuse shadow register and lock it.
+ *
+ * Please make sure the wrtie address is not locked while calling this API.
+ *
+ * Some OCOTP controller supports ECC mode and redundancy mode (see reference mananual
+ * for more details). OCOTP controller will auto select ECC or redundancy
+ * mode to program the fuse word according to fuse map definition. In ECC mode, the
+ * 32 fuse bits in one word can only be written once. In redundancy mode, the word can
+ * be written more than once as long as they are different fuse bits. Set parameter
+ * @p lock as true to force use ECC mode.
+ *
+ * @param base OCOTP peripheral base address.
+ * @param address The fuse address to be written.
+ * @param data The value will be writen to fuse address.
+ * @param lock Lock or unlock write fuse shadow register operation.
+ * @retval kStatus_Success Program and reload success.
+ * @retval kStatus_OCOTP_Locked The eFuse word is locked and cannot be programmed.
+ * @retval kStatus_OCOTP_ProgramFail eFuse word programming failed.
+ * @retval kStatus_OCOTP_ReloadError eFuse word programming success, but
+ * error happens during reload the values.
+ * @retval kStatus_OCOTP_AccessError Cannot access eFuse word.
+ */
+status_t OCOTP_WriteFuseShadowRegisterWithLock(OCOTP_Type *base, uint32_t address, uint32_t data, bool lock);
+
+/*!
+ * @brief Get the OCOTP controller version from the register.
+ *
+ * @param base OCOTP peripheral base address.
+ * @retval return the version value.
+ */
+static inline uint32_t OCOTP_GetVersion(OCOTP_Type *base)
+{
+ return (base->VERSION);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_OCOTP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c
new file mode 100644
index 0000000000..bfdc89384c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pdm.h"
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pdm"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief Typedef for pdm rx interrupt handler. */
+typedef void (*pdm_isr_t)(PDM_Type *base, pdm_handle_t *pdmHandle);
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+/*!
+ * @brief Get the instance number for PDM.
+ *
+ * @param channelMask enabled channel.
+ * @param qualitymode selected quality mode.
+ * @param osr oversample rate.
+ * @param regdiv register divider.
+ */
+static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
+ pdm_df_quality_mode_t qualityMode,
+ uint8_t osr,
+ uint32_t regDiv);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
+/*!@brief PDM handle pointer */
+static pdm_handle_t *s_pdmHandle[ARRAY_SIZE(s_pdmBases)];
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_pdmClock[] = PDM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+/* Clock name array */
+static const clock_ip_name_t s_pdmFilterClock[] = PDM_FILTER_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static pdm_isr_t s_pdmIsr;
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief callback for hwvad. */
+static pdm_hwvad_notification_t s_pdm_hwvad_notification[ARRAY_SIZE(s_pdmBases)];
+#endif
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t PDM_GetInstance(PDM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pdmBases); instance++)
+ {
+ if (s_pdmBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pdmBases));
+
+ return instance;
+}
+
+/*!
+ * brief PDM read fifo.
+ * Note: This function support 16 bit only for IP version that only supports 16bit.
+ *
+ * param base PDM base pointer.
+ * param startChannel start channel number.
+ * param channelNums total enabled channelnums.
+ * param buffer received buffer address.
+ * param size number of samples to read.
+ * param dataWidth sample width.
+ */
+void PDM_ReadFifo(
+ PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth)
+{
+ uint32_t i = 0, j = 0U;
+ uint32_t *dataAddr = (uint32_t *)buffer;
+
+ for (i = 0U; i < size; i++)
+ {
+ for (j = 0; j < channelNums; j++)
+ {
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
+ *dataAddr = base->DATACH[startChannel + j] >> (dataWidth == 4U ? 0U : 8U);
+ dataAddr = (uint32_t *)((uint32_t)dataAddr + dataWidth);
+#else
+ *dataAddr = base->DATACH[startChannel + j];
+ dataAddr = (uint32_t *)((uint32_t)dataAddr + 2U);
+#endif
+ }
+ }
+}
+
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
+/*!
+ * brief PDM read data non blocking, only support 16bit data read.
+ * So the actually read data byte size in this function is (size * 2 * channelNums).
+ * param base PDM base pointer.
+ * param startChannel start channel number.
+ * param channelNums total enabled channelnums.
+ * param buffer received buffer address.
+ * param size number of 16bit data to read.
+ */
+void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size)
+{
+ uint32_t i = 0, j = 0U;
+
+ for (i = 0U; i < size; i++)
+ {
+ for (j = 0; j < channelNums; j++)
+ {
+ *buffer++ = (int16_t)base->DATACH[startChannel + j];
+ }
+ }
+}
+#endif
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
+ pdm_df_quality_mode_t qualityMode,
+ uint8_t osr,
+ uint32_t regDiv)
+{
+ uint32_t enabledChannel = 0U, i = 0U, factor = 0U, k = 0U;
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM; i++)
+ {
+ if (((channelMask >> i) & 0x01U) != 0U)
+ {
+ enabledChannel++;
+ }
+ }
+
+ switch (qualityMode)
+ {
+ case kPDM_QualityModeMedium:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 2U;
+ break;
+
+ case kPDM_QualityModeHigh:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 1U;
+ break;
+
+ case kPDM_QualityModeLow:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 4U;
+ break;
+
+ case kPDM_QualityModeVeryLow0:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 2U;
+ break;
+
+ case kPDM_QualityModeVeryLow1:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 4U;
+ break;
+
+ case kPDM_QualityModeVeryLow2:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 8U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ /* validate the minimum clock divider */
+ /* 2U is for canculating k, 100U is for determing the specific float number of clock divider */
+ if (((regDiv * k) / 2U * 100U) < (((10U + factor * enabledChannel) * 100U / (8U * osr)) * k / 2U))
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+#endif
+
+/*!
+ * brief PDM set sample rate.
+ *
+ * note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
+ * code
+ * PDM_Init(base, pdmConfig)
+ * PDM_SetChannelConfig(base, channel, &channelConfig)
+ * PDM_SetSampleRateConfig(base, source, sampleRate)
+ * endcode
+ * param base PDM base pointer
+ * param sourceClock_HZ PDM source clock frequency.
+ * param sampleRate_HZ PDM sample rate.
+ */
+status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ)
+{
+ uint32_t osr = (base->CTRL_2 & PDM_CTRL_2_CICOSR_MASK) >> PDM_CTRL_2_CICOSR_SHIFT;
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ pdm_df_quality_mode_t qualityMode =
+ (pdm_df_quality_mode_t)(uint32_t)((base->CTRL_2 & PDM_CTRL_2_QSEL_MASK) >> PDM_CTRL_2_QSEL_SHIFT);
+ uint32_t enabledChannelMask = base->CTRL_1 & (uint32_t)kPDM_EnableChannelAll;
+#endif
+
+ uint32_t pdmClockRate = 0U;
+ uint32_t regDiv = 0U;
+
+ /* get divider */
+ osr = 16U - osr;
+ pdmClockRate = sampleRate_HZ * osr * 8U;
+ regDiv = sourceClock_HZ / pdmClockRate;
+
+ if (regDiv > PDM_CTRL_2_CLKDIV_MASK)
+ {
+ return kStatus_Fail;
+ }
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ if (PDM_ValidateSrcClockRate(enabledChannelMask, qualityMode, (uint8_t)osr, regDiv) == kStatus_Fail)
+ {
+ return kStatus_Fail;
+ }
+#endif
+
+ base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief PDM set sample rate.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref PDM_SetSampleRateConfig
+ * param base PDM base pointer
+ * param enableChannelMask PDM channel enable mask.
+ * param qualityMode quality mode.
+ * param osr cic oversample rate
+ * param clkDiv clock divider
+ */
+status_t PDM_SetSampleRate(
+ PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv)
+{
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ uint8_t realOsr = 16U - (osr & (PDM_CTRL_2_CICOSR_MASK >> PDM_CTRL_2_CICOSR_SHIFT));
+#endif
+ uint32_t regDiv = clkDiv >> 1U;
+
+ switch (qualityMode)
+ {
+ case kPDM_QualityModeHigh:
+ regDiv <<= 1U;
+ break;
+ case kPDM_QualityModeLow:
+ case kPDM_QualityModeVeryLow1:
+ regDiv >>= 1U;
+ break;
+ case kPDM_QualityModeVeryLow2:
+ regDiv >>= 2U;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ if (PDM_ValidateSrcClockRate(enableChannelMask, qualityMode, realOsr, regDiv) == kStatus_Fail)
+ {
+ return kStatus_Fail;
+ }
+#endif
+
+ assert(regDiv <= PDM_CTRL_2_CLKDIV_MASK);
+ base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the PDM peripheral.
+ *
+ * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * PDM_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base PDM base pointer
+ * param config PDM configuration structure.
+ */
+void PDM_Init(PDM_Type *base, const pdm_config_t *config)
+{
+ assert(config != NULL);
+ assert(config->fifoWatermark <= PDM_FIFO_CTRL_FIFOWMK_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the PDM clock */
+ CLOCK_EnableClock(s_pdmClock[PDM_GetInstance(base)]);
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+ CLOCK_EnableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Enable the module and disable the interface/all channel */
+ base->CTRL_1 &=
+ ~(PDM_CTRL_1_MDIS_MASK | PDM_CTRL_1_PDMIEN_MASK | PDM_CTRL_1_ERREN_MASK | (uint32_t)kPDM_EnableChannelAll);
+
+ /* wait all filter stopped */
+ while ((base->STAT & PDM_STAT_BSY_FIL_MASK) != 0U)
+ {
+ }
+
+ /* software reset */
+ base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
+
+ /* Set the configure settings */
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DOZEN_MASK)) | PDM_CTRL_1_DOZEN(config->enableDoze);
+
+ base->CTRL_2 = (base->CTRL_2 & (~(PDM_CTRL_2_CICOSR_MASK | PDM_CTRL_2_QSEL_MASK))) |
+ PDM_CTRL_2_CICOSR(config->cicOverSampleRate) | PDM_CTRL_2_QSEL(config->qualityMode);
+
+ /* Set the watermark */
+ base->FIFO_CTRL = PDM_FIFO_CTRL_FIFOWMK(config->fifoWatermark);
+}
+
+/*!
+ * brief De-initializes the PDM peripheral.
+ *
+ * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
+ * is called to enable the clock.
+ *
+ * param base PDM base pointer
+ */
+void PDM_Deinit(PDM_Type *base)
+{
+ /* disable PDM interface */
+ PDM_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_pdmClock[PDM_GetInstance(base)]);
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+ CLOCK_DisableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Enables the PDM interrupt requests.
+ *
+ * param base PDM base pointer
+ * param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * arg kPDM_ErrorInterruptEnable
+ * arg kPDM_FIFOInterruptEnable
+ */
+void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kPDM_FIFOInterruptEnable) != 0U)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | (uint32_t)kPDM_FIFOInterruptEnable;
+ }
+ if ((mask & (uint32_t)kPDM_ErrorInterruptEnable) != 0U)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_ERREN_MASK)) | (uint32_t)kPDM_ErrorInterruptEnable;
+ }
+}
+
+/*!
+ * brief PDM one channel configurations.
+ *
+ * param base PDM base pointer
+ * param config PDM channel configurations.
+ * param channel channel number.
+ * after completing the current frame in debug mode.
+ */
+void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config)
+{
+ assert(config != NULL);
+ assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+ uint32_t dcCtrl = 0U;
+
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+ dcCtrl = base->DC_OUT_CTRL;
+ /* configure gain and cut off freq */
+ dcCtrl &= ~((uint32_t)PDM_DC_OUT_CTRL_DCCONFIG0_MASK << (channel << 1U));
+ dcCtrl |= (uint32_t)config->outputCutOffFreq << (channel << 1U);
+ base->DC_OUT_CTRL = dcCtrl;
+#endif
+
+#if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
+ dcCtrl = base->DC_CTRL;
+ /* configure gain and cut off freq */
+ dcCtrl &= ~((uint32_t)PDM_DC_CTRL_DCCONFIG0_MASK << (channel << 1U));
+ dcCtrl |= (uint32_t)config->cutOffFreq << (channel << 1U);
+ base->DC_CTRL = dcCtrl;
+#endif
+
+ PDM_SetChannelGain(base, channel, config->gain);
+
+ /* enable channel */
+ base->CTRL_1 |= 1UL << channel;
+}
+
+/*!
+ * brief Set the PDM channel gain.
+ *
+ * Please note for different quality mode, the valid gain value is different, reference RM for detail.
+ * param base PDM base pointer.
+ * param channel PDM channel index.
+ * param gain channel gain, the register gain value range is 0 - 15.
+ */
+void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain)
+{
+ assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ uint32_t outCtrl = base->RANGE_CTRL;
+#else
+ uint32_t outCtrl = base->OUT_CTRL;
+#endif
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ outCtrl &= ~((uint32_t)PDM_RANGE_CTRL_RANGEADJ0_MASK << (channel << 2U));
+#else
+ outCtrl &= ~((uint32_t)PDM_OUT_CTRL_OUTGAIN0_MASK << (channel << 2U));
+#endif
+
+ outCtrl |= (uint32_t)gain << (channel << 2U);
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ base->RANGE_CTRL = outCtrl;
+#else
+ base->OUT_CTRL = outCtrl;
+#endif
+}
+
+/*!
+ * brief PDM set channel transfer config.
+ *
+ * param base PDM base pointer.
+ * param handle PDM handle pointer.
+ * param channel PDM channel.
+ * param config channel config.
+ * param format data format.
+ */
+status_t PDM_TransferSetChannelConfig(
+ PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format)
+{
+ assert(handle != NULL);
+
+ PDM_SetChannelConfig(base, channel, config);
+
+ handle->format = format;
+
+ if (handle->channelNums == 0U)
+ {
+ handle->startChannel = (uint8_t)channel;
+ }
+
+ handle->channelNums++;
+
+ if (handle->channelNums > (uint8_t)FSL_FEATURE_PDM_CHANNEL_NUM)
+ {
+ return kStatus_PDM_ChannelConfig_Failed;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the PDM handle.
+ *
+ * This function initializes the handle for the PDM transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base PDM base pointer.
+ * param handle PDM handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_pdmHandle[PDM_GetInstance(base)] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
+
+ /* Set the isr pointer */
+ s_pdmIsr = PDM_TransferHandleIRQ;
+
+ /* Enable RX event IRQ */
+ (void)EnableIRQ(PDM_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ /* Enable FIFO error IRQ */
+ (void)EnableIRQ(PDM_ERROR_IRQn);
+#endif
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on PDM.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
+ * is finished.
+ *
+ * param base PDM base pointer
+ * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the pdm_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_PDM_Busy Previous receive still not finished.
+ */
+status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->pdmQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_PDM_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->pdmQueue[handle->queueUser].data = xfer->data;
+ handle->pdmQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % PDM_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kStatus_PDM_Busy;
+
+ /* Enable interrupt */
+ PDM_EnableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable);
+
+ PDM_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base PDM base pointer
+ * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ */
+void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Use FIFO request interrupt and fifo error */
+ PDM_DisableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable | (uint32_t)kPDM_ErrorInterruptEnable);
+ PDM_Enable(base, false);
+ handle->state = kStatus_PDM_Idle;
+ /* Clear the queue */
+ (void)memset(handle->pdmQueue, 0, sizeof(pdm_transfer_t) * PDM_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base PDM base pointer.
+ * param handle Pointer to the pdm_handle_t structure.
+ */
+void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle)
+{
+ assert(handle != NULL);
+
+#if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ uint32_t status = 0U;
+
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ if (PDM_GetStatus(base) & PDM_STAT_LOWFREQF_MASK)
+ {
+ PDM_ClearStatus(base, PDM_STAT_LOWFREQF_MASK);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_CLK_LOW, handle->userData);
+ }
+ }
+#endif
+ status = PDM_GetFifoStatus(base);
+ if (status != 0U)
+ {
+ PDM_ClearFIFOStatus(base, status);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_FIFO_ERROR, handle->userData);
+ }
+ }
+
+#if !(defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL)
+ status = PDM_GetOutputStatus(base);
+ if (status != 0U)
+ {
+ PDM_ClearOutputStatus(base, status);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_Output_ERROR, handle->userData);
+ }
+ }
+#endif
+#endif
+
+ /* Handle transfer */
+ if (((base->STAT & 0xFFU) != 0U) && (handle->channelNums != 0U) &&
+ ((base->CTRL_1 & PDM_CTRL_1_DISEL_MASK) == (0x2UL << PDM_CTRL_1_DISEL_SHIFT)))
+ {
+ PDM_ClearStatus(base, 0xFFU);
+ /* Judge if the data need to transmit is less than space */
+ uint8_t size = (uint8_t)MIN((handle->pdmQueue[handle->queueDriver].dataSize),
+ ((uint32_t)handle->watermark * handle->channelNums * handle->format));
+
+ PDM_ReadFifo(base, handle->startChannel, handle->channelNums,
+ (uint8_t *)(uint32_t)handle->pdmQueue[handle->queueDriver].data,
+ ((size_t)size / handle->channelNums / handle->format), handle->format);
+
+ /* Update the internal counter */
+ handle->pdmQueue[handle->queueDriver].dataSize -= size;
+ handle->pdmQueue[handle->queueDriver].data = &(handle->pdmQueue[handle->queueDriver].data[size]);
+ }
+
+ /* If finished a block, call the callback function */
+ if (handle->pdmQueue[handle->queueDriver].dataSize == 0U)
+ {
+ handle->pdmQueue[handle->queueDriver].data = NULL;
+ handle->queueDriver = (handle->queueDriver + 1U) % PDM_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_Idle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->pdmQueue[handle->queueDriver].data == NULL)
+ {
+ PDM_TransferAbortReceive(base, handle);
+ }
+}
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*!
+ * brief set HWVAD in envelope based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = false,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = false,
+ * .enableNoiseMin = true,
+ * .enableNoiseDecimation = true,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = true,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value.
+ */
+void PDM_SetHwvadInEnvelopeBasedMode(PDM_Type *base,
+ const pdm_hwvad_config_t *hwvadConfig,
+ const pdm_hwvad_noise_filter_t *noiseConfig,
+ const pdm_hwvad_zero_cross_detector_t *zcdConfig,
+ uint32_t signalGain)
+{
+ assert(hwvadConfig != NULL);
+ assert(noiseConfig != NULL);
+
+ uint32_t i = 0U;
+
+ PDM_SetHwvadConfig(base, hwvadConfig);
+ PDM_SetHwvadSignalFilterConfig(base, true, signalGain);
+ PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
+ PDM_EnableHwvad(base, true);
+
+ if (NULL != zcdConfig)
+ {
+ PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
+ }
+
+ PDM_Enable(base, true);
+
+ while (PDM_GetHwvadInitialFlag(base) != 0U)
+ {
+ }
+
+ for (i = 0; i < 3U; i++)
+ {
+ /* set HWVAD interal filter stauts initial */
+ PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterInitial);
+ }
+
+ PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterNormalOperation);
+}
+
+/*!
+ * brief set HWVAD in energy based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = true,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = true,
+ * .enableNoiseMin = false,
+ * .enableNoiseDecimation = false,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = false,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value, signal gain value should be properly according to application.
+ */
+void PDM_SetHwvadInEnergyBasedMode(PDM_Type *base,
+ const pdm_hwvad_config_t *hwvadConfig,
+ const pdm_hwvad_noise_filter_t *noiseConfig,
+ const pdm_hwvad_zero_cross_detector_t *zcdConfig,
+ uint32_t signalGain)
+{
+ assert(hwvadConfig != NULL);
+ assert(noiseConfig != NULL);
+
+ PDM_SetHwvadConfig(base, hwvadConfig);
+ /* signal filter need to disable, but signal gain value should be set */
+ base->VAD0_SCONFIG = PDM_VAD0_SCONFIG_VADSGAIN(signalGain);
+ PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
+ PDM_EnableHwvad(base, true);
+
+ if (NULL != zcdConfig)
+ {
+ PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
+ }
+
+ PDM_Enable(base, true);
+}
+
+/*!
+ * brief Configure voice activity detector.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector configure structure pointer .
+ */
+void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t ctrl1 = base->VAD0_CTRL_1;
+
+ /* Configure VAD0_CTRL_1 register */
+ ctrl1 &= ~(PDM_VAD0_CTRL_1_VADCHSEL_MASK | PDM_VAD0_CTRL_1_VADCICOSR_MASK | PDM_VAD0_CTRL_1_VADINITT_MASK);
+ ctrl1 |= (PDM_VAD0_CTRL_1_VADCHSEL(config->channel) | PDM_VAD0_CTRL_1_VADCICOSR(config->cicOverSampleRate) |
+ PDM_VAD0_CTRL_1_VADINITT(config->initializeTime));
+ base->VAD0_CTRL_1 = ctrl1;
+
+ /* Configure VAD0_CTRL_2 register */
+ base->VAD0_CTRL_2 =
+ (PDM_VAD0_CTRL_2_VADFRENDIS((config->enableFrameEnergy == true) ? 0U : 1U) |
+ PDM_VAD0_CTRL_2_VADPREFEN(config->enablePreFilter) | PDM_VAD0_CTRL_2_VADFRAMET(config->frameTime) |
+ PDM_VAD0_CTRL_2_VADINPGAIN(config->inputGain) | PDM_VAD0_CTRL_2_VADHPF(config->cutOffFreq));
+}
+
+/*!
+ * brief Configure voice activity detector signal filter.
+ *
+ * param base PDM base pointer
+ * param enableMaxBlock If signal maximum block enabled.
+ * param signalGain Gain value for the signal energy.
+ */
+void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain)
+{
+ uint32_t signalConfig = base->VAD0_SCONFIG;
+
+ signalConfig &= ~(PDM_VAD0_SCONFIG_VADSMAXEN_MASK | PDM_VAD0_SCONFIG_VADSGAIN_MASK);
+ signalConfig |= (PDM_VAD0_SCONFIG_VADSMAXEN(enableMaxBlock) | PDM_VAD0_SCONFIG_VADSGAIN(signalGain)) |
+ PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ base->VAD0_SCONFIG = signalConfig;
+}
+
+/*!
+ * brief Configure voice activity detector noise filter.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector noise filter configure structure pointer .
+ */
+void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config)
+{
+ assert(config != NULL);
+
+ base->VAD0_NCONFIG =
+ (PDM_VAD0_NCONFIG_VADNFILAUTO(config->enableAutoNoiseFilter) |
+ PDM_VAD0_NCONFIG_VADNOREN(config->enableNoiseDetectOR) | PDM_VAD0_NCONFIG_VADNMINEN(config->enableNoiseMin) |
+ PDM_VAD0_NCONFIG_VADNDECEN(config->enableNoiseDecimation) |
+ PDM_VAD0_NCONFIG_VADNFILADJ(config->noiseFilterAdjustment) | PDM_VAD0_NCONFIG_VADNGAIN(config->noiseGain));
+}
+
+/*!
+ * brief Configure voice activity detector zero cross detector.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector zero cross detector configure structure pointer .
+ */
+void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t zcd = (base->VAD0_ZCD & (~(PDM_VAD0_ZCD_VADZCDTH_MASK | PDM_VAD0_ZCD_VADZCDADJ_MASK |
+ PDM_VAD0_ZCD_VADZCDAUTO_MASK | PDM_VAD0_ZCD_VADZCDAND_MASK)));
+
+ zcd |= (PDM_VAD0_ZCD_VADZCDTH(config->threshold) | PDM_VAD0_ZCD_VADZCDADJ(config->adjustmentThreshold) |
+ PDM_VAD0_ZCD_VADZCDAUTO(config->enableAutoThreshold) | PDM_VAD0_ZCD_VADZCDAND(config->zcdAnd)) |
+ PDM_VAD0_ZCD_VADZCDEN_MASK;
+
+ base->VAD0_ZCD = zcd;
+}
+
+/*!
+ * brief Enable/Disable hwvad callback.
+
+ * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
+ *
+ * param base Base address of the PDM peripheral.
+ * param vadCallback callback Pointer to store callback function, should be NULL when disable.
+ * param userData user data.
+ * param enable true is enable, false is disable.
+ * retval None.
+ */
+void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable)
+{
+ uint32_t instance = PDM_GetInstance(base);
+
+ if (enable)
+ {
+ PDM_EnableHwvadInterrupts(base, (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
+ NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
+ (void)EnableIRQ(PDM_HWVAD_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
+ (void)EnableIRQ(PDM_HWVAD_ERROR_IRQn);
+#endif
+ s_pdm_hwvad_notification[instance].callback = vadCallback;
+ s_pdm_hwvad_notification[instance].userData = userData;
+ }
+ else
+ {
+ PDM_DisableHwvadInterrupts(base,
+ (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
+ (void)DisableIRQ(PDM_HWVAD_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ (void)DisableIRQ(PDM_HWVAD_ERROR_IRQn);
+ NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
+#endif
+ s_pdm_hwvad_notification[instance].callback = NULL;
+ s_pdm_hwvad_notification[instance].userData = NULL;
+ NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
+ }
+}
+
+#if (defined PDM)
+void PDM_HWVAD_EVENT_DriverIRQHandler(void);
+void PDM_HWVAD_EVENT_DriverIRQHandler(void)
+{
+ if ((PDM_GetHwvadInterruptStatusFlags(PDM) & (uint32_t)kPDM_HwvadStatusVoiceDetectFlag) != 0U)
+ {
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusVoiceDetectFlag);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_VoiceDetected, s_pdm_hwvad_notification[0].userData);
+ }
+ }
+#if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ else
+ {
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
+ }
+ }
+#endif
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+void PDM_HWVAD_ERROR_DriverIRQHandler(void);
+void PDM_HWVAD_ERROR_DriverIRQHandler(void)
+{
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(PDM)
+void PDM_EVENT_DriverIRQHandler(void);
+void PDM_EVENT_DriverIRQHandler(void)
+{
+ assert(s_pdmHandle[0] != NULL);
+ s_pdmIsr(PDM, s_pdmHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h
new file mode 100644
index 0000000000..f7c263a188
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_PDM_H_
+#define _FSL_PDM_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup pdm_driver PDM Driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_DRIVER_VERSION (MAKE_VERSION(2, 8, 0)) /*!< Version 2.8.0 */
+/*@}*/
+
+/*! @brief PDM XFER QUEUE SIZE */
+#define PDM_XFER_QUEUE_SIZE (4U)
+
+/*! @brief PDM return status*/
+enum
+{
+ kStatus_PDM_Busy = MAKE_STATUS(kStatusGroup_PDM, 0), /*!< PDM is busy. */
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ kStatus_PDM_CLK_LOW = MAKE_STATUS(kStatusGroup_PDM, 1), /*!< PDM clock frequency low */
+#endif
+ kStatus_PDM_FIFO_ERROR = MAKE_STATUS(kStatusGroup_PDM, 2), /*!< PDM FIFO underrun or overflow */
+ kStatus_PDM_QueueFull = MAKE_STATUS(kStatusGroup_PDM, 3), /*!< PDM FIFO underrun or overflow */
+ kStatus_PDM_Idle = MAKE_STATUS(kStatusGroup_PDM, 4), /*!< PDM is idle */
+ kStatus_PDM_Output_ERROR = MAKE_STATUS(kStatusGroup_PDM, 5), /*!< PDM is output error */
+ kStatus_PDM_ChannelConfig_Failed = MAKE_STATUS(kStatusGroup_PDM, 6), /*!< PDM channel config failed */
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+ kStatus_PDM_HWVAD_VoiceDetected = MAKE_STATUS(kStatusGroup_PDM, 7), /*!< PDM hwvad voice detected */
+ kStatus_PDM_HWVAD_Error = MAKE_STATUS(kStatusGroup_PDM, 8), /*!< PDM hwvad error */
+#endif
+};
+
+/*! @brief The PDM interrupt enable flag */
+enum _pdm_interrupt_enable
+{
+ kPDM_ErrorInterruptEnable = PDM_CTRL_1_ERREN_MASK, /*!< PDM channel error interrupt enable. */
+ kPDM_FIFOInterruptEnable = PDM_CTRL_1_DISEL(2U), /*!< PDM channel FIFO interrupt */
+};
+
+/*! @brief The PDM status */
+enum _pdm_internal_status
+{
+ kPDM_StatusDfBusyFlag = (int)PDM_STAT_BSY_FIL_MASK, /*!< Decimation filter is busy processing data */
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_FIR_RDY) && FSL_FEATURE_PDM_HAS_NO_FIR_RDY)
+ kPDM_StatusFIRFilterReady = PDM_STAT_FIR_RDY_MASK, /*!< FIR filter data is ready */
+#endif
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ kPDM_StatusFrequencyLow = PDM_STAT_LOWFREQF_MASK, /*!< Mic app clock frequency not high enough */
+#endif
+ kPDM_StatusCh0FifoDataAvaliable = PDM_STAT_CH0F_MASK, /*!< channel 0 fifo data reached watermark level */
+ kPDM_StatusCh1FifoDataAvaliable = PDM_STAT_CH1F_MASK, /*!< channel 1 fifo data reached watermark level */
+ kPDM_StatusCh2FifoDataAvaliable = PDM_STAT_CH2F_MASK, /*!< channel 2 fifo data reached watermark level */
+ kPDM_StatusCh3FifoDataAvaliable = PDM_STAT_CH3F_MASK, /*!< channel 3 fifo data reached watermark level */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_StatusCh4FifoDataAvaliable = PDM_STAT_CH4F_MASK, /*!< channel 4 fifo data reached watermark level */
+ kPDM_StatusCh5FifoDataAvaliable = PDM_STAT_CH5F_MASK, /*!< channel 5 fifo data reached watermark level */
+ kPDM_StatusCh6FifoDataAvaliable = PDM_STAT_CH6F_MASK, /*!< channel 6 fifo data reached watermark level */
+ kPDM_StatusCh7FifoDataAvaliable = PDM_STAT_CH7F_MASK, /*!< channel 7 fifo data reached watermark level */
+#endif
+};
+
+/*! @brief PDM channel enable mask */
+enum _pdm_channel_enable_mask
+{
+ kPDM_EnableChannel0 = PDM_STAT_CH0F_MASK, /*!< channgel 0 enable mask */
+ kPDM_EnableChannel1 = PDM_STAT_CH1F_MASK, /*!< channgel 1 enable mask */
+ kPDM_EnableChannel2 = PDM_STAT_CH2F_MASK, /*!< channgel 2 enable mask */
+ kPDM_EnableChannel3 = PDM_STAT_CH3F_MASK, /*!< channgel 3 enable mask */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_EnableChannel4 = PDM_STAT_CH4F_MASK, /*!< channgel 4 enable mask */
+ kPDM_EnableChannel5 = PDM_STAT_CH5F_MASK, /*!< channgel 5 enable mask */
+ kPDM_EnableChannel6 = PDM_STAT_CH6F_MASK, /*!< channgel 6 enable mask */
+ kPDM_EnableChannel7 = PDM_STAT_CH7F_MASK, /*!< channgel 7 enable mask */
+
+ kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3 |
+ kPDM_EnableChannel4 | kPDM_EnableChannel5 | kPDM_EnableChannel6 | kPDM_EnableChannel7,
+#else
+ kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3,
+#endif
+};
+
+/*! @brief The PDM fifo status */
+enum _pdm_fifo_status
+{
+ kPDM_FifoStatusUnderflowCh0 = PDM_FIFO_STAT_FIFOUND0_MASK, /*!< channel0 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh1 = PDM_FIFO_STAT_FIFOUND1_MASK, /*!< channel1 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh2 = PDM_FIFO_STAT_FIFOUND2_MASK, /*!< channel2 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh3 = PDM_FIFO_STAT_FIFOUND3_MASK, /*!< channel3 fifo status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_FifoStatusUnderflowCh4 = PDM_FIFO_STAT_FIFOUND4_MASK, /*!< channel4 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh5 = PDM_FIFO_STAT_FIFOUND5_MASK, /*!< channel5 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh6 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel6 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh7 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel7 fifo status underflow */
+#endif
+
+ kPDM_FifoStatusOverflowCh0 = PDM_FIFO_STAT_FIFOOVF0_MASK, /*!< channel0 fifo status overflow */
+ kPDM_FifoStatusOverflowCh1 = PDM_FIFO_STAT_FIFOOVF1_MASK, /*!< channel1 fifo status overflow */
+ kPDM_FifoStatusOverflowCh2 = PDM_FIFO_STAT_FIFOOVF2_MASK, /*!< channel2 fifo status overflow */
+ kPDM_FifoStatusOverflowCh3 = PDM_FIFO_STAT_FIFOOVF3_MASK, /*!< channel3 fifo status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_FifoStatusOverflowCh4 = PDM_FIFO_STAT_FIFOOVF4_MASK, /*!< channel4 fifo status overflow */
+ kPDM_FifoStatusOverflowCh5 = PDM_FIFO_STAT_FIFOOVF5_MASK, /*!< channel5 fifo status overflow */
+ kPDM_FifoStatusOverflowCh6 = PDM_FIFO_STAT_FIFOOVF6_MASK, /*!< channel6 fifo status overflow */
+ kPDM_FifoStatusOverflowCh7 = PDM_FIFO_STAT_FIFOOVF7_MASK, /*!< channel7 fifo status overflow */
+#endif
+};
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*! @brief The PDM output status */
+enum _pdm_range_status
+{
+ kPDM_RangeStatusUnderFlowCh0 = PDM_RANGE_STAT_RANGEUNF0_MASK, /*!< channel0 range status underflow */
+ kPDM_RangeStatusUnderFlowCh1 = PDM_RANGE_STAT_RANGEUNF1_MASK, /*!< channel1 range status underflow */
+ kPDM_RangeStatusUnderFlowCh2 = PDM_RANGE_STAT_RANGEUNF2_MASK, /*!< channel2 range status underflow */
+ kPDM_RangeStatusUnderFlowCh3 = PDM_RANGE_STAT_RANGEUNF3_MASK, /*!< channel3 range status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_RangeStatusUnderFlowCh4 = PDM_RANGE_STAT_RANGEUNF4_MASK, /*!< channel4 range status underflow */
+ kPDM_RangeStatusUnderFlowCh5 = PDM_RANGE_STAT_RANGEUNF5_MASK, /*!< channel5 range status underflow */
+ kPDM_RangeStatusUnderFlowCh6 = PDM_RANGE_STAT_RANGEUNF6_MASK, /*!< channel6 range status underflow */
+ kPDM_RangeStatusUnderFlowCh7 = PDM_RANGE_STAT_RANGEUNF7_MASK, /*!< channel7 range status underflow */
+#endif
+ kPDM_RangeStatusOverFlowCh0 = PDM_RANGE_STAT_RANGEOVF0_MASK, /*!< channel0 range status overflow */
+ kPDM_RangeStatusOverFlowCh1 = PDM_RANGE_STAT_RANGEOVF1_MASK, /*!< channel1 range status overflow */
+ kPDM_RangeStatusOverFlowCh2 = PDM_RANGE_STAT_RANGEOVF2_MASK, /*!< channel2 range status overflow */
+ kPDM_RangeStatusOverFlowCh3 = PDM_RANGE_STAT_RANGEOVF3_MASK, /*!< channel3 range status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_RangeStatusOverFlowCh4 = PDM_RANGE_STAT_RANGEOVF4_MASK, /*!< channel4 range status overflow */
+ kPDM_RangeStatusOverFlowCh5 = PDM_RANGE_STAT_RANGEOVF5_MASK, /*!< channel5 range status overflow */
+ kPDM_RangeStatusOverFlowCh6 = PDM_RANGE_STAT_RANGEOVF6_MASK, /*!< channel6 range status overflow */
+ kPDM_RangeStatusOverFlowCh7 = PDM_RANGE_STAT_RANGEOVF7_MASK, /*!< channel7 range status overflow */
+#endif
+};
+#else
+/*! @brief The PDM output status */
+enum _pdm_output_status
+{
+ kPDM_OutputStatusUnderFlowCh0 = PDM_OUT_STAT_OUTUNF0_MASK, /*!< channel0 output status underflow */
+ kPDM_OutputStatusUnderFlowCh1 = PDM_OUT_STAT_OUTUNF1_MASK, /*!< channel1 output status underflow */
+ kPDM_OutputStatusUnderFlowCh2 = PDM_OUT_STAT_OUTUNF2_MASK, /*!< channel2 output status underflow */
+ kPDM_OutputStatusUnderFlowCh3 = PDM_OUT_STAT_OUTUNF3_MASK, /*!< channel3 output status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_OutputStatusUnderFlowCh4 = PDM_OUT_STAT_OUTUNF4_MASK, /*!< channel4 output status underflow */
+ kPDM_OutputStatusUnderFlowCh5 = PDM_OUT_STAT_OUTUNF5_MASK, /*!< channel5 output status underflow */
+ kPDM_OutputStatusUnderFlowCh6 = PDM_OUT_STAT_OUTUNF6_MASK, /*!< channel6 output status underflow */
+ kPDM_OutputStatusUnderFlowCh7 = PDM_OUT_STAT_OUTUNF7_MASK, /*!< channel7 output status underflow */
+#endif
+ kPDM_OutputStatusOverFlowCh0 = PDM_OUT_STAT_OUTOVF0_MASK, /*!< channel0 output status overflow */
+ kPDM_OutputStatusOverFlowCh1 = PDM_OUT_STAT_OUTOVF1_MASK, /*!< channel1 output status overflow */
+ kPDM_OutputStatusOverFlowCh2 = PDM_OUT_STAT_OUTOVF2_MASK, /*!< channel2 output status overflow */
+ kPDM_OutputStatusOverFlowCh3 = PDM_OUT_STAT_OUTOVF3_MASK, /*!< channel3 output status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_OutputStatusOverFlowCh4 = PDM_OUT_STAT_OUTOVF4_MASK, /*!< channel4 output status overflow */
+ kPDM_OutputStatusOverFlowCh5 = PDM_OUT_STAT_OUTOVF5_MASK, /*!< channel5 output status overflow */
+ kPDM_OutputStatusOverFlowCh6 = PDM_OUT_STAT_OUTOVF6_MASK, /*!< channel6 output status overflow */
+ kPDM_OutputStatusOverFlowCh7 = PDM_OUT_STAT_OUTOVF7_MASK, /*!< channel7 output status overflow */
+#endif
+};
+#endif
+
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+/*! @brief PDM DC remover configurations */
+typedef enum _pdm_dc_remover
+{
+ kPDM_DcRemoverCutOff20Hz = 0U, /*!< DC remover cut off 20HZ */
+ kPDM_DcRemoverCutOff13Hz = 1U, /*!< DC remover cut off 13.3HZ */
+ kPDM_DcRemoverCutOff40Hz = 2U, /*!< DC remover cut off 40HZ */
+ kPDM_DcRemoverBypass = 3U, /*!< DC remover bypass */
+} pdm_dc_remover_t;
+#else
+/*! @brief PDM DC remover configurations */
+typedef enum _pdm_dc_remover
+{
+ kPDM_DcRemoverCutOff21Hz = 0U, /*!< DC remover cut off 21HZ */
+ kPDM_DcRemoverCutOff83Hz = 1U, /*!< DC remover cut off 83HZ */
+ kPDM_DcRemoverCutOff152Hz = 2U, /*!< DC remover cut off 152HZ */
+ kPDM_DcRemoverBypass = 3U, /*!< DC remover bypass */
+} pdm_dc_remover_t;
+#endif
+
+/*! @brief PDM decimation filter quality mode */
+typedef enum _pdm_df_quality_mode
+{
+ kPDM_QualityModeMedium = 0U, /*!< quality mode memdium */
+ kPDM_QualityModeHigh = 1U, /*!< quality mode high */
+ kPDM_QualityModeLow = 7U, /*!< quality mode low */
+ kPDM_QualityModeVeryLow0 = 6U, /*!< quality mode very low0 */
+ kPDM_QualityModeVeryLow1 = 5U, /*!< quality mode very low1 */
+ kPDM_QualityModeVeryLow2 = 4U, /*!< quality mode very low2 */
+} pdm_df_quality_mode_t;
+
+/*! @brief PDM quality mode K factor */
+enum _pdm_qulaity_mode_k_factor
+{
+ kPDM_QualityModeHighKFactor = 1U, /*!< high quality mode K factor = 1 / 2 */
+ kPDM_QualityModeMediumKFactor = 2U, /*!< medium/very low0 quality mode K factor = 2 / 2 */
+ kPDM_QualityModeLowKFactor = 4U, /*!< low/very low1 quality mode K factor = 4 / 2 */
+ kPDM_QualityModeVeryLow2KFactor = 8U, /*!< very low2 quality mode K factor = 8 / 2 */
+};
+
+/*! @brief PDM decimation filter output gain */
+typedef enum _pdm_df_output_gain
+{
+ kPDM_DfOutputGain0 = 0U, /*!< Decimation filter output gain 0 */
+ kPDM_DfOutputGain1 = 1U, /*!< Decimation filter output gain 1 */
+ kPDM_DfOutputGain2 = 2U, /*!< Decimation filter output gain 2 */
+ kPDM_DfOutputGain3 = 3U, /*!< Decimation filter output gain 3 */
+ kPDM_DfOutputGain4 = 4U, /*!< Decimation filter output gain 4 */
+ kPDM_DfOutputGain5 = 5U, /*!< Decimation filter output gain 5 */
+ kPDM_DfOutputGain6 = 6U, /*!< Decimation filter output gain 6 */
+ kPDM_DfOutputGain7 = 7U, /*!< Decimation filter output gain 7 */
+ kPDM_DfOutputGain8 = 8U, /*!< Decimation filter output gain 8 */
+ kPDM_DfOutputGain9 = 9U, /*!< Decimation filter output gain 9 */
+ kPDM_DfOutputGain10 = 0xAU, /*!< Decimation filter output gain 10 */
+ kPDM_DfOutputGain11 = 0xBU, /*!< Decimation filter output gain 11 */
+ kPDM_DfOutputGain12 = 0xCU, /*!< Decimation filter output gain 12 */
+ kPDM_DfOutputGain13 = 0xDU, /*!< Decimation filter output gain 13 */
+ kPDM_DfOutputGain14 = 0xEU, /*!< Decimation filter output gain 14 */
+ kPDM_DfOutputGain15 = 0xFU, /*!< Decimation filter output gain 15 */
+} pdm_df_output_gain_t;
+
+/*! @brief PDM data width */
+enum _pdm_data_width
+{
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
+ kPDM_DataWwidth24 = 3U, /*!< PDM data width 24bit */
+ kPDM_DataWwidth32 = 4U, /*!< PDM data width 32bit */
+#else
+ kPDM_DataWdith16 = 2U, /*!< PDM data width 16bit */
+#endif
+};
+
+/*! @brief PDM channel configurations */
+typedef struct _pdm_channel_config
+{
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+ pdm_dc_remover_t outputCutOffFreq; /*!< PDM output DC remover cut off frequency */
+#endif
+
+#if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
+ pdm_dc_remover_t cutOffFreq; /*!< DC remover cut off frequency */
+#endif
+
+ pdm_df_output_gain_t gain; /*!< Decimation Filter Output Gain */
+} pdm_channel_config_t;
+
+/*! @brief PDM user configuration structure */
+typedef struct _pdm_config
+{
+ bool
+ enableDoze; /*!< This module will enter disable/low leakage mode if DOZEN is active with ipg_doze is asserted */
+ uint8_t fifoWatermark; /*!< Watermark value for FIFO */
+ pdm_df_quality_mode_t qualityMode; /*!< Quality mode */
+ uint8_t cicOverSampleRate; /*!< CIC filter over sampling rate */
+} pdm_config_t;
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief PDM voice activity detector interrupt type */
+enum _pdm_hwvad_interrupt_enable
+{
+ kPDM_HwvadErrorInterruptEnable = PDM_VAD0_CTRL_1_VADERIE_MASK, /*!< PDM channel HWVAD error interrupt enable. */
+ kPDM_HwvadInterruptEnable = PDM_VAD0_CTRL_1_VADIE_MASK, /*!< PDM channel HWVAD interrupt */
+};
+
+/*! @brief The PDM hwvad interrupt status flag */
+enum _pdm_hwvad_int_status
+{
+ kPDM_HwvadStatusInputSaturation = PDM_VAD0_STAT_VADINSATF_MASK, /*!< HWVAD saturation condition */
+ kPDM_HwvadStatusVoiceDetectFlag = PDM_VAD0_STAT_VADIF_MASK, /*!< HWVAD voice detect interrupt triggered */
+};
+
+/*! @brief High pass filter configure cut-off frequency*/
+typedef enum _pdm_hwvad_hpf_config
+{
+ kPDM_HwvadHpfBypassed = 0x0U, /*!< High-pass filter bypass */
+ kPDM_HwvadHpfCutOffFreq1750Hz = 0x1U, /*!< High-pass filter cut off frequency 1750HZ */
+ kPDM_HwvadHpfCutOffFreq215Hz = 0x2U, /*!< High-pass filter cut off frequency 215HZ */
+ kPDM_HwvadHpfCutOffFreq102Hz = 0x3U, /*!< High-pass filter cut off frequency 102HZ */
+} pdm_hwvad_hpf_config_t;
+
+/*! @brief HWVAD internal filter status */
+typedef enum _pdm_hwvad_filter_status
+{
+ kPDM_HwvadInternalFilterNormalOperation = 0U, /*!< internal filter ready for normal operation */
+ kPDM_HwvadInternalFilterInitial = PDM_VAD0_CTRL_1_VADST10_MASK, /*!< interla filter are initial */
+} pdm_hwvad_filter_status_t;
+
+/*! @brief PDM voice activity detector user configuration structure */
+typedef struct _pdm_hwvad_config
+{
+ uint8_t channel; /*!< Which channel uses voice activity detector */
+ uint8_t initializeTime; /*!< Number of frames or samples to initialize voice activity detector. */
+ uint8_t cicOverSampleRate; /*!< CIC filter over sampling rate */
+
+ uint8_t inputGain; /*!< Voice activity detector input gain */
+ uint32_t frameTime; /*!< Voice activity frame time */
+ pdm_hwvad_hpf_config_t cutOffFreq; /*!< High pass filter cut off frequency */
+ bool enableFrameEnergy; /*!< If frame energy enabled, true means enable */
+ bool enablePreFilter; /*!< If pre-filter enabled */
+} pdm_hwvad_config_t;
+
+/*! @brief PDM voice activity detector noise filter user configuration structure */
+typedef struct _pdm_hwvad_noise_filter
+{
+ bool enableAutoNoiseFilter; /*!< If noise fileter automatically activated, true means enable */
+ bool enableNoiseMin; /*!< If Noise minimum block enabled, true means enabled */
+ bool enableNoiseDecimation; /*!< If enable noise input decimation */
+ bool enableNoiseDetectOR; /*!< Enables a OR logic in the output of minimum noise estimator block */
+ uint32_t noiseFilterAdjustment; /*!< The adjustment value of the noise filter */
+ uint32_t noiseGain; /*!< Gain value for the noise energy or envelope estimated */
+} pdm_hwvad_noise_filter_t;
+
+/*! @brief PDM voice activity detector zero cross detector result */
+typedef enum _pdm_hwvad_zcd_result
+{
+ kPDM_HwvadResultOREnergyBasedDetection =
+ 0U, /*!< zero cross detector result will be OR with energy based detection */
+ kPDM_HwvadResultANDEnergyBasedDetection =
+ 1U, /*!< zero cross detector result will be AND with energy based detection */
+} pdm_hwvad_zcd_result_t;
+
+/*! @brief PDM voice activity detector zero cross detector configuration structure */
+typedef struct _pdm_hwvad_zero_cross_detector
+{
+ bool enableAutoThreshold; /*!< If ZCD auto-threshold enabled, true means enabled. */
+ pdm_hwvad_zcd_result_t zcdAnd; /*!< Is ZCD result is AND'ed with energy-based detection, false means OR'ed */
+ uint32_t threshold; /*!< The adjustment value of the noise filter */
+ uint32_t adjustmentThreshold; /*!< Gain value for the noise energy or envelope estimated */
+} pdm_hwvad_zero_cross_detector_t;
+#endif
+
+/*! @brief PDM SDMA transfer structure */
+typedef struct _pdm_transfer
+{
+ volatile uint8_t *data; /*!< Data start address to transfer. */
+ volatile size_t dataSize; /*!< Total Transfer bytes size. */
+} pdm_transfer_t;
+
+/*! @brief PDM handle */
+typedef struct _pdm_handle pdm_handle_t;
+
+/*! @brief PDM transfer callback prototype */
+typedef void (*pdm_transfer_callback_t)(PDM_Type *base, pdm_handle_t *handle, status_t status, void *userData);
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief PDM HWVAD callback prototype */
+typedef void (*pdm_hwvad_callback_t)(status_t status, void *userData);
+/*! @brief PDM HWVAD notification structure */
+typedef struct _pdm_hwvad_notification
+{
+ pdm_hwvad_callback_t callback;
+ void *userData;
+} pdm_hwvad_notification_t;
+#endif
+
+/*! @brief PDM handle structure */
+struct _pdm_handle
+{
+ uint32_t state; /*!< Transfer status */
+ pdm_transfer_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+
+ pdm_transfer_t pdmQueue[PDM_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[PDM_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+
+ uint32_t format; /*!< data format */
+ uint8_t watermark; /*!< Watermark value */
+ uint8_t startChannel; /*!< end channel */
+ uint8_t channelNums; /*!< Enabled channel number */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM peripheral.
+ *
+ * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * PDM_GetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base PDM base pointer
+ * @param config PDM configuration structure.
+ */
+void PDM_Init(PDM_Type *base, const pdm_config_t *config);
+
+/*!
+ * @brief De-initializes the PDM peripheral.
+ *
+ * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
+ * is called to enable the clock.
+ *
+ * @param base PDM base pointer
+ */
+void PDM_Deinit(PDM_Type *base);
+
+/*!
+ * @brief Resets the PDM module.
+ *
+ * @param base PDM base pointer
+ */
+static inline void PDM_Reset(PDM_Type *base)
+{
+ base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
+}
+
+/*!
+ * @brief Enables/disables PDM interface.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is enabled, false means PDM interface is disabled.
+ */
+static inline void PDM_Enable(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_PDMIEN_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_PDMIEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables DOZE.
+ *
+ * @param base PDM base pointer
+ * @param enable True means the module will enter Disable/Low Leakage mode when ipg_doze is asserted, false means the
+ * module will not enter Disable/Low Leakage mode when ipg_doze is asserted.
+ */
+static inline void PDM_EnableDoze(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DOZEN_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DOZEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables debug mode for PDM.
+ * The PDM interface cannot enter debug mode once in Disable/Low Leakage or Low Power mode.
+ * @param base PDM base pointer
+ * @param enable True means PDM interface enter debug mode, false means PDM interface in normal mode.
+ */
+static inline void PDM_EnableDebugMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DBG_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DBG_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables PDM interface in debug mode.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is enabled debug mode, false means PDM interface is disabled after
+ * after completing the current frame in debug mode.
+ */
+static inline void PDM_EnableInDebugMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DBGE_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DBGE_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables PDM interface disable/Low Leakage mode.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is in disable/low leakage mode, False means PDM interface is in normal mode.
+ */
+static inline void PDM_EnterLowLeakageMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_MDIS_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_MDIS_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables the PDM channel.
+ *
+ * @param base PDM base pointer
+ * @param channel PDM channel number need to enable or disable.
+ * @param enable True means enable PDM channel, false means disable.
+ */
+static inline void PDM_EnableChannel(PDM_Type *base, uint8_t channel, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= (1UL << channel);
+ }
+ else
+ {
+ base->CTRL_1 &= ~(1UL << channel);
+ }
+}
+
+/*!
+ * @brief PDM one channel configurations.
+ *
+ * @param base PDM base pointer
+ * @param config PDM channel configurations.
+ * @param channel channel number.
+ * after completing the current frame in debug mode.
+ */
+void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config);
+
+/*!
+ * @brief PDM set sample rate.
+ *
+ * @note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
+ * @code
+ * PDM_Init(base, pdmConfig)
+ * PDM_SetChannelConfig(base, channel, &channelConfig)
+ * PDM_SetSampleRateConfig(base, source, sampleRate)
+ * @endcode
+ * @param base PDM base pointer
+ * @param sourceClock_HZ PDM source clock frequency.
+ * @param sampleRate_HZ PDM sample rate.
+ */
+status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ);
+
+/*!
+ * @brief PDM set sample rate.
+ *
+ * @deprecated Do not use this function. It has been superceded by @ref PDM_SetSampleRateConfig
+ * @param base PDM base pointer
+ * @param enableChannelMask PDM channel enable mask.
+ * @param qualityMode quality mode.
+ * @param osr cic oversample rate
+ * @param clkDiv clock divider
+ */
+status_t PDM_SetSampleRate(
+ PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv);
+
+/*!
+ * @brief Get the instance number for PDM.
+ *
+ * @param base PDM base pointer.
+ */
+uint32_t PDM_GetInstance(PDM_Type *base);
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the PDM internal status flag.
+ * Use the Status Mask in _pdm_internal_status to get the status value needed
+ * @param base PDM base pointer
+ * @return PDM status flag value.
+ */
+static inline uint32_t PDM_GetStatus(PDM_Type *base)
+{
+ return base->STAT;
+}
+
+/*!
+ * @brief Gets the PDM FIFO status flag.
+ * Use the Status Mask in _pdm_fifo_status to get the status value needed
+ * @param base PDM base pointer
+ * @return FIFO status.
+ */
+static inline uint32_t PDM_GetFifoStatus(PDM_Type *base)
+{
+ return base->FIFO_STAT;
+}
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*!
+ * @brief Gets the PDM Range status flag.
+ * Use the Status Mask in _pdm_range_status to get the status value needed
+ * @param base PDM base pointer
+ * @return output status.
+ */
+static inline uint32_t PDM_GetRangeStatus(PDM_Type *base)
+{
+ return base->RANGE_STAT;
+}
+#else
+/*!
+ * @brief Gets the PDM output status flag.
+ * Use the Status Mask in _pdm_output_status to get the status value needed
+ * @param base PDM base pointer
+ * @return output status.
+ */
+static inline uint32_t PDM_GetOutputStatus(PDM_Type *base)
+{
+ return base->OUT_STAT;
+}
+#endif
+
+/*!
+ * @brief Clears the PDM Tx status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status between kPDM_StatusFrequencyLow and
+ * kPDM_StatusCh7FifoDataAvaliable.
+ */
+static inline void PDM_ClearStatus(PDM_Type *base, uint32_t mask)
+{
+ base->STAT = mask;
+}
+
+/*!
+ * @brief Clears the PDM Tx status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask.It can be a combination of the status in _pdm_fifo_status.
+ */
+static inline void PDM_ClearFIFOStatus(PDM_Type *base, uint32_t mask)
+{
+ base->FIFO_STAT = mask;
+}
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*!
+ * @brief Clears the PDM range status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status in _pdm_range_status.
+ */
+static inline void PDM_ClearRangeStatus(PDM_Type *base, uint32_t mask)
+{
+ base->RANGE_STAT = mask;
+}
+#else
+/*!
+ * @brief Clears the PDM output status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status in _pdm_output_status.
+ */
+static inline void PDM_ClearOutputStatus(PDM_Type *base, uint32_t mask)
+{
+ base->OUT_STAT = mask;
+}
+#endif
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the PDM interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_ErrorInterruptEnable
+ * @arg kPDM_FIFOInterruptEnable
+ */
+void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the PDM interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_ErrorInterruptEnable
+ * @arg kPDM_FIFOInterruptEnable
+ */
+static inline void PDM_DisableInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->CTRL_1 &= ~mask;
+}
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the PDM DMA requests.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void PDM_EnableDMA(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | PDM_CTRL_1_DISEL(0x1U);
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DISEL_MASK;
+ }
+}
+
+/*!
+ * @brief Gets the PDM data register address.
+ *
+ * This API is used to provide a transfer address for the PDM DMA transfer configuration.
+ *
+ * @param base PDM base pointer.
+ * @param channel Which data channel used.
+ * @return data register address.
+ */
+static inline uint32_t PDM_GetDataRegisterAddress(PDM_Type *base, uint32_t channel)
+{
+ return (uint32_t)(&(base->DATACH)[channel]);
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
+/*!
+ * @brief Reads data from the PDM FIFO.
+ *
+ * @param base PDM base pointer.
+ * @param channel Data channel used.
+ * @return Data in PDM FIFO.
+ */
+static inline int16_t PDM_ReadData(PDM_Type *base, uint32_t channel)
+{
+ return (int16_t)(base->DATACH[channel]);
+}
+
+/*!
+ * @brief PDM read data non blocking.
+ * So the actually read data byte size in this function is (size * 2 * channelNums).
+ * @param base PDM base pointer.
+ * @param startChannel start channel number.
+ * @param channelNums total enabled channelnums.
+ * @param buffer received buffer address.
+ * @param size number of 16bit data to read.
+ */
+void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size);
+#endif
+
+/*!
+ * @brief PDM read fifo.
+ * @note: This function support 16 bit only for IP version that only supports 16bit.
+ *
+ * @param base PDM base pointer.
+ * @param startChannel start channel number.
+ * @param channelNums total enabled channelnums.
+ * @param buffer received buffer address.
+ * @param size number of samples to read.
+ * @param dataWidth sample width.
+ */
+void PDM_ReadFifo(
+ PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth);
+
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 4U)
+/*!
+ * @brief Reads data from the PDM FIFO.
+ *
+ * @param base PDM base pointer.
+ * @param channel Data channel used.
+ * @return Data in PDM FIFO.
+ */
+static inline uint32_t PDM_ReadData(PDM_Type *base, uint32_t channel)
+{
+ return base->DATACH[channel];
+}
+#endif
+
+/*!
+ * @brief Set the PDM channel gain.
+ *
+ * Please note for different quality mode, the valid gain value is different, reference RM for detail.
+ * @param base PDM base pointer.
+ * @param channel PDM channel index.
+ * @param gain channel gain, the register gain value range is 0 - 15.
+ */
+void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain);
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @} */
+
+/*!
+ * @name Voice Activity Detector
+ * @{
+ */
+
+/*!
+ * @brief Configure voice activity detector.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector configure structure pointer .
+ */
+void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config);
+
+/*!
+ * @brief PDM hwvad force output disable.
+ *
+ * @param base PDM base pointer
+ * @param enable true is output force disable, false is output not force.
+ */
+static inline void PDM_ForceHwvadOutputDisable(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_CTRL_2 &= ~PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
+ }
+ else
+ {
+ base->VAD0_CTRL_2 |= PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
+ }
+}
+
+/*!
+ * @brief PDM hwvad reset.
+ * It will reset VADNDATA register and will clean all internal buffers, should be called when the PDM isn't running.
+ *
+ * @param base PDM base pointer
+ */
+static inline void PDM_ResetHwvad(PDM_Type *base)
+{
+ base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADRST_MASK;
+}
+/*!
+ * @brief Enable/Disable Voice activity detector.
+ * Should be called when the PDM isn't running.
+ * @param base PDM base pointer.
+ * @param enable True means enable voice activity detector, false means disable.
+ */
+static inline void PDM_EnableHwvad(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADEN_MASK;
+ }
+ else
+ {
+ base->VAD0_CTRL_1 &= ~PDM_VAD0_CTRL_1_VADEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables the PDM Voice Detector interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_HWVADErrorInterruptEnable
+ * @arg kPDM_HWVADInterruptEnable
+ */
+static inline void PDM_EnableHwvadInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_CTRL_1 |= mask;
+}
+
+/*!
+ * @brief Disables the PDM Voice Detector interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_HWVADErrorInterruptEnable
+ * @arg kPDM_HWVADInterruptEnable
+ */
+static inline void PDM_DisableHwvadInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_CTRL_1 &= ~mask;
+}
+
+/*!
+ * @brief Clears the PDM voice activity detector status flags.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask,reference _pdm_hwvad_int_status.
+ */
+static inline void PDM_ClearHwvadInterruptStatusFlags(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_STAT = mask;
+}
+
+/*!
+ * @brief Clears the PDM voice activity detector status flags.
+ *
+ * @param base PDM base pointer
+ * @return status, reference _pdm_hwvad_int_status
+ */
+static inline uint32_t PDM_GetHwvadInterruptStatusFlags(PDM_Type *base)
+{
+ return base->VAD0_STAT & (PDM_VAD0_STAT_VADIF_MASK | PDM_VAD0_STAT_VADINSATF_MASK);
+}
+
+/*!
+ * @brief Get the PDM voice activity detector initial flags.
+ *
+ * @param base PDM base pointer
+ * @return initial flag.
+ */
+static inline uint32_t PDM_GetHwvadInitialFlag(PDM_Type *base)
+{
+ return base->VAD0_STAT & PDM_VAD0_STAT_VADINITF_MASK;
+}
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_VADEF) && (FSL_FEATURE_PDM_HAS_NO_VADEF))
+/*!
+ * @brief Get the PDM voice activity detector voice detected flags.
+ * NOte: this flag is auto cleared when voice gone.
+ * @param base PDM base pointer
+ * @return voice detected flag.
+ */
+static inline uint32_t PDM_GetHwvadVoiceDetectedFlag(PDM_Type *base)
+{
+ return base->VAD0_STAT & PDM_VAD0_STAT_VADEF_MASK;
+}
+#endif
+
+/*!
+ * @brief Enables/disables voice activity detector signal filter.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable signal filter, false means disable.
+ */
+static inline void PDM_EnableHwvadSignalFilter(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_SCONFIG |= PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ }
+ else
+ {
+ base->VAD0_SCONFIG &= ~PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configure voice activity detector signal filter.
+ *
+ * @param base PDM base pointer
+ * @param enableMaxBlock If signal maximum block enabled.
+ * @param signalGain Gain value for the signal energy.
+ */
+void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain);
+
+/*!
+ * @brief Configure voice activity detector noise filter.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector noise filter configure structure pointer .
+ */
+void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config);
+
+/*!
+ * @brief Enables/disables voice activity detector zero cross detector.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable zero cross detector, false means disable.
+ */
+static inline void PDM_EnableHwvadZeroCrossDetector(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_ZCD |= PDM_VAD0_ZCD_VADZCDEN_MASK;
+ }
+ else
+ {
+ base->VAD0_ZCD &= ~PDM_VAD0_ZCD_VADZCDEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configure voice activity detector zero cross detector.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector zero cross detector configure structure pointer .
+ */
+void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config);
+
+/*!
+ * @brief Reads noise data.
+ *
+ * @param base PDM base pointer.
+ * @return Data in PDM noise data register.
+ */
+static inline uint16_t PDM_GetNoiseData(PDM_Type *base)
+{
+ return (uint16_t)base->VAD0_NDATA;
+}
+
+/*!
+ * @brief set hwvad internal filter status .
+ * Note: filter initial status should be asserted for two more cycles, then set it to normal operation.
+ * @param base PDM base pointer.
+ * @param status internal filter status.
+ */
+static inline void PDM_SetHwvadInternalFilterStatus(PDM_Type *base, pdm_hwvad_filter_status_t status)
+{
+ base->VAD0_CTRL_1 = (base->VAD0_CTRL_1 & (~PDM_VAD0_CTRL_1_VADST10_MASK)) | (uint32_t)status;
+}
+
+/*!
+ * @brief set HWVAD in envelope based mode .
+ * Recommand configurations,
+ * @code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = false,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = false,
+ * .enableNoiseMin = true,
+ * .enableNoiseDecimation = true,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = true,
+ * };
+ * @endcode
+ * @param base PDM base pointer.
+ * @param hwvadConfig internal filter status.
+ * @param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * @param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * @param signalGain signal gain value.
+ */
+void PDM_SetHwvadInEnvelopeBasedMode(PDM_Type *base,
+ const pdm_hwvad_config_t *hwvadConfig,
+ const pdm_hwvad_noise_filter_t *noiseConfig,
+ const pdm_hwvad_zero_cross_detector_t *zcdConfig,
+ uint32_t signalGain);
+
+/*!
+ * brief set HWVAD in energy based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = true,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = true,
+ * .enableNoiseMin = false,
+ * .enableNoiseDecimation = false,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = false,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value, signal gain value should be properly according to application.
+ */
+void PDM_SetHwvadInEnergyBasedMode(PDM_Type *base,
+ const pdm_hwvad_config_t *hwvadConfig,
+ const pdm_hwvad_noise_filter_t *noiseConfig,
+ const pdm_hwvad_zero_cross_detector_t *zcdConfig,
+ uint32_t signalGain);
+
+/*!
+ * @brief Enable/Disable hwvad callback.
+
+ * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
+ *
+ * @param base Base address of the PDM peripheral.
+ * @param vadCallback callback Pointer to store callback function, should be NULL when disable.
+ * @param userData user data.
+ * @param enable true is enable, false is disable.
+ * @retval None.
+ */
+void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable);
+/*! @} */
+#endif
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM handle.
+ *
+ * This function initializes the handle for the PDM transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function.
+ */
+void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData);
+
+/*!
+ * @brief PDM set channel transfer config.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM handle pointer.
+ * @param channel PDM channel.
+ * @param config channel config.
+ * @param format data format, support data width configurations,_pdm_data_width.
+ * @retval kStatus_PDM_ChannelConfig_Failed or kStatus_Success.
+ */
+status_t PDM_TransferSetChannelConfig(
+ PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on PDM.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
+ * is finished.
+ *
+ * @param base PDM base pointer
+ * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the pdm_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_PDM_Busy Previous receive still not finished.
+ */
+status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the current IRQ receive.
+ *
+ * @note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base PDM base pointer
+ * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ */
+void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base PDM base pointer.
+ * @param handle Pointer to the pdm_handle_t structure.
+ */
+void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_PDM_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c
new file mode 100644
index 0000000000..3c8104b5f3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pdm_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pdm_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32) & ~0x1FU)
+
+/*<! Structure definition for pdm_edma_private_handle_t. The structure is private. */
+typedef struct _pdm_edma_private_handle
+{
+ PDM_Type *base;
+ pdm_edma_handle_t *handle;
+} pdm_edma_private_handle_t;
+
+/*! @brief pdm transfer state */
+enum _pdm_edma_transfer_state
+{
+ kPDM_Busy = 0x0U, /*!< PDM is busy */
+ kPDM_Idle, /*!< Transfer is done. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief PDM EDMA callback for receive.
+ *
+ * @param handle pointer to pdm_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void PDM_EDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief Mapping the enabled channel to a number power of 2.
+ *
+ * @param channel PDM channel number.
+ */
+static edma_modulo_t PDM_TransferMappingChannel(uint32_t *channel);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief pdm base address pointer */
+static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
+/*<! Private handle only used for internally. */
+static pdm_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_pdmBases)];
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static edma_modulo_t PDM_TransferMappingChannel(uint32_t *channel)
+{
+ edma_modulo_t modulo = kEDMA_ModuloDisable;
+#if FSL_FEATURE_PDM_CHANNEL_NUM == 8U
+ if (*channel == 2U)
+ {
+ modulo = kEDMA_Modulo8bytes;
+ }
+ else if ((*channel == 3U) || (*channel == 4U))
+ {
+ *channel = 4U;
+ modulo = kEDMA_Modulo16bytes;
+ }
+ else
+ {
+ modulo = kEDMA_ModuloDisable;
+ }
+#endif
+
+ return modulo;
+}
+
+static void PDM_EDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ pdm_edma_private_handle_t *privHandle = (pdm_edma_private_handle_t *)userData;
+ pdm_edma_handle_t *pdmHandle = privHandle->handle;
+
+ if (!(pdmHandle->isLoopTransfer))
+ {
+ (void)memset(&pdmHandle->tcd[pdmHandle->tcdDriver], 0, sizeof(edma_tcd_t));
+ pdmHandle->tcdDriver = (pdmHandle->tcdDriver + 1U) % pdmHandle->tcdNum;
+ }
+
+ pdmHandle->receivedBytes +=
+ pdmHandle->tcd[pdmHandle->tcdDriver].BITER * (pdmHandle->tcd[pdmHandle->tcdDriver].NBYTES & 0x3FFU);
+
+ /* If finished a block, call the callback function */
+ if (pdmHandle->callback != NULL)
+ {
+ (pdmHandle->callback)(privHandle->base, pdmHandle, kStatus_PDM_Idle, pdmHandle->userData);
+ }
+
+ pdmHandle->tcdUsedNum--;
+ /* If all data finished, just stop the transfer */
+ if ((pdmHandle->tcdUsedNum == 0U) && !(pdmHandle->isLoopTransfer))
+ {
+ /* Disable DMA enable bit */
+ PDM_EnableDMA(privHandle->base, false);
+ EDMA_AbortTransfer(handle);
+ }
+}
+
+/*!
+ * brief Initializes the PDM Rx eDMA handle.
+ *
+ * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ * param base PDM peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void PDM_TransferCreateHandleEDMA(
+ PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ uint32_t instance = PDM_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set pdm base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set PDM state to idle */
+ handle->state = (uint32_t)kPDM_Idle;
+
+ s_edmaPrivateHandle[instance].base = base;
+ s_edmaPrivateHandle[instance].handle = handle;
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, PDM_EDMACallback, &s_edmaPrivateHandle[instance]);
+}
+
+/*!
+ * brief Initializes the multi PDM channel interleave type.
+ *
+ * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would
+ * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample always
+ *
+ * param handle PDM eDMA handle pointer.
+ * param multiChannelInterleaveType Multi channel interleave type.
+ */
+void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle,
+ pdm_edma_multi_channel_interleave_t multiChannelInterleaveType)
+{
+ handle->interleaveType = multiChannelInterleaveType;
+}
+
+/*!
+ * brief Install EDMA descriptor memory.
+ *
+ * param handle Pointer to EDMA channel transfer handle.
+ * param tcdAddr EDMA head descriptor address.
+ * param tcdNum EDMA link descriptor address.
+ */
+void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum)
+{
+ assert(handle != NULL);
+
+ handle->tcd = (edma_tcd_t *)tcdAddr;
+ handle->tcdNum = tcdNum;
+}
+
+/*!
+ * brief Configures the PDM channel.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ * param channel channel index.
+ * param pdmConfig pdm channel configurations.
+ */
+void PDM_TransferSetChannelConfigEDMA(PDM_Type *base,
+ pdm_edma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config)
+{
+ assert((handle != NULL) && (config != NULL));
+ assert(channel < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+ /* Configure the PDM channel */
+ PDM_SetChannelConfig(base, channel, config);
+
+ /* record end channel number */
+ handle->endChannel = (uint8_t)channel;
+ /* increase totoal enabled channel number */
+ handle->channelNums++;
+ /* increase count pre channel numbers */
+ handle->count = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
+}
+
+/*!
+ * brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * 1. Scatter gather case:
+ * This functio support dynamic scatter gather and staic scatter gather,
+ * a. for the dynamic scatter gather case:
+ * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit
+ *before the previous one finish. b. for the static scatter gather case: Application should use the link transfer
+ *feature and make sure a loop link transfer is provided, such as: code pdm_edma_transfer_t pdmXfer[2] =
+ * {
+ * {
+ * .data = s_buffer,
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[1],
+ * },
+ *
+ * {
+ * .data = &s_buffer[BUFFER_SIZE],
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[0]
+ * },
+ * };
+ *endcode
+ *
+ * 2. Multi channel case:
+ * This function support receive multi pdm channel data, for example, if two channel is requested,
+ * code
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig);
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig);
+ * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer);
+ * endcode
+ * The output data will be formatted as below if handle->interleaveType =
+ *kPDM_EDMAMultiChannelInterleavePerChannelSample :
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ *
+ * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock
+ *:
+ * ----------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5
+ *|....|
+ * ----------------------------------------------------------------------------------------------------------------------
+ * Note: the dataSize of xfer is the total data size, while application using
+ * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize /
+ * channelNums, there are limitation for this feature,
+ * 1. For 3 DMIC array: the dataSize shall be 4 * (channelSize)
+ * The addtional buffer is mandantory for edma modulo feature.
+ * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only,
+ * 2 DMIC array: CHANNEL3, CHANNEL4
+ * 3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5
+ * 4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6
+ * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4
+ * MAXIMUM DMIC CHANNELS.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a PDM eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t startAddr = PDM_GetDataRegisterAddress(base, handle->endChannel - (handle->channelNums - 1UL));
+ pdm_edma_transfer_t *currentTransfer = xfer;
+ uint32_t nextTcdIndex = 0U, tcdIndex = handle->tcdUser, destOffset = FSL_FEATURE_PDM_FIFO_WIDTH;
+ uint32_t mappedChannel = handle->channelNums;
+ edma_modulo_t modulo = kEDMA_ModuloDisable;
+ /* minor offset used for channel sample interleave transfer */
+ edma_minor_offset_config_t minorOffset = {
+ .enableSrcMinorOffset = true,
+ .enableDestMinorOffset = false,
+ .minorOffset = 0xFFFFFU - mappedChannel * (uint32_t)FSL_FEATURE_PDM_FIFO_OFFSET + 1U};
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->interleaveType == kPDM_EDMAMultiChannelInterleavePerChannelBlock) && (mappedChannel > 1U))
+ {
+ /* Limitation of the feature, reference the API comments */
+ if (((startAddr & 0xFU) != 0U) || (mappedChannel > 4U))
+ {
+ return kStatus_InvalidArgument;
+ }
+ modulo = PDM_TransferMappingChannel(&mappedChannel);
+ if ((xfer->dataSize % mappedChannel) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+ destOffset = xfer->dataSize / mappedChannel;
+ /* reconfigure the minor loop offset for channel block interleave */
+ minorOffset.enableSrcMinorOffset = false, minorOffset.enableDestMinorOffset = true,
+ minorOffset.minorOffset =
+ 0xFFFFFU - mappedChannel * (uint32_t)destOffset + (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH + 1U;
+ }
+
+ while (currentTransfer != NULL)
+ {
+ if (handle->tcdUsedNum >= handle->tcdNum)
+ {
+ return kStatus_PDM_QueueFull;
+ }
+ else
+ {
+ uint32_t primask = DisableGlobalIRQ();
+ handle->tcdUsedNum++;
+ EnableGlobalIRQ(primask);
+ }
+
+ nextTcdIndex = (handle->tcdUser + 1U) % handle->tcdNum;
+
+ if (mappedChannel == 1U)
+ {
+ EDMA_PrepareTransferConfig(&config, (void *)(uint32_t *)startAddr, FSL_FEATURE_PDM_FIFO_WIDTH, 0,
+ (uint8_t *)(uint32_t)currentTransfer->data, FSL_FEATURE_PDM_FIFO_WIDTH,
+ FSL_FEATURE_PDM_FIFO_WIDTH, handle->count * (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH,
+ currentTransfer->dataSize);
+ }
+ else
+ {
+ EDMA_PrepareTransferConfig(&config, (void *)(uint32_t *)startAddr, FSL_FEATURE_PDM_FIFO_WIDTH,
+ FSL_FEATURE_PDM_FIFO_OFFSET, (uint8_t *)(uint32_t)currentTransfer->data,
+ FSL_FEATURE_PDM_FIFO_WIDTH, (int16_t)destOffset,
+ mappedChannel * (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH, currentTransfer->dataSize);
+ }
+
+ EDMA_TcdSetTransferConfig((edma_tcd_t *)&handle->tcd[handle->tcdUser], &config,
+ (edma_tcd_t *)&handle->tcd[nextTcdIndex]);
+
+ if (mappedChannel > 1U)
+ {
+ EDMA_TcdSetMinorOffsetConfig((edma_tcd_t *)&handle->tcd[handle->tcdUser], &minorOffset);
+
+ if (handle->interleaveType == kPDM_EDMAMultiChannelInterleavePerChannelBlock)
+ {
+ EDMA_TcdSetModulo((edma_tcd_t *)&handle->tcd[handle->tcdUser], modulo, kEDMA_ModuloDisable);
+ }
+ }
+
+ EDMA_TcdEnableInterrupts((edma_tcd_t *)&handle->tcd[handle->tcdUser], (uint32_t)kEDMA_MajorInterruptEnable);
+
+ handle->tcdUser = nextTcdIndex;
+
+ currentTransfer = currentTransfer->linkTransfer;
+
+ if (currentTransfer == xfer)
+ {
+ handle->isLoopTransfer = true;
+ break;
+ }
+ }
+
+ if (handle->state != (uint32_t)kPDM_Busy)
+ {
+ EDMA_InstallTCD(handle->dmaHandle->base, handle->dmaHandle->channel, (edma_tcd_t *)&handle->tcd[tcdIndex]);
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ PDM_EnableDMA(base, true);
+ /* enable PDM */
+ PDM_Enable(base, true);
+
+ handle->state = (uint32_t)kPDM_Busy;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a PDM receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ PDM_EnableDMA(base, false);
+
+ /* Disable PDM */
+ PDM_Enable(base, false);
+
+ /* Handle the queue index */
+ handle->tcdUsedNum--;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kPDM_Idle;
+}
+
+/*!
+ * brief Terminate all PDM receive.
+ *
+ * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the
+ * current transfer slot, please call PDM_TransferAbortReceiveEDMA.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ PDM_TransferAbortReceiveEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(edma_tcd_t) * handle->tcdNum);
+ handle->tcdUser = 0U;
+ handle->tcdUsedNum = 0U;
+}
+
+/*!
+ * brief Gets byte count received by PDM.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ * param count Bytes count received by PDM.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ *count = handle->receivedBytes;
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h
new file mode 100644
index 0000000000..4da78192f9
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2019 - 2020, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PDM_EDMA_H_
+#define _FSL_PDM_EDMA_H_
+
+#include "fsl_edma.h"
+#include "fsl_pdm.h"
+
+/*!
+ * @addtogroup pdm_edma PDM EDMA Driver
+ * @ingroup pdm
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 1)) /*!< Version 2.6.1 */
+/*@}*/
+
+/*! @brief PDM edma handler */
+typedef struct _pdm_edma_handle pdm_edma_handle_t;
+
+/*!@brief pdm multi channel interleave type */
+typedef enum _pdm_edma_multi_channel_interleave
+{
+ kPDM_EDMAMultiChannelInterleavePerChannelSample =
+ 0U, /*!< multi channel PDM data interleave per channel sample
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ */
+ kPDM_EDMAMultiChannelInterleavePerChannelBlock =
+ 1U, /*!< multi channel PDM data interleave per channel block
+ * ----------------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL0 | CHANNEL0 | ...... | CHANNEL1 | CHANNEL 1 | CHANNEL 1 | ....| CHANNEL2 | CHANNEL 2
+ * | CHANNEL 2 | ....|
+ * ----------------------------------------------------------------------------------------------------------------------------
+ */
+} pdm_edma_multi_channel_interleave_t;
+
+/*! @brief PDM edma transfer */
+typedef struct _pdm_edma_transfer
+{
+ volatile uint8_t *data; /*!< Data start address to transfer. */
+ volatile size_t dataSize; /*!< Total Transfer bytes size. */
+ struct _pdm_edma_transfer *linkTransfer; /*!< linked transfer configurations */
+} pdm_edma_transfer_t;
+
+/*! @brief PDM eDMA transfer callback function for finish and error */
+typedef void (*pdm_edma_callback_t)(PDM_Type *base, pdm_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/
+struct _pdm_edma_handle
+{
+ edma_handle_t *dmaHandle; /*!< DMA handler for PDM send */
+ uint8_t count; /*!< The transfer data count in a DMA request */
+ uint32_t receivedBytes; /*!< total transfer count */
+ uint32_t state; /*!< Internal state for PDM eDMA transfer */
+ pdm_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ bool isLoopTransfer; /*!< loop transfer */
+ void *userData; /*!< User callback parameter */
+ edma_tcd_t *tcd; /*!< TCD pool for eDMA transfer. */
+ uint32_t tcdNum; /*!< TCD number */
+ uint32_t tcdUser; /*!< Index for user to queue transfer. */
+ uint32_t tcdDriver; /*!< Index for driver to get the transfer data and size */
+ volatile uint32_t tcdUsedNum; /*!< Index for user to queue transfer. */
+
+ pdm_edma_multi_channel_interleave_t interleaveType; /*!< multi channel transfer interleave type */
+
+ uint8_t endChannel; /*!< The last enabled channel */
+ uint8_t channelNums; /*!< total channel numbers */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PDM eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Install EDMA descriptor memory.
+ *
+ * @param handle Pointer to EDMA channel transfer handle.
+ * @param tcdAddr EDMA head descriptor address.
+ * @param tcdNum EDMA link descriptor address.
+ */
+void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum);
+
+/*!
+ * @brief Initializes the PDM Rx eDMA handle.
+ *
+ * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void PDM_TransferCreateHandleEDMA(
+ PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Initializes the multi PDM channel interleave type.
+ *
+ * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would
+ * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample always
+ *
+ * @param handle PDM eDMA handle pointer.
+ * @param multiChannelInterleaveType Multi channel interleave type.
+ */
+void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle,
+ pdm_edma_multi_channel_interleave_t multiChannelInterleaveType);
+
+/*!
+ * @brief Configures the PDM channel.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param channel channel index.
+ * @param config pdm channel configurations.
+ */
+void PDM_TransferSetChannelConfigEDMA(PDM_Type *base,
+ pdm_edma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config);
+
+/*!
+ * @brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * 1. Scatter gather case:
+ * This functio support dynamic scatter gather and staic scatter gather,
+ * a. for the dynamic scatter gather case:
+ * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit
+ * before the previous one finish. b. for the static scatter gather case: Application should use the link transfer
+ * feature and make sure a loop link transfer is provided, such as:
+ * @code pdm_edma_transfer_t pdmXfer[2] =
+ * {
+ * {
+ * .data = s_buffer,
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[1],
+ * },
+ *
+ * {
+ * .data = &s_buffer[BUFFER_SIZE],
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[0]
+ * },
+ * };
+ * @endcode
+ *
+ * 2. Multi channel case:
+ * This function support receive multi pdm channel data, for example, if two channel is requested,
+ * @code
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig);
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig);
+ * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer);
+ * @endcode
+ * The output data will be formatted as below if handle->interleaveType =
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample :
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ *
+ * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock
+ * :
+ * ----------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5
+ * |....|
+ * ----------------------------------------------------------------------------------------------------------------------
+ * Note: the dataSize of xfer is the total data size, while application using
+ * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize /
+ * channelNums, then there are limitation for this feature,
+ * 1. 3 DMIC array: the dataSize shall be 4 * (channelSize)
+ * The addtional buffer is mandantory for edma modulo feature.
+ * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only,
+ * 2 DMIC array: CHANNEL3, CHANNEL4
+ * 3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5
+ * 4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6
+ * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4
+ * MAXIMUM DMIC CHANNELS.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a PDM eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer);
+
+/*!
+ * @brief Terminate all PDM receive.
+ *
+ * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the
+ * current transfer slot, please call PDM_TransferAbortReceiveEDMA.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a PDM receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count received by PDM.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param count Bytes count received by PDM.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h
new file mode 100644
index 0000000000..9237341309
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019 - 2020, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_PDM_SDMA_H_
+#define _FSL_PDM_SDMA_H_
+
+#include "fsl_pdm.h"
+#include "fsl_sdma.h"
+
+/*!
+ * @addtogroup pdm_sdma PDM SDMA Driver
+ * @ingroup pdm
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_SDMA_DRIVER_VERSION (MAKE_VERSION(2, 7, 0)) /*!< Version 2.7.0 */
+/*@}*/
+
+typedef struct _pdm_sdma_handle pdm_sdma_handle_t;
+
+/*! @brief PDM eDMA transfer callback function for finish and error */
+typedef void (*pdm_sdma_callback_t)(PDM_Type *base, pdm_sdma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/
+struct _pdm_sdma_handle
+{
+ sdma_handle_t *dmaHandle; /*!< DMA handler for PDM send */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t fifoWidth; /*!< fifo width */
+ uint8_t endChannel; /*!< The last enabled channel */
+ uint8_t channelNums; /*!< total channel numbers */
+ uint32_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for PDM eDMA transfer */
+ uint32_t eventSource; /*!< PDM event source number */
+ pdm_sdma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ sdma_buffer_descriptor_t bdPool[PDM_XFER_QUEUE_SIZE]; /*!< BD pool for SDMA transfer. */
+ pdm_transfer_t pdmQueue[PDM_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[PDM_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM eDMA handle.
+ *
+ * This function initializes the PDM DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ * @param eventSource PDM event source number.
+ */
+void PDM_TransferCreateHandleSDMA(PDM_Type *base,
+ pdm_sdma_handle_t *handle,
+ pdm_sdma_callback_t callback,
+ void *userData,
+ sdma_handle_t *dmaHandle,
+ uint32_t eventSource);
+
+/*!
+ * @brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a PDM eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle, pdm_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a PDM receive using eDMA.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle);
+
+/*!
+ * @brief PDM channel configurations.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param channel channel number.
+ * @param config channel configurations.
+ */
+void PDM_SetChannelConfigSDMA(PDM_Type *base,
+ pdm_sdma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config);
+
+/*!
+ * @brief Terminate all the PDM sdma receive transfer.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM SDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.c b/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.c
new file mode 100644
index 0000000000..659de24999
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pit.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pit"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base PIT peripheral base address
+ *
+ * @return The PIT instance
+ */
+static uint32_t PIT_GetInstance(PIT_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PIT bases for each instance. */
+static PIT_Type *const s_pitBases[] = PIT_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PIT clocks for each instance. */
+static const clock_ip_name_t s_pitClocks[] = PIT_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t PIT_GetInstance(PIT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pitBases); instance++)
+ {
+ if (s_pitBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pitBases));
+
+ return instance;
+}
+
+/*!
+ * brief Ungates the PIT clock, enables the PIT module, and configures the peripheral for basic operations.
+ *
+ * note This API should be called at the beginning of the application using the PIT driver.
+ *
+ * param base PIT peripheral base address
+ * param config Pointer to the user's PIT config structure
+ */
+void PIT_Init(PIT_Type *base, const pit_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the PIT clock*/
+ CLOCK_EnableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_PIT_HAS_MDIS) && FSL_FEATURE_PIT_HAS_MDIS
+ /* Enable PIT timers */
+ base->MCR &= ~PIT_MCR_MDIS_MASK;
+#endif
+
+#if defined(FSL_FEATURE_PIT_TIMER_COUNT) && (FSL_FEATURE_PIT_TIMER_COUNT)
+ /* Clear all status bits for all channels to make sure the status of all TCTRL registers is clean. */
+ for (uint8_t i = 0U; i < (uint32_t)FSL_FEATURE_PIT_TIMER_COUNT; i++)
+ {
+ base->CHANNEL[i].TCTRL &= ~(PIT_TCTRL_TEN_MASK | PIT_TCTRL_TIE_MASK | PIT_TCTRL_CHN_MASK);
+ }
+#endif /* FSL_FEATURE_PIT_TIMER_COUNT */
+
+ /* Config timer operation when in debug mode */
+ if (true == config->enableRunInDebug)
+ {
+ base->MCR &= ~PIT_MCR_FRZ_MASK;
+ }
+ else
+ {
+ base->MCR |= PIT_MCR_FRZ_MASK;
+ }
+}
+
+/*!
+ * brief Gates the PIT clock and disables the PIT module.
+ *
+ * param base PIT peripheral base address
+ */
+void PIT_Deinit(PIT_Type *base)
+{
+#if defined(FSL_FEATURE_PIT_HAS_MDIS) && FSL_FEATURE_PIT_HAS_MDIS
+ /* Disable PIT timers */
+ base->MCR |= PIT_MCR_MDIS_MASK;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the PIT clock*/
+ CLOCK_DisableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if defined(FSL_FEATURE_PIT_HAS_LIFETIME_TIMER) && FSL_FEATURE_PIT_HAS_LIFETIME_TIMER
+
+/*!
+ * brief Reads the current lifetime counter value.
+ *
+ * The lifetime timer is a 64-bit timer which chains timer 0 and timer 1 together.
+ * Timer 0 and 1 are chained by calling the PIT_SetTimerChainMode before using this timer.
+ * The period of lifetime timer is equal to the "period of timer 0 * period of timer 1".
+ * For the 64-bit value, the higher 32-bit has the value of timer 1, and the lower 32-bit
+ * has the value of timer 0.
+ *
+ * param base PIT peripheral base address
+ *
+ * return Current lifetime timer value
+ */
+uint64_t PIT_GetLifetimeTimerCount(PIT_Type *base)
+{
+ uint32_t valueH = 0U;
+ uint32_t valueL = 0U;
+
+ /* LTMR64H should be read before LTMR64L */
+ valueH = base->LTMR64H;
+ valueL = base->LTMR64L;
+
+ return (((uint64_t)valueH << 32U) + (uint64_t)(valueL));
+}
+
+#endif /* FSL_FEATURE_PIT_HAS_LIFETIME_TIMER */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.h b/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.h
new file mode 100644
index 0000000000..2b035d41ad
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pit/fsl_pit.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PIT_H_
+#define _FSL_PIT_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup pit
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief PIT Driver Version 2.0.4 */
+#define FSL_PIT_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+/*!
+ * @brief List of PIT channels
+ * @note Actual number of available channels is SoC dependent
+ */
+typedef enum _pit_chnl
+{
+ kPIT_Chnl_0 = 0U, /*!< PIT channel number 0*/
+ kPIT_Chnl_1, /*!< PIT channel number 1 */
+ kPIT_Chnl_2, /*!< PIT channel number 2 */
+ kPIT_Chnl_3, /*!< PIT channel number 3 */
+} pit_chnl_t;
+
+/*! @brief List of PIT interrupts */
+typedef enum _pit_interrupt_enable
+{
+ kPIT_TimerInterruptEnable = PIT_TCTRL_TIE_MASK, /*!< Timer interrupt enable*/
+} pit_interrupt_enable_t;
+
+/*! @brief List of PIT status flags */
+typedef enum _pit_status_flags
+{
+ kPIT_TimerFlag = PIT_TFLG_TIF_MASK, /*!< Timer flag */
+} pit_status_flags_t;
+
+/*!
+ * @brief PIT configuration structure
+ *
+ * This structure holds the configuration settings for the PIT peripheral. To initialize this
+ * structure to reasonable defaults, call the PIT_GetDefaultConfig() function and pass a
+ * pointer to your config structure instance.
+ *
+ * The configuration structure can be made constant so it resides in flash.
+ */
+typedef struct _pit_config
+{
+ bool enableRunInDebug; /*!< true: Timers run in debug mode; false: Timers stop in debug mode */
+} pit_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Ungates the PIT clock, enables the PIT module, and configures the peripheral for basic operations.
+ *
+ * @note This API should be called at the beginning of the application using the PIT driver.
+ *
+ * @param base PIT peripheral base address
+ * @param config Pointer to the user's PIT config structure
+ */
+void PIT_Init(PIT_Type *base, const pit_config_t *config);
+
+/*!
+ * @brief Gates the PIT clock and disables the PIT module.
+ *
+ * @param base PIT peripheral base address
+ */
+void PIT_Deinit(PIT_Type *base);
+
+/*!
+ * @brief Fills in the PIT configuration structure with the default settings.
+ *
+ * The default values are as follows.
+ * @code
+ * config->enableRunInDebug = false;
+ * @endcode
+ * @param config Pointer to the configuration structure.
+ */
+static inline void PIT_GetDefaultConfig(pit_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Timers are stopped in Debug mode */
+ config->enableRunInDebug = false;
+}
+
+#if defined(FSL_FEATURE_PIT_HAS_CHAIN_MODE) && FSL_FEATURE_PIT_HAS_CHAIN_MODE
+
+/*!
+ * @brief Enables or disables chaining a timer with the previous timer.
+ *
+ * When a timer has a chain mode enabled, it only counts after the previous
+ * timer has expired. If the timer n-1 has counted down to 0, counter n
+ * decrements the value by one. Each timer is 32-bits, which allows the developers
+ * to chain timers together and form a longer timer (64-bits and larger). The first timer
+ * (timer 0) can't be chained to any other timer.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number which is chained with the previous timer
+ * @param enable Enable or disable chain.
+ * true: Current timer is chained with the previous timer.
+ * false: Timer doesn't chain with other timers.
+ */
+static inline void PIT_SetTimerChainMode(PIT_Type *base, pit_chnl_t channel, bool enable)
+{
+ if (enable)
+ {
+ base->CHANNEL[channel].TCTRL |= PIT_TCTRL_CHN_MASK;
+ }
+ else
+ {
+ base->CHANNEL[channel].TCTRL &= ~PIT_TCTRL_CHN_MASK;
+ }
+}
+
+#endif /* FSL_FEATURE_PIT_HAS_CHAIN_MODE */
+
+/*! @}*/
+
+/*!
+ * @name Interrupt Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected PIT interrupts.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pit_interrupt_enable_t
+ */
+static inline void PIT_EnableInterrupts(PIT_Type *base, pit_chnl_t channel, uint32_t mask)
+{
+ base->CHANNEL[channel].TCTRL |= mask;
+}
+
+/*!
+ * @brief Disables the selected PIT interrupts.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ * @param mask The interrupts to disable. This is a logical OR of members of the
+ * enumeration ::pit_interrupt_enable_t
+ */
+static inline void PIT_DisableInterrupts(PIT_Type *base, pit_chnl_t channel, uint32_t mask)
+{
+ base->CHANNEL[channel].TCTRL &= ~mask;
+}
+
+/*!
+ * @brief Gets the enabled PIT interrupts.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::pit_interrupt_enable_t
+ */
+static inline uint32_t PIT_GetEnabledInterrupts(PIT_Type *base, pit_chnl_t channel)
+{
+ return (base->CHANNEL[channel].TCTRL & PIT_TCTRL_TIE_MASK);
+}
+
+/*! @}*/
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Gets the PIT status flags.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration ::pit_status_flags_t
+ */
+static inline uint32_t PIT_GetStatusFlags(PIT_Type *base, pit_chnl_t channel)
+{
+ return (base->CHANNEL[channel].TFLG & PIT_TFLG_TIF_MASK);
+}
+
+/*!
+ * @brief Clears the PIT status flags.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::pit_status_flags_t
+ */
+static inline void PIT_ClearStatusFlags(PIT_Type *base, pit_chnl_t channel, uint32_t mask)
+{
+ base->CHANNEL[channel].TFLG = mask;
+}
+
+/*! @}*/
+
+/*!
+ * @name Read and Write the timer period
+ * @{
+ */
+
+/*!
+ * @brief Sets the timer period in units of count.
+ *
+ * Timers begin counting from the value set by this function until it reaches 0,
+ * then it generates an interrupt and load this register value again.
+ * Writing a new value to this register does not restart the timer. Instead, the value
+ * is loaded after the timer expires.
+ *
+ * @note Users can call the utility macros provided in fsl_common.h to convert to ticks.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ * @param count Timer period in units of ticks
+ */
+static inline void PIT_SetTimerPeriod(PIT_Type *base, pit_chnl_t channel, uint32_t count)
+{
+ assert(count != 0U);
+ /* According to RM, the LDVAL trigger = clock ticks -1 */
+ base->CHANNEL[channel].LDVAL = count - 1U;
+}
+
+/*!
+ * @brief Reads the current timer counting value.
+ *
+ * This function returns the real-time timer counting value, in a range from 0 to a
+ * timer period.
+ *
+ * @note Users can call the utility macros provided in fsl_common.h to convert ticks to usec or msec.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number
+ *
+ * @return Current timer counting value in ticks
+ */
+static inline uint32_t PIT_GetCurrentTimerCount(PIT_Type *base, pit_chnl_t channel)
+{
+ return base->CHANNEL[channel].CVAL;
+}
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+
+/*!
+ * @brief Starts the timer counting.
+ *
+ * After calling this function, timers load period value, count down to 0 and
+ * then load the respective start value again. Each time a timer reaches 0,
+ * it generates a trigger pulse and sets the timeout interrupt flag.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number.
+ */
+static inline void PIT_StartTimer(PIT_Type *base, pit_chnl_t channel)
+{
+ base->CHANNEL[channel].TCTRL |= PIT_TCTRL_TEN_MASK;
+}
+
+/*!
+ * @brief Stops the timer counting.
+ *
+ * This function stops every timer counting. Timers reload their periods
+ * respectively after the next time they call the PIT_DRV_StartTimer.
+ *
+ * @param base PIT peripheral base address
+ * @param channel Timer channel number.
+ */
+static inline void PIT_StopTimer(PIT_Type *base, pit_chnl_t channel)
+{
+ base->CHANNEL[channel].TCTRL &= ~PIT_TCTRL_TEN_MASK;
+}
+
+/*! @}*/
+
+#if defined(FSL_FEATURE_PIT_HAS_LIFETIME_TIMER) && FSL_FEATURE_PIT_HAS_LIFETIME_TIMER
+
+/*!
+ * @brief Reads the current lifetime counter value.
+ *
+ * The lifetime timer is a 64-bit timer which chains timer 0 and timer 1 together.
+ * Timer 0 and 1 are chained by calling the PIT_SetTimerChainMode before using this timer.
+ * The period of lifetime timer is equal to the "period of timer 0 * period of timer 1".
+ * For the 64-bit value, the higher 32-bit has the value of timer 1, and the lower 32-bit
+ * has the value of timer 0.
+ *
+ * @param base PIT peripheral base address
+ *
+ * @return Current lifetime timer value
+ */
+uint64_t PIT_GetLifetimeTimerCount(PIT_Type *base);
+
+#endif /* FSL_FEATURE_PIT_HAS_LIFETIME_TIMER */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PIT_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.c b/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.c
new file mode 100644
index 0000000000..d82299ed24
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright 2018-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_puf.h"
+#include "fsl_clock.h"
+#include "fsl_common.h"
+
+#if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
+#include "fsl_reset.h"
+#endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.puf"
+#endif
+
+/* RT6xx POWER CONTROL bit masks */
+#if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
+#define PUF_PWRCTRL_CKDIS_MASK (0x4U)
+#define PUF_PWRCTRL_RAMINIT_MASK (0x8U)
+#define PUF_PWRCTRL_RAMPSWLARGEMA_MASK (0x10U)
+#define PUF_PWRCTRL_RAMPSWLARGEMP_MASK (0x20U)
+#define PUF_PWRCTRL_RAMPSWSMALLMA_MASK (0x40U)
+#define PUF_PWRCTRL_RAMPSWSMALLMP_MASK (0x80U)
+#endif
+
+#if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+#define DEFAULT_CKGATING 0x0u
+#define PUF_ENABLE_MASK 0xFFFFFFFEu
+#define PUF_ENABLE_CTRL 0x1u
+
+#else
+static void puf_wait_usec(volatile uint32_t usec, uint32_t coreClockFrequencyMHz)
+{
+ SDK_DelayAtLeastUs(usec, coreClockFrequencyMHz * 1000000U);
+
+ /* Instead of calling SDK_DelayAtLeastUs() implement delay loop here */
+ // while (usec > 0U)
+ // {
+ // usec--;
+
+ // number of MHz is directly number of core clocks to wait 1 usec.
+ // the while loop below is actually 4 clocks so divide by 4 for ~1 usec
+ // volatile uint32_t ticksCount = coreClockFrequencyMHz / 4u + 1u;
+ // while (0U != ticksCount--)
+ // {
+ // }
+ // }
+}
+#endif /* defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0) */
+
+static status_t puf_waitForInit(PUF_Type *base)
+{
+ status_t status = kStatus_Fail;
+
+ /* wait until status register reads non-zero. All zero is not valid. It should be BUSY or OK or ERROR */
+ while (0U == base->STAT)
+ {
+ }
+
+ /* wait if busy */
+ while ((base->STAT & PUF_STAT_BUSY_MASK) != 0U)
+ {
+ }
+
+ /* return status */
+ if (0U != (base->STAT & (PUF_STAT_SUCCESS_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static void puf_powerOn(PUF_Type *base, puf_config_t *conf)
+{
+#if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
+ /* RT6xxs */
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK);
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+#elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* LPCXpresso55s16 */
+ conf->puf_sram_base->CFG |= PUF_ENABLE_CTRL;
+ while (0U == (PUF_SRAM_CTRL_STATUS_READY_MASK & conf->puf_sram_base->STATUS))
+ {
+ }
+#else /* !FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
+ /* LPCXpresso55s69 & LPCXpresso54S018 */
+ base->PWRCTRL = PUF_PWRCTRL_RAMON_MASK;
+ while (0U == (PUF_PWRCTRL_RAMSTAT_MASK & base->PWRCTRL))
+ {
+ }
+#endif /* FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
+}
+/*!
+ * brief Powercycle PUF
+ *
+ * This function make powercycle of PUF.
+ *
+ * param base PUF peripheral base address
+ * param conf PUF configuration structure
+ * return Status of the powercycle operation.
+ */
+status_t PUF_PowerCycle(PUF_Type *base, puf_config_t *conf)
+{
+#if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
+ /* RT6xxs */
+ uint32_t coreClockFrequencyMHz = conf->coreClockFrequencyHz / 1000000u;
+
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* disable RAM CK */
+
+ /* enter ASPS mode */
+ base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* SLEEP = 1 */
+ base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK); /* enable RAM CK */
+ base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK | PUF_PWRCTRL_RAMPSWLARGEMP_MASK |
+ PUF_PWRCTRL_RAMPSWSMALLMA_MASK | PUF_PWRCTRL_RAMPSWSMALLMP_MASK); /* SLEEP=1, PSW*=1 */
+
+ /* Wait enough time to discharge fully */
+ puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
+
+ /* write PWRCTRL=0x38. wait time > 1 us */
+ base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK |
+ PUF_PWRCTRL_RAMPSWLARGEMP_MASK); /* SLEEP=1. PSWSMALL*=0. PSWLARGE*=1. */
+ puf_wait_usec(1, coreClockFrequencyMHz);
+
+ /* write PWRCTRL=0x8. wait time > 1 us */
+ base->PWRCTRL = PUF_PWRCTRL_RAMINIT_MASK; /* SLEEP=1. PSWSMALL*=0. PSWLARGE*=0 */
+ puf_wait_usec(1, coreClockFrequencyMHz);
+
+ base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+
+ /* Generate INITN low pulse */
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK);
+ base->PWRCTRL = PUF_PWRCTRL_RAM_ON_MASK;
+#elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* LPCXpresso55s16 */
+ conf->puf_sram_base->CFG &= PUF_ENABLE_MASK;
+#else
+ /* LPCXpresso55s69 & LPCXpresso54S018 */
+ base->PWRCTRL = 0x0u;
+ while (0U != (PUF_PWRCTRL_RAMSTAT_MASK & base->PWRCTRL))
+ {
+ }
+
+ /* Wait enough time to discharge fully */
+ puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
+#endif
+
+#if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
+ /* Reset PUF and reenable power to PUF SRAM */
+ RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
+#endif /* FSL_TEATURE_PUF_HAS_NO_RESET */
+ puf_powerOn(base, conf);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets the default configuration of PUF
+ *
+ * This function initialize PUF config structure to default values.
+ *
+ * param conf PUF configuration structure
+ */
+void PUF_GetDefaultConfig(puf_config_t *conf)
+{
+#if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* LPCXpresso55s16 */
+ conf->puf_sram_base = PUF_SRAM_CTRL;
+
+ /* Default configuration after reset */
+ conf->CKGATING = DEFAULT_CKGATING; /* PUF SRAM Clock Gating */
+#endif /* FSL_FEATURE_PUF_HAS_SRAM_CTRL */
+
+ conf->dischargeTimeMsec = KEYSTORE_PUF_DISCHARGE_TIME_FIRST_TRY_MS;
+ conf->coreClockFrequencyHz = CLOCK_GetFreq(kCLOCK_CoreSysClk);
+
+ return;
+}
+
+/*!
+ * brief Initialize PUF
+ *
+ * This function enables power to PUF block and waits until the block initializes.
+ *
+ * param base PUF peripheral base address
+ * param conf PUF configuration structure
+ * return Status of the init operation
+ */
+status_t PUF_Init(PUF_Type *base, puf_config_t *conf)
+{
+ status_t status = kStatus_Fail;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Puf);
+#endif
+#if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
+ /* Reset PUF */
+ RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
+#endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
+
+#if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* Set configuration for SRAM */
+ conf->puf_sram_base->CFG |= PUF_SRAM_CTRL_CFG_CKGATING(conf->CKGATING);
+
+#endif /* FSL_FEATURE_PUF_HAS_SRAM_CTRL */
+
+ /* Enable power to PUF SRAM */
+ puf_powerOn(base, conf);
+
+ /* Wait for peripheral to become ready */
+ status = puf_waitForInit(base);
+
+ /* In case of error or enroll or start not allowed, do power-cycle */
+ /* First try with shorter discharge time, if then it also fails try with longer time */
+ /* conf->dischargeTimeMsec = KEYSTORE_PUF_DISCHARGE_TIME_FIRST_TRY_MS; */
+ if ((status != kStatus_Success) || (0U == (base->ALLOW & (PUF_ALLOW_ALLOWENROLL_MASK | PUF_ALLOW_ALLOWSTART_MASK))))
+ {
+ (void)PUF_PowerCycle(base, conf);
+ status = puf_waitForInit(base);
+ }
+
+ /* In case of error or enroll or start not allowed, do power-cycle with worst discharge timing */
+ if ((status != kStatus_Success) || (0U == (base->ALLOW & (PUF_ALLOW_ALLOWENROLL_MASK | PUF_ALLOW_ALLOWSTART_MASK))))
+ {
+ conf->dischargeTimeMsec = KEYSTORE_PUF_DISCHARGE_TIME_MAX_MS;
+ (void)PUF_PowerCycle(base, conf);
+ status = puf_waitForInit(base);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Denitialize PUF
+ *
+ * This function disables power to PUF SRAM and peripheral clock.
+ *
+ * param base PUF peripheral base address
+ * param conf PUF configuration structure
+ */
+void PUF_Deinit(PUF_Type *base, puf_config_t *conf)
+{
+#if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
+ /* RT6xxs */
+ base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* disable RAM CK */
+
+ /* enter ASPS mode */
+ base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* SLEEP = 1 */
+ base->PWRCTRL = PUF_PWRCTRL_RAMINIT_MASK; /* enable RAM CK */
+ base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK | PUF_PWRCTRL_RAMPSWLARGEMP_MASK |
+ PUF_PWRCTRL_RAMPSWSMALLMA_MASK | PUF_PWRCTRL_RAMPSWSMALLMP_MASK); /* SLEEP=1, PSW*=1 */
+ puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
+#elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* LPCXpresso55s16 */
+ conf->puf_sram_base = PUF_SRAM_CTRL;
+ conf->puf_sram_base->CFG &= PUF_ENABLE_MASK;
+#else /* !FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
+ /* LPCXpresso55s69 & LPCXpresso54S018 */
+ base->PWRCTRL = 0x00u;
+ puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
+#endif
+
+#if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
+ RESET_SetPeripheralReset(kPUF_RST_SHIFT_RSTn);
+#endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Puf);
+#endif
+}
+
+/*!
+ * brief Enroll PUF
+ *
+ * This function derives a digital fingerprint, generates the corresponding Activation Code (AC)
+ * and returns it to be stored in an NVM or a file. This step needs to be
+ * performed only once for each device. This function may be permanently disallowed by a fuse.
+ *
+ * param base PUF peripheral base address
+ * param[out] activationCode Word aligned address of the resulting activation code.
+ * param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
+ * return Status of enroll operation.
+ */
+status_t PUF_Enroll(PUF_Type *base, uint8_t *activationCode, size_t activationCodeSize)
+{
+ status_t status = kStatus_Fail;
+ uint32_t *activationCodeAligned = NULL;
+ register uint32_t temp32 = 0;
+
+ /* check that activation code buffer size is at least 1192 bytes */
+ if (activationCodeSize < PUF_ACTIVATION_CODE_SIZE)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* only work with aligned activationCode */
+ if (0U != (0x3u & (uintptr_t)activationCode))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ activationCodeAligned = (uint32_t *)(uintptr_t)activationCode;
+
+ /* check if ENROLL is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWENROLL_MASK))
+ {
+ return kStatus_EnrollNotAllowed;
+ }
+
+ /* begin */
+ base->CTRL = PUF_CTRL_ENROLL_MASK;
+
+ /* check status */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* read out AC */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
+ {
+ temp32 = base->CODEOUTPUT;
+ if (activationCodeSize >= sizeof(uint32_t))
+ {
+ *activationCodeAligned = temp32;
+ activationCodeAligned++;
+ activationCodeSize -= sizeof(uint32_t);
+ }
+ }
+ }
+
+ if (((base->STAT & PUF_STAT_SUCCESS_MASK) != 0U) && (activationCodeSize == 0U))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Start PUF
+ *
+ * The Activation Code generated during the Enroll operation is used to
+ * reconstruct the digital fingerprint. This needs to be done after every power-up
+ * and reset.
+ *
+ * param base PUF peripheral base address
+ * param activationCode Word aligned address of the input activation code.
+ * param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
+ * return Status of start operation.
+ */
+status_t PUF_Start(PUF_Type *base, const uint8_t *activationCode, size_t activationCodeSize)
+{
+ status_t status = kStatus_Fail;
+ const uint32_t *activationCodeAligned = NULL;
+ register uint32_t temp32 = 0;
+
+ /* check that activation code size is at least 1192 bytes */
+ if (activationCodeSize < 1192U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* only work with aligned activationCode */
+ if (0U != (0x3u & (uintptr_t)activationCode))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ activationCodeAligned = (const uint32_t *)(uintptr_t)activationCode;
+
+ /* check if START is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSTART_MASK))
+ {
+ return kStatus_StartNotAllowed;
+ }
+
+ /* begin */
+ base->CTRL = PUF_CTRL_START_MASK;
+
+ /* check status */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* while busy send AC */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
+ {
+ if (activationCodeSize >= sizeof(uint32_t))
+ {
+ temp32 = *activationCodeAligned;
+ activationCodeAligned++;
+ activationCodeSize -= sizeof(uint32_t);
+ }
+ base->CODEINPUT = temp32;
+ }
+ }
+
+ /* get status */
+ if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set intrinsic key
+ *
+ * The digital fingerprint generated during the Enroll/Start
+ * operations is used to generate a Key Code (KC) that defines a unique intrinsic
+ * key. This KC is returned to be stored in an NVM or a file. This operation
+ * needs to be done only once for each intrinsic key.
+ * Each time a Set Intrinsic Key operation is executed a new unique key is
+ * generated.
+ *
+ * param base PUF peripheral base address
+ * param keyIndex PUF key index register
+ * param keySize Size of the intrinsic key to generate in bytes.
+ * param[out] keyCode Word aligned address of the resulting key code.
+ * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * return Status of set intrinsic key operation.
+ */
+status_t PUF_SetIntrinsicKey(
+ PUF_Type *base, puf_key_index_register_t keyIndex, size_t keySize, uint8_t *keyCode, size_t keyCodeSize)
+{
+ status_t status = kStatus_Fail;
+ uint32_t *keyCodeAligned = NULL;
+ register uint32_t temp32 = 0;
+
+ /* check if SET KEY is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSETKEY_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ /* only work with aligned keyCode */
+ if (0U != (0x3u & (uintptr_t)keyCode))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that keySize is in the correct range and that it is multiple of 8 */
+ if ((keySize < (uint32_t)kPUF_KeySizeMin) || (keySize > (uint32_t)kPUF_KeySizeMax) || (0U != (keySize & 0x7U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* check that keyCodeSize is correct for given keySize */
+ if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((uint32_t)keyIndex > (uint32_t)kPUF_KeyIndexMax)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
+
+ /* program the key size and index */
+ base->KEYSIZE = keySize >> 3;
+ base->KEYINDEX = (uint32_t)keyIndex;
+
+ /* begin */
+ base->CTRL = PUF_CTRL_GENERATEKEY_MASK;
+
+ /* wait till command is accepted */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* while busy read KC */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
+ {
+ temp32 = base->CODEOUTPUT;
+ if (keyCodeSize >= sizeof(uint32_t))
+ {
+ *keyCodeAligned = temp32;
+ keyCodeAligned++;
+ keyCodeSize -= sizeof(uint32_t);
+ }
+ }
+ }
+
+ /* get status */
+ if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set user key
+ *
+ * The digital fingerprint generated during the Enroll/Start
+ * operations and a user key (UK) provided as input are used to
+ * generate a Key Code (KC). This KC is sent returned to be stored
+ * in an NVM or a file. This operation needs to be done only once for each user key.
+ *
+ * param base PUF peripheral base address
+ * param keyIndex PUF key index register
+ * param userKey Word aligned address of input user key.
+ * param userKeySize Size of the input user key in bytes.
+ * param[out] keyCode Word aligned address of the resulting key code.
+ * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize).
+ * return Status of set user key operation.
+ */
+status_t PUF_SetUserKey(PUF_Type *base,
+ puf_key_index_register_t keyIndex,
+ const uint8_t *userKey,
+ size_t userKeySize,
+ uint8_t *keyCode,
+ size_t keyCodeSize)
+{
+ status_t status = kStatus_Fail;
+ uint32_t *keyCodeAligned = NULL;
+ const uint32_t *userKeyAligned = NULL;
+ register uint32_t temp32 = 0;
+
+ /* check if SET KEY is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSETKEY_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ /* only work with aligned keyCode */
+ if (0U != (0x3u & (uintptr_t)keyCode))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that userKeySize is in the correct range and that it is multiple of 8 */
+ if ((userKeySize < (uint32_t)kPUF_KeySizeMin) || (userKeySize > (uint32_t)kPUF_KeySizeMax) ||
+ (0U != (userKeySize & 0x7U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* check that keyCodeSize is correct for given userKeySize */
+ if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((uint32_t)keyIndex > (uint32_t)kPUF_KeyIndexMax)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
+ userKeyAligned = (const uint32_t *)(uintptr_t)userKey;
+
+ /* program the key size and index */
+ base->KEYSIZE = userKeySize >> 3; /* convert to 64-bit blocks */
+ base->KEYINDEX = (uint32_t)keyIndex;
+
+ /* We have to store the user key on index 0 swaped for HW bus */
+ if (keyIndex == kPUF_KeyIndex_00)
+ {
+ userKeyAligned = userKeyAligned + (userKeySize / sizeof(uint32_t));
+ }
+
+ /* begin */
+ base->CTRL = PUF_CTRL_SETKEY_MASK;
+
+ /* wait till command is accepted */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* while busy write UK and read KC */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_KEYINREQ_MASK & base->STAT))
+ {
+ if (userKeySize >= sizeof(uint32_t))
+ {
+#if defined(LPC54S018_SERIES)
+ if (keyIndex == kPUF_KeyIndex_00)
+ {
+ userKeyAligned--;
+ temp32 = *userKeyAligned;
+ userKeySize -= sizeof(uint32_t);
+ }
+#else
+ if (keyIndex == kPUF_KeyIndex_00)
+ {
+ userKeyAligned--;
+ temp32 = __REV(*userKeyAligned);
+ userKeySize--;
+ }
+#endif /* defined(LPC54S018_SERIES) */
+ else if (keyIndex != kPUF_KeyIndex_00)
+ {
+ temp32 = *userKeyAligned;
+ userKeyAligned++;
+ userKeySize -= sizeof(uint32_t);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ }
+ base->KEYINPUT = temp32;
+ }
+
+ if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
+ {
+ temp32 = base->CODEOUTPUT;
+ if (keyCodeSize >= sizeof(uint32_t))
+ {
+ *keyCodeAligned = temp32;
+ keyCodeAligned++;
+ keyCodeSize -= sizeof(uint32_t);
+ }
+ }
+ }
+
+ /* get status */
+ if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static status_t puf_getHwKey(PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize)
+{
+ status_t status = kStatus_Fail;
+ uint32_t *keyCodeAligned = NULL;
+ register uint32_t temp32 = 0;
+
+ keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
+
+ /* begin */
+ base->CTRL = PUF_CTRL_GETKEY_MASK;
+
+ /* wait till command is accepted */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* while busy send KC, key is reconstructed to HW bus */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
+ {
+ if (keyCodeSize >= sizeof(uint32_t))
+ {
+ temp32 = *keyCodeAligned;
+ keyCodeAligned++;
+ keyCodeSize -= sizeof(uint32_t);
+ }
+ base->CODEINPUT = temp32;
+ }
+ }
+
+ /* get status */
+ if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Reconstruct hw bus key from a key code
+ *
+ * The digital fingerprint generated during the Start operation and the KC
+ * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
+ * operation needs to be done every time a key is needed.
+ * This function accepts only Key Codes created for PUF index register kPUF_KeyIndex_00.
+ * Such a key is output directly to a dedicated hardware bus. The reconstructed key is not exposed to system memory.
+ *
+ * param base PUF peripheral base address
+ * param keyCode Word aligned address of the input key code.
+ * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * param keySlot key slot to output on hw bus. Parameter is ignored on devices with less than two key slots.
+ * param keyMask key masking value. Shall be random for each POR/reset. Value does not have to be cryptographicaly
+ * secure.
+ * return Status of get key operation.
+ */
+status_t PUF_GetHwKey(
+ PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, puf_key_slot_t keySlot, uint32_t keyMask)
+{
+ status_t status = kStatus_Fail;
+ uint32_t keyIndex;
+
+ /* check if GET KEY is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ /* only work with aligned keyCode */
+ if (0U != (0x3u & (uintptr_t)keyCode))
+ {
+ return kStatus_Fail;
+ }
+
+ /* check that keyCodeSize is at least PUF_MIN_KEY_CODE_SIZE */
+ if (keyCodeSize < PUF_MIN_KEY_CODE_SIZE)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ keyIndex = (uint32_t)(0x0Fu & (uint32_t)keyCode[1]);
+
+ /* check the Key Code header byte 1. index must be zero for the hw key. */
+ if (kPUF_KeyIndex_00 != (puf_key_index_register_t)keyIndex)
+ {
+ return kStatus_Fail;
+ }
+
+#if defined(PUF_KEYMASK_COUNT) && (PUF_KEYMASK_COUNT > 0)
+ volatile uint32_t *keyMask_reg = NULL;
+ uint32_t regVal = ((uint32_t)2U << ((uint32_t)2U * (uint32_t)keySlot));
+
+ switch (keySlot)
+ {
+ case kPUF_KeySlot0:
+ keyMask_reg = &base->KEYMASK[0];
+ break;
+
+ case kPUF_KeySlot1:
+ keyMask_reg = &base->KEYMASK[1];
+ break;
+#if (PUF_KEYMASK_COUNT > 2)
+ case kPUF_KeySlot2:
+ keyMask_reg = &base->KEYMASK[2];
+ break;
+
+ case kPUF_KeySlot3:
+ keyMask_reg = &base->KEYMASK[3];
+ break;
+#endif /* PUF_KEYMASK_COUNT > 2 */
+ default:
+ status = kStatus_InvalidArgument;
+ break;
+ }
+#endif /* PUF_KEYMASK_COUNT */
+
+ if (status != kStatus_InvalidArgument)
+ {
+#if defined(PUF_KEYMASK_COUNT) && (PUF_KEYMASK_COUNT > 0)
+ base->KEYRESET = regVal;
+ base->KEYENABLE = regVal;
+ *keyMask_reg = keyMask;
+#endif /* FSL_FEATURE_PUF_HAS_KEYSLOTS */
+
+ status = puf_getHwKey(base, keyCode, keyCodeSize);
+
+#if defined(FSL_FEATURE_PUF_HAS_SHIFT_STATUS) && (FSL_FEATURE_PUF_HAS_SHIFT_STATUS > 0)
+ size_t keyWords = 0;
+
+ if (status == kStatus_Success)
+ {
+ /* if the corresponding shift count does not match, return fail anyway */
+ keyWords = ((((size_t)keyCode[3]) * 2U) - 1u) << ((size_t)keySlot << 2U);
+ if (keyWords != ((0x0FUL << ((uint32_t)keySlot << 2U)) & base->SHIFT_STATUS))
+ {
+ status = kStatus_Fail;
+ }
+ }
+#elif defined(PUF_IDXBLK_SHIFT_IND_KEY0_MASK) && PUF_IDXBLK_SHIFT_IND_KEY0_MASK
+ size_t keyWords = 0;
+
+ if (status == kStatus_Success)
+ {
+ /* if the corresponding shift count does not match, return fail anyway */
+ keyWords = ((((size_t)keyCode[3]) * 2U) - 1u) << ((size_t)keySlot << 2U);
+ if (keyWords != ((0x0FUL << ((uint32_t)keySlot << 2U)) & base->IDXBLK_SHIFT))
+ {
+ status = kStatus_Fail;
+ }
+ }
+#endif /* FSL_FEATURE_PUF_HAS_SHIFT_STATUS || PUF_IDXBLK_SHIFT_IND_KEY0_MASK */
+ }
+
+ return status;
+}
+
+/*!
+ * brief Checks if Get Key operation is allowed.
+ *
+ * This function returns true if get key operation is allowed.
+ *
+ * param base PUF peripheral base address
+ * return true if get key operation is allowed
+ */
+bool PUF_IsGetKeyAllowed(PUF_Type *base)
+{
+ /* check if GET KEY is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * brief Reconstruct key from a key code
+ *
+ * The digital fingerprint generated during the Start operation and the KC
+ * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
+ * operation needs to be done every time a key is needed.
+ * This function accepts only Key Codes created for PUF index registers kPUF_KeyIndex_01 to kPUF_KeyIndex_15.
+ *
+ * param base PUF peripheral base address
+ * param keyCode Word aligned address of the input key code.
+ * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * param[out] key Word aligned address of output key.
+ * param keySize Size of the output key in bytes.
+ * return Status of get key operation.
+ */
+status_t PUF_GetKey(PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, uint8_t *key, size_t keySize)
+{
+ status_t status = kStatus_Fail;
+ uint32_t *keyCodeAligned = NULL;
+ uint32_t *keyAligned = NULL;
+ uint32_t keyIndex;
+ register uint32_t temp32 = 0;
+
+ /* check if GET KEY is allowed */
+ if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ /* only work with aligned keyCode */
+ if (0U != (0x3u & (uintptr_t)keyCode))
+ {
+ return kStatus_Fail;
+ }
+
+ /* only work with aligned key */
+ if (0U != (0x3u & (uintptr_t)key))
+ {
+ return kStatus_Fail;
+ }
+
+ /* check that keyCodeSize is correct for given keySize */
+ if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ keyIndex = (0x0Fu & (uint32_t)keyCode[1]);
+
+ /* check the Key Code header byte 1. index must be non-zero for the register key. */
+ if (kPUF_KeyIndex_00 == (puf_key_index_register_t)keyIndex)
+ {
+ return kStatus_Fail;
+ }
+
+ keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
+ keyAligned = (uint32_t *)(uintptr_t)key;
+
+ /* begin */
+ base->CTRL = PUF_CTRL_GETKEY_MASK;
+
+ /* wait till command is accepted */
+ while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
+ {
+ }
+
+ /* while busy send KC, read key */
+ while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
+ {
+ if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
+ {
+ temp32 = 0;
+ if (keyCodeSize >= sizeof(uint32_t))
+ {
+ temp32 = *keyCodeAligned;
+ keyCodeAligned++;
+ keyCodeSize -= sizeof(uint32_t);
+ }
+ base->CODEINPUT = temp32;
+ }
+
+ if (0U != (PUF_STAT_KEYOUTAVAIL_MASK & base->STAT))
+ {
+ keyIndex = base->KEYOUTINDEX;
+ temp32 = base->KEYOUTPUT;
+ if (keySize >= sizeof(uint32_t))
+ {
+ *keyAligned = temp32;
+ keyAligned++;
+ keySize -= sizeof(uint32_t);
+ }
+ }
+ }
+
+ /* get status */
+ if ((keyIndex != 0U) && (0U != (base->STAT & PUF_STAT_SUCCESS_MASK)))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Zeroize PUF
+ *
+ * This function clears all PUF internal logic and puts the PUF to error state.
+ *
+ * param base PUF peripheral base address
+ * return Status of the zeroize operation.
+ */
+status_t PUF_Zeroize(PUF_Type *base)
+{
+ status_t status = kStatus_Fail;
+
+ /* zeroize command is always allowed */
+ base->CTRL = PUF_CTRL_ZEROIZE_MASK;
+
+ /* check that command is accepted */
+ if ((0U != (base->STAT & PUF_STAT_ERROR_MASK)) && (0U == base->ALLOW))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.h b/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.h
new file mode 100644
index 0000000000..b8a5c51c85
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/puf/fsl_puf.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2018-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PUF_H_
+#define _PUF_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*!
+ * @addtogroup puf_driver
+ * @{
+ */
+/*! @name Driver version */
+/*@{*/
+/*! @brief PUF driver version. Version 2.1.6.
+ *
+ * Current version: 2.1.6
+ *
+ * Change log:
+ * - 2.0.0
+ * - Initial version.
+ * - 2.0.1
+ * - Fixed puf_wait_usec function optimization issue.
+ * - 2.0.2
+ * - Add PUF configuration structure and support for PUF SRAM controller.
+ * Remove magic constants.
+ * - 2.0.3
+ * - Fix MISRA C-2012 issue.
+ * - 2.1.0
+ * - Align driver with PUF SRAM controller registers on LPCXpresso55s16.
+ * - Update initizalition logic .
+ * - 2.1.1
+ * - Fix ARMGCC build warning .
+ * - 2.1.2
+ * - Update: Add automatic big to little endian swap for user
+ * (pre-shared) keys destinated to secret hardware bus (PUF key index 0).
+ * - 2.1.3
+ * - Fix MISRA C-2012 issue.
+ * - 2.1.4
+ * - Replace register uint32_t ticksCount with volatile uint32_t ticksCount in puf_wait_usec() to prevent optimization
+ * out delay loop.
+ * - 2.1.5
+ * - Use common SDK delay in puf_wait_usec()
+ * - 2.1.6
+ * - Changed wait time in PUF_Init(), when initialization fails it will try PUF_Powercycle() with shorter time. If
+ * this shorter time will also fail, initialization will be tried with worst case time as before.
+ */
+#define FSL_PUF_DRIVER_VERSION (MAKE_VERSION(2, 1, 6))
+/*@}*/
+
+typedef enum _puf_key_index_register
+{
+ kPUF_KeyIndex_00 = 0x00U,
+ kPUF_KeyIndex_01 = 0x01U,
+ kPUF_KeyIndex_02 = 0x02U,
+ kPUF_KeyIndex_03 = 0x03U,
+ kPUF_KeyIndex_04 = 0x04U,
+ kPUF_KeyIndex_05 = 0x05U,
+ kPUF_KeyIndex_06 = 0x06U,
+ kPUF_KeyIndex_07 = 0x07U,
+ kPUF_KeyIndex_08 = 0x08U,
+ kPUF_KeyIndex_09 = 0x09U,
+ kPUF_KeyIndex_10 = 0x0AU,
+ kPUF_KeyIndex_11 = 0x0BU,
+ kPUF_KeyIndex_12 = 0x0CU,
+ kPUF_KeyIndex_13 = 0x0DU,
+ kPUF_KeyIndex_14 = 0x0EU,
+ kPUF_KeyIndex_15 = 0x0FU,
+} puf_key_index_register_t;
+
+typedef enum _puf_min_max
+{
+ kPUF_KeySizeMin = 8u,
+ kPUF_KeySizeMax = 512u,
+ kPUF_KeyIndexMax = kPUF_KeyIndex_15,
+} puf_min_max_t;
+
+/*! @brief PUF key slot. */
+typedef enum _puf_key_slot
+{
+ kPUF_KeySlot0 = 0U, /*!< PUF key slot 0 */
+ kPUF_KeySlot1 = 1U, /*!< PUF key slot 1 */
+#if defined(PUF_KEYMASK_COUNT) && (PUF_KEYMASK_COUNT > 2)
+ kPUF_KeySlot2 = 2U, /*!< PUF key slot 2 */
+ kPUF_KeySlot3 = 3U, /*!< PUF key slot 3 */
+#endif
+} puf_key_slot_t;
+
+typedef struct
+{
+ uint32_t dischargeTimeMsec;
+ uint32_t coreClockFrequencyHz;
+#if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
+ /* LPCXpresso55s16 */
+ PUF_SRAM_CTRL_Type *puf_sram_base;
+ uint8_t CKGATING;
+#endif /* FSL_FEATURE_PUF_HAS_SRAM_CTRL */
+} puf_config_t;
+/*! @brief Get Key Code size in bytes from key size in bytes at compile time. */
+#define PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(x) ((160u + (((((x) << 3) + 255u) >> 8) << 8)) >> 3)
+#define PUF_MIN_KEY_CODE_SIZE PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(8UL)
+#define PUF_ACTIVATION_CODE_SIZE 1192U
+#define KEYSTORE_PUF_DISCHARGE_TIME_FIRST_TRY_MS 50
+#define KEYSTORE_PUF_DISCHARGE_TIME_MAX_MS 400
+
+/*! PUF status return codes. */
+enum
+{
+ kStatus_EnrollNotAllowed = MAKE_STATUS(kStatusGroup_PUF, 1),
+ kStatus_StartNotAllowed = MAKE_STATUS(kStatusGroup_PUF, 2)
+};
+
+/*! @} */
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @brief Sets the default configuration of PUF
+ *
+ * This function initialize PUF config structure to default values.
+ *
+ * @param conf PUF configuration structure
+ */
+void PUF_GetDefaultConfig(puf_config_t *conf);
+
+/*!
+ * @brief Initialize PUF
+ *
+ * This function enables power to PUF block and waits until the block initializes.
+ *
+ * @param base PUF peripheral base address
+ * @param conf PUF configuration structure
+ * @return Status of the init operation
+ */
+status_t PUF_Init(PUF_Type *base, puf_config_t *conf);
+
+/*!
+ * @brief Denitialize PUF
+ *
+ * This function disables power to PUF SRAM and peripheral clock.
+ *
+ * @param base PUF peripheral base address
+ * @param conf PUF configuration structure
+ */
+void PUF_Deinit(PUF_Type *base, puf_config_t *conf);
+
+/*!
+ * @brief Enroll PUF
+ *
+ * This function derives a digital fingerprint, generates the corresponding Activation Code (AC)
+ * and returns it to be stored in an NVM or a file. This step needs to be
+ * performed only once for each device. This function may be permanently disallowed by a fuse.
+ *
+ * @param base PUF peripheral base address
+ * @param[out] activationCode Word aligned address of the resulting activation code.
+ * @param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
+ * @return Status of enroll operation.
+ */
+status_t PUF_Enroll(PUF_Type *base, uint8_t *activationCode, size_t activationCodeSize);
+
+/*!
+ * @brief Start PUF
+ *
+ * The Activation Code generated during the Enroll operation is used to
+ * reconstruct the digital fingerprint. This needs to be done after every power-up
+ * and reset.
+ *
+ * @param base PUF peripheral base address
+ * @param activationCode Word aligned address of the input activation code.
+ * @param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
+ * @return Status of start operation.
+ */
+status_t PUF_Start(PUF_Type *base, const uint8_t *activationCode, size_t activationCodeSize);
+
+/*!
+ * @brief Set intrinsic key
+ *
+ * The digital fingerprint generated during the Enroll/Start
+ * operations is used to generate a Key Code (KC) that defines a unique intrinsic
+ * key. This KC is returned to be stored in an NVM or a file. This operation
+ * needs to be done only once for each intrinsic key.
+ * Each time a Set Intrinsic Key operation is executed a new unique key is
+ * generated.
+ *
+ * @param base PUF peripheral base address
+ * @param keyIndex PUF key index register
+ * @param keySize Size of the intrinsic key to generate in bytes.
+ * @param[out] keyCode Word aligned address of the resulting key code.
+ * @param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * @return Status of set intrinsic key operation.
+ */
+status_t PUF_SetIntrinsicKey(
+ PUF_Type *base, puf_key_index_register_t keyIndex, size_t keySize, uint8_t *keyCode, size_t keyCodeSize);
+
+/*!
+ * @brief Set user key
+ *
+ * The digital fingerprint generated during the Enroll/Start
+ * operations and a user key (UK) provided as input are used to
+ * generate a Key Code (KC). This KC is sent returned to be stored
+ * in an NVM or a file. This operation needs to be done only once for each user key.
+ *
+ * @param base PUF peripheral base address
+ * @param keyIndex PUF key index register
+ * @param userKey Word aligned address of input user key.
+ * @param userKeySize Size of the input user key in bytes.
+ * @param[out] keyCode Word aligned address of the resulting key code.
+ * @param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize).
+ * @return Status of set user key operation.
+ */
+status_t PUF_SetUserKey(PUF_Type *base,
+ puf_key_index_register_t keyIndex,
+ const uint8_t *userKey,
+ size_t userKeySize,
+ uint8_t *keyCode,
+ size_t keyCodeSize);
+
+/*!
+ * @brief Reconstruct key from a key code
+ *
+ * The digital fingerprint generated during the Start operation and the KC
+ * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
+ * operation needs to be done every time a key is needed.
+ * This function accepts only Key Codes created for PUF index registers kPUF_KeyIndex_01 to kPUF_KeyIndex_15.
+ *
+ * @param base PUF peripheral base address
+ * @param keyCode Word aligned address of the input key code.
+ * @param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * @param[out] key Word aligned address of output key.
+ * @param keySize Size of the output key in bytes.
+ * @return Status of get key operation.
+ */
+status_t PUF_GetKey(PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, uint8_t *key, size_t keySize);
+
+/*!
+ * @brief Reconstruct hw bus key from a key code
+ *
+ * The digital fingerprint generated during the Start operation and the KC
+ * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
+ * operation needs to be done every time a key is needed.
+ * This function accepts only Key Codes created for PUF index register kPUF_KeyIndex_00.
+ * Such a key is output directly to a dedicated hardware bus. The reconstructed key is not exposed to system memory.
+ *
+ * @param base PUF peripheral base address
+ * @param keyCode Word aligned address of the input key code.
+ * @param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
+ * @param keySlot key slot to output on hw bus. Parameter is ignored on devices with less than two key slots.
+ * @param keyMask key masking value. Shall be random for each POR/reset. Value does not have to be cryptographicaly
+ * secure.
+ * @return Status of get key operation.
+ */
+status_t PUF_GetHwKey(
+ PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, puf_key_slot_t keySlot, uint32_t keyMask);
+
+/*!
+ * @brief Zeroize PUF
+ *
+ * This function clears all PUF internal logic and puts the PUF to error state.
+ *
+ * @param base PUF peripheral base address
+ * @return Status of the zeroize operation.
+ */
+status_t PUF_Zeroize(PUF_Type *base);
+
+/*!
+ * @brief Checks if Get Key operation is allowed.
+ *
+ * This function returns true if get key operation is allowed.
+ *
+ * @param base PUF peripheral base address
+ * @return true if get key operation is allowed
+ */
+bool PUF_IsGetKeyAllowed(PUF_Type *base);
+
+#if defined(PUF_CFG_BLOCKKEYOUTPUT_MASK) && PUF_CFG_BLOCKKEYOUTPUT_MASK
+static inline void PUF_BlockSetKey(PUF_Type *base)
+{
+ base->CFG |= PUF_CFG_BLOCKKEYOUTPUT_MASK; /* block set key */
+}
+#endif /* PUF_CFG_BLOCKKEYOUTPUT_MASK */
+
+#if defined(PUF_CFG_PUF_BLOCK_SET_KEY_MASK) && PUF_CFG_PUF_BLOCK_SET_KEY_MASK
+static inline void PUF_BlockSetKey(PUF_Type *base)
+{
+ base->CFG |= PUF_CFG_PUF_BLOCK_SET_KEY_MASK; /* block set key */
+}
+#endif /* PUF_CFG_PUF_BLOCK_SET_KEY_MASK */
+
+#if defined(PUF_CFG_BLOCKENROLL_SETKEY_MASK) && PUF_CFG_BLOCKENROLL_SETKEY_MASK
+static inline void PUF_BlockEnroll(PUF_Type *base)
+{
+ base->CFG |= PUF_CFG_BLOCKENROLL_SETKEY_MASK; /* block enroll */
+}
+#endif /* PUF_CFG_BLOCKENROLL_SETKEY_MASK */
+
+#if defined(PUF_CFG_PUF_BLOCK_ENROLL_MASK) && PUF_CFG_PUF_BLOCK_ENROLL_MASK
+static inline void PUF_BlockEnroll(PUF_Type *base)
+{
+ base->CFG |= PUF_CFG_PUF_BLOCK_ENROLL_MASK; /* block enroll */
+}
+#endif /* PUF_CFG_PUF_BLOCK_ENROLL_MASK */
+
+/*!
+ * @brief Powercycle PUF
+ *
+ * This function make powercycle.
+ *
+ * @param base PUF peripheral base address
+ * @param conf PUF configuration structure
+ * @return Status of the powercycle operation.
+ */
+status_t PUF_PowerCycle(PUF_Type *base, puf_config_t *conf);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+#endif /* _PUF_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.c b/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.c
new file mode 100644
index 0000000000..22dc817c30
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.c
@@ -0,0 +1,1328 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pwm.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pwm"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base PWM peripheral base address
+ *
+ * @return The PWM module instance
+ */
+static uint32_t PWM_GetInstance(PWM_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PWM bases for each instance. */
+static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PWM clocks for each PWM submodule. */
+static const clock_ip_name_t s_pwmClocks[][FSL_FEATURE_PWM_SUBMODULE_COUNT] = PWM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Temporary PWM duty cycle. */
+static uint8_t s_pwmGetPwmDutyCycle[FSL_FEATURE_PWM_SUBMODULE_COUNT][PWM_SUBMODULE_CHANNEL] = {{0}};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Complement the variable of type uint16_t as needed
+ *
+ * This function can complement the variable of type uint16_t as needed.For example,
+ * need to ask for the opposite of a positive integer.
+ *
+ * param value Parameters of type uint16_t
+ */
+static inline uint16_t PWM_GetComplementU16(uint16_t value)
+{
+ return (~value + 1U);
+}
+
+static inline uint16_t dutyCycleToReloadValue(uint8_t dutyCyclePercent)
+{
+ /* Rounding calculations to improve the accuracy of reloadValue */
+ return ((65535U * dutyCyclePercent) + 50U) / 100U;
+}
+
+static uint32_t PWM_GetInstance(PWM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
+ {
+ if (s_pwmBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pwmBases));
+
+ return instance;
+}
+
+/*!
+ * brief Ungates the PWM submodule clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the PWM driver.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param config Pointer to user's PWM config structure.
+ *
+ * return kStatus_Success means success; else failed.
+ */
+status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)
+{
+ assert(config);
+
+ uint16_t reg;
+
+ /* Source clock for submodule 0 cannot be itself */
+ if ((config->clockSource == kPWM_Submodule0Clock) && (subModule == kPWM_Module_0))
+ {
+ return kStatus_Fail;
+ }
+
+ /* Reload source select clock for submodule 0 cannot be master reload */
+ if ((config->reloadSelect == kPWM_MasterReload) && (subModule == kPWM_Module_0))
+ {
+ return kStatus_Fail;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the PWM submodule clock*/
+ CLOCK_EnableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Clear the fault status flags */
+ base->FSTS |= PWM_FSTS_FFLAG_MASK;
+
+ reg = base->SM[subModule].CTRL2;
+
+ /* Setup the submodule clock-source, control source of the INIT signal,
+ * source of the force output signal, operation in debug & wait modes and reload source select
+ */
+ reg &=
+ ~(uint16_t)(PWM_CTRL2_CLK_SEL_MASK | PWM_CTRL2_FORCE_SEL_MASK | PWM_CTRL2_INIT_SEL_MASK | PWM_CTRL2_INDEP_MASK |
+#if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
+ PWM_CTRL2_WAITEN_MASK |
+#endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
+ PWM_CTRL2_DBGEN_MASK | PWM_CTRL2_RELOAD_SEL_MASK);
+ reg |= (PWM_CTRL2_CLK_SEL(config->clockSource) | PWM_CTRL2_FORCE_SEL(config->forceTrigger) |
+ PWM_CTRL2_INIT_SEL(config->initializationControl) | PWM_CTRL2_DBGEN(config->enableDebugMode) |
+#if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
+ PWM_CTRL2_WAITEN(config->enableWait) |
+#endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
+ PWM_CTRL2_RELOAD_SEL(config->reloadSelect));
+
+ /* Setup PWM A & B to be independent or a complementary-pair */
+ switch (config->pairOperation)
+ {
+ case kPWM_Independent:
+ reg |= PWM_CTRL2_INDEP_MASK;
+ break;
+ case kPWM_ComplementaryPwmA:
+ base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_ComplementaryPwmB:
+ base->MCTRL |= ((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].CTRL2 = reg;
+
+ reg = base->SM[subModule].CTRL;
+
+ /* Setup the clock prescale, load mode and frequency */
+ reg &= ~(uint16_t)(PWM_CTRL_PRSC_MASK | PWM_CTRL_LDFQ_MASK | PWM_CTRL_LDMOD_MASK);
+ reg |= (PWM_CTRL_PRSC(config->prescale) | PWM_CTRL_LDFQ(config->reloadFrequency));
+
+ /* Setup register reload logic */
+ switch (config->reloadLogic)
+ {
+ case kPWM_ReloadImmediate:
+ reg |= PWM_CTRL_LDMOD_MASK;
+ break;
+ case kPWM_ReloadPwmHalfCycle:
+ reg |= PWM_CTRL_HALF_MASK;
+ reg &= (uint16_t)(~PWM_CTRL_FULL_MASK);
+ break;
+ case kPWM_ReloadPwmFullCycle:
+ reg &= (uint16_t)(~PWM_CTRL_HALF_MASK);
+ reg |= PWM_CTRL_FULL_MASK;
+ break;
+ case kPWM_ReloadPwmHalfAndFullCycle:
+ reg |= PWM_CTRL_HALF_MASK;
+ reg |= PWM_CTRL_FULL_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].CTRL = reg;
+
+ /* Set PWM output normal */
+ base->MASK &= ~(uint16_t)(PWM_MASK_MASKX_MASK | PWM_MASK_MASKA_MASK | PWM_MASK_MASKB_MASK);
+
+ base->DTSRCSEL = 0U;
+
+ /* Issue a Force trigger event when configured to trigger locally */
+ if (config->forceTrigger == kPWM_Force_Local)
+ {
+ base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE(1U);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gate the PWM submodule clock
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to deinitialize
+ */
+void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule)
+{
+ /* Stop the submodule */
+ base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_RUN_SHIFT + (uint16_t)subModule));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the PWM submodule clock*/
+ CLOCK_DisableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fill in the PWM config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->enableDebugMode = false;
+ * config->enableWait = false;
+ * config->reloadSelect = kPWM_LocalReload;
+ * config->clockSource = kPWM_BusClock;
+ * config->prescale = kPWM_Prescale_Divide_1;
+ * config->initializationControl = kPWM_Initialize_LocalSync;
+ * config->forceTrigger = kPWM_Force_Local;
+ * config->reloadFrequency = kPWM_LoadEveryOportunity;
+ * config->reloadLogic = kPWM_ReloadImmediate;
+ * config->pairOperation = kPWM_Independent;
+ * endcode
+ * param config Pointer to user's PWM config structure.
+ */
+void PWM_GetDefaultConfig(pwm_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* PWM is paused in debug mode */
+ config->enableDebugMode = false;
+ /* PWM is paused in wait mode */
+#if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
+ config->enableWait = false;
+#endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
+ /* PWM module uses the local reload signal to reload registers */
+ config->reloadSelect = kPWM_LocalReload;
+ /* Use the IP Bus clock as source clock for the PWM submodule */
+ config->clockSource = kPWM_BusClock;
+ /* Clock source prescale is set to divide by 1*/
+ config->prescale = kPWM_Prescale_Divide_1;
+ /* Local sync causes initialization */
+ config->initializationControl = kPWM_Initialize_LocalSync;
+ /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
+ config->forceTrigger = kPWM_Force_Local;
+ /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
+ * This field is not used in Immediate reload mode
+ */
+ config->reloadFrequency = kPWM_LoadEveryOportunity;
+ /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
+ config->reloadLogic = kPWM_ReloadImmediate;
+ /* PWM A & PWM B operate as 2 independent channels */
+ config->pairOperation = kPWM_Independent;
+}
+
+/*!
+ * brief Sets up the PWM signals for a PWM submodule.
+ *
+ * The function initializes the submodule according to the parameters passed in by the user. The function
+ * also sets up the value compare registers to match the PWM signal requirements.
+ * If the dead time insertion logic is enabled, the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param chnlParams Array of PWM channel parameters to configure the channel(s), PWMX submodule is not supported.
+ * param numOfChnls Number of channels to configure, this should be the size of the array passed in.
+ * Array size should not be more than 2 as each submodule has 2 pins to output PWM
+ * param mode PWM operation mode, options available in enumeration ::pwm_mode_t
+ * param pwmFreq_Hz PWM signal frequency in Hz
+ * param srcClock_Hz PWM main counter clock in Hz.
+ *
+ * return Returns kStatusFail if there was error setting up the signal; kStatusSuccess otherwise
+ */
+status_t PWM_SetupPwm(PWM_Type *base,
+ pwm_submodule_t subModule,
+ const pwm_signal_param_t *chnlParams,
+ uint8_t numOfChnls,
+ pwm_mode_t mode,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz)
+{
+ assert(chnlParams);
+ assert(pwmFreq_Hz);
+ assert(numOfChnls);
+ assert(srcClock_Hz);
+
+ uint32_t pwmClock;
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t modulo = 0;
+ uint8_t i, polarityShift = 0, outputEnableShift = 0;
+
+ for (i = 0; i < numOfChnls; i++)
+ {
+ if (chnlParams[i].pwmChannel == kPWM_PwmX)
+ {
+ /* PWMX configuration is not supported yet */
+ return kStatus_Fail;
+ }
+ }
+
+ /* Divide the clock by the prescale value */
+ pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+ pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
+
+ /* Setup each PWM channel */
+ for (i = 0; i < numOfChnls; i++)
+ {
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100U;
+
+ /* Setup the different match registers to generate the PWM signal */
+ switch (mode)
+ {
+ case kPWM_SignedCenterAligned:
+ /* Setup the PWM period for a signed center aligned signal */
+ if (i == 0U)
+ {
+ modulo = (pulseCnt >> 1U);
+ /* Indicates the start of the PWM period */
+ base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = 0;
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = modulo - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
+ }
+ break;
+ case kPWM_CenterAligned:
+ /* Setup the PWM period for an unsigned center aligned signal */
+ /* Indicates the start of the PWM period */
+ if (i == 0U)
+ {
+ base->SM[subModule].INIT = 0;
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = (pulseCnt / 2U);
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = pulseCnt - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ break;
+ case kPWM_SignedEdgeAligned:
+ /* Setup the PWM period for a signed edge aligned signal */
+ if (i == 0U)
+ {
+ modulo = (pulseCnt >> 1U);
+ /* Indicates the start of the PWM period */
+ base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = 0;
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = modulo - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ break;
+ case kPWM_EdgeAligned:
+ /* Setup the PWM period for a unsigned edge aligned signal */
+ /* Indicates the start of the PWM period */
+ if (i == 0U)
+ {
+ base->SM[subModule].INIT = 0;
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = (pulseCnt / 2U);
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = pulseCnt - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = 0;
+ base->SM[subModule].VAL3 = pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = 0;
+ base->SM[subModule].VAL5 = pwmHighPulse;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ /* Setup register shift values based on the channel being configured.
+ * Also setup the deadtime value
+ */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ polarityShift = PWM_OCTRL_POLA_SHIFT;
+ outputEnableShift = PWM_OUTEN_PWMA_EN_SHIFT;
+ base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
+ }
+ else
+ {
+ polarityShift = PWM_OCTRL_POLB_SHIFT;
+ outputEnableShift = PWM_OUTEN_PWMB_EN_SHIFT;
+ base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
+ }
+
+ /* Set PWM output fault status */
+ switch (chnlParams->pwmChannel)
+ {
+ case kPWM_PwmA:
+ base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) &
+ (uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ break;
+ case kPWM_PwmB:
+ base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) &
+ (uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ /* Setup signal active level */
+ if ((bool)chnlParams->level == kPWM_HighTrue)
+ {
+ base->SM[subModule].OCTRL &= ~((uint16_t)1U << (uint16_t)polarityShift);
+ }
+ else
+ {
+ base->SM[subModule].OCTRL |= ((uint16_t)1U << (uint16_t)polarityShift);
+ }
+ if (chnlParams->pwmchannelenable)
+ {
+ /* Enable PWM output */
+ base->OUTEN |= ((uint16_t)1U << ((uint16_t)outputEnableShift + (uint16_t)subModule));
+ }
+
+ /* Get the pwm duty cycle */
+ s_pwmGetPwmDutyCycle[subModule][chnlParams->pwmChannel] = chnlParams->dutyCyclePercent;
+
+ /* Get the next channel parameters */
+ chnlParams++;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set PWM phase shift for PWM channel running on channel PWM_A, PWM_B which with 50% duty cycle.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel PWM channel to configure
+ * param pwmFreq_Hz PWM signal frequency in Hz
+ * param srcClock_Hz PWM main counter clock in Hz.
+ * param shiftvalue Phase shift value, range in 0 ~ 50
+ * param doSync true: Set LDOK bit for the submodule list;
+ * false: LDOK bit don't set, need to call PWM_SetPwmLdok to sync update.
+ *
+ * return Returns kStatus_Fail if there was error setting up the signal; kStatus_Success otherwise
+ */
+status_t PWM_SetupPwmPhaseShift(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz,
+ uint8_t shiftvalue,
+ bool doSync)
+{
+ assert(pwmFreq_Hz != 0U);
+ assert(srcClock_Hz != 0U);
+ assert(shiftvalue <= 50U);
+
+ uint32_t pwmClock;
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t modulo = 0;
+ uint16_t shift = 0;
+
+ if (pwmChannel != kPWM_PwmX)
+ {
+ /* Divide the clock by the prescale value */
+ pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+ pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
+
+ /* Clear LDOK bit if it is set */
+ if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
+ {
+ base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
+ }
+
+ modulo = (pulseCnt >> 1U);
+ /* Indicates the start of the PWM period */
+ base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = 0;
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = modulo - 1U;
+
+ /* Immediately upon when MCTRL[LDOK] being set */
+ base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
+
+ /* phase shift value */
+ shift = (pulseCnt * shiftvalue) / 100U;
+
+ /* duty cycle 50% */
+ pwmHighPulse = pulseCnt / 2U;
+
+ if (pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo) + shift;
+ base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
+ }
+ else if (pwmChannel == kPWM_PwmB)
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo) + shift;
+ base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+
+ if (doSync)
+ {
+ /* Set LDOK bit to load VALx bit */
+ base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
+ }
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Updates the PWM signal's dutycycle.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmSignal Signal (PWM A or PWM B) to update
+ * param currPwmMode The current PWM mode set during PWM setup
+ * param dutyCyclePercent New PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycle(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmSignal,
+ pwm_mode_t currPwmMode,
+ uint8_t dutyCyclePercent)
+{
+ assert(dutyCyclePercent <= 100U);
+ assert(pwmSignal != kPWM_PwmX);
+ uint16_t reloadValue = dutyCycleToReloadValue(dutyCyclePercent);
+
+ PWM_UpdatePwmDutycycleHighAccuracy(base, subModule, pwmSignal, currPwmMode, reloadValue);
+}
+
+/*!
+ * brief Updates the PWM signal's dutycycle with 16-bit accuracy.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmSignal Signal (PWM A or PWM B) to update
+ * param currPwmMode The current PWM mode set during PWM setup
+ * param dutyCycle New PWM pulse width, value should be between 0 to 65535
+ * 0=inactive signal(0% duty cycle)...
+ * 65535=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycleHighAccuracy(
+ PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle)
+{
+ assert(pwmSignal != kPWM_PwmX);
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t modulo = 0;
+
+ switch (currPwmMode)
+ {
+ case kPWM_SignedCenterAligned:
+ modulo = base->SM[subModule].VAL1 + 1U;
+ pulseCnt = modulo * 2U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
+ }
+ else if (pwmSignal == kPWM_PwmB)
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
+ }
+ else
+ {
+ assert(false);
+ }
+ break;
+ case kPWM_CenterAligned:
+ pulseCnt = base->SM[subModule].VAL1 + 1U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ else if (pwmSignal == kPWM_PwmB)
+ {
+ base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ else
+ {
+ assert(false);
+ }
+ break;
+ case kPWM_SignedEdgeAligned:
+ modulo = base->SM[subModule].VAL1 + 1U;
+ pulseCnt = modulo * 2U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ else if (pwmSignal == kPWM_PwmB)
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ else
+ {
+ assert(false);
+ }
+ break;
+ case kPWM_EdgeAligned:
+ pulseCnt = base->SM[subModule].VAL1 + 1U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = 0;
+ base->SM[subModule].VAL3 = pwmHighPulse;
+ }
+ else if (pwmSignal == kPWM_PwmB)
+ {
+ base->SM[subModule].VAL4 = 0;
+ base->SM[subModule].VAL5 = pwmHighPulse;
+ }
+ else
+ {
+ assert(false);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ if (kPWM_PwmX != pwmSignal)
+ {
+ /* Get the pwm duty cycle */
+ s_pwmGetPwmDutyCycle[subModule][pwmSignal] = (uint8_t)(dutyCycle / 65535U);
+ }
+}
+
+/*!
+ * brief Sets up the PWM input capture
+ *
+ * Each PWM submodule has 3 pins that can be configured for use as input capture pins. This function
+ * sets up the capture parameters for each pin and enables the pin for input capture operation.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel Channel in the submodule to setup
+ * param inputCaptureParams Parameters passed in to set up the input pin
+ */
+void PWM_SetupInputCapture(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ const pwm_input_capture_param_t *inputCaptureParams)
+{
+ uint16_t reg = 0;
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ /* Setup the capture paramters for PWM A pin */
+ reg = (PWM_CAPTCTRLA_INP_SELA(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLA_EDGA0(inputCaptureParams->edge0) | PWM_CAPTCTRLA_EDGA1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLA_ONESHOTA(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLA_CFAWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLA_EDGCNTA_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLA_ARMA_MASK;
+
+ base->SM[subModule].CAPTCTRLA = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPA = PWM_CAPTCOMPA_EDGCMPA(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM A pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmB:
+ /* Setup the capture paramters for PWM B pin */
+ reg = (PWM_CAPTCTRLB_INP_SELB(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLB_EDGB0(inputCaptureParams->edge0) | PWM_CAPTCTRLB_EDGB1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLB_ONESHOTB(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLB_CFBWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLB_EDGCNTB_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLB_ARMB_MASK;
+
+ base->SM[subModule].CAPTCTRLB = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPB = PWM_CAPTCOMPB_EDGCMPB(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM B pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmX:
+ reg = (PWM_CAPTCTRLX_INP_SELX(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLX_EDGX0(inputCaptureParams->edge0) | PWM_CAPTCTRLX_EDGX1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLX_ONESHOTX(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLX_CFXWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLX_EDGCNTX_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLX_ARMX_MASK;
+
+ base->SM[subModule].CAPTCTRLX = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPX = PWM_CAPTCOMPX_EDGCMPX(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM X pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Sets up the PWM fault input filter.
+ *
+ * @param base PWM peripheral base address
+ * @param faultInputFilterParams Parameters passed in to set up the fault input filter.
+ */
+void PWM_SetupFaultInputFilter(PWM_Type *base, const pwm_fault_input_filter_param_t *faultInputFilterParams)
+{
+ assert(NULL != faultInputFilterParams);
+
+ /* When changing values for fault period from a non-zero value, first write a value of 0 to clear the filter. */
+ if (0U != (base->FFILT & PWM_FFILT_FILT_PER_MASK))
+ {
+ base->FFILT &= ~(uint16_t)(PWM_FFILT_FILT_PER_MASK);
+ }
+
+ base->FFILT = (uint16_t)(PWM_FFILT_FILT_PER(faultInputFilterParams->faultFilterPeriod) |
+ PWM_FFILT_FILT_CNT(faultInputFilterParams->faultFilterCount) |
+ PWM_FFILT_GSTR(faultInputFilterParams->faultGlitchStretch ? 1U : 0U));
+}
+
+/*!
+ * brief Sets up the PWM fault protection.
+ *
+ * PWM has 4 fault inputs.
+ *
+ * param base PWM peripheral base address
+ * param faultNum PWM fault to configure.
+ * param faultParams Pointer to the PWM fault config structure
+ */
+void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams)
+{
+ assert(faultParams);
+ uint16_t reg;
+
+ reg = base->FCTRL;
+ /* Set the faults level-settting */
+ if (faultParams->faultLevel)
+ {
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
+ }
+ else
+ {
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
+ }
+ /* Set the fault clearing mode */
+ if ((uint16_t)faultParams->faultClearingMode != 0U)
+ {
+ /* Use manual fault clearing */
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
+ if (faultParams->faultClearingMode == kPWM_ManualSafety)
+ {
+ /* Use manual fault clearing with safety mode enabled */
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
+ }
+ else
+ {
+ /* Use manual fault clearing with safety mode disabled */
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
+ }
+ }
+ else
+ {
+ /* Use automatic fault clearing */
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
+ }
+ base->FCTRL = reg;
+
+ /* Set the combinational path option */
+ if (faultParams->enableCombinationalPath)
+ {
+ /* Combinational path from the fault input to the PWM output is available */
+ base->FCTRL2 &= ~((uint16_t)1U << (uint16_t)faultNum);
+ }
+ else
+ {
+ /* No combinational path available, only fault filter & latch signal can disable PWM output */
+ base->FCTRL2 |= ((uint16_t)1U << (uint16_t)faultNum);
+ }
+
+ /* Initially clear both recovery modes */
+ reg = base->FSTS;
+ reg &= ~(((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum)) |
+ ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum)));
+ /* Setup fault recovery */
+ switch (faultParams->recoverMode)
+ {
+ case kPWM_NoRecovery:
+ break;
+ case kPWM_RecoverHalfCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
+ break;
+ case kPWM_RecoverFullCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
+ break;
+ case kPWM_RecoverHalfAndFullCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
+ reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->FSTS = reg;
+}
+
+/*!
+ * brief Fill in the PWM fault config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->faultClearingMode = kPWM_Automatic;
+ * config->faultLevel = false;
+ * config->enableCombinationalPath = true;
+ * config->recoverMode = kPWM_NoRecovery;
+ * endcode
+ * param config Pointer to user's PWM fault config structure.
+ */
+void PWM_FaultDefaultConfig(pwm_fault_param_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* PWM uses automatic fault clear mode */
+ config->faultClearingMode = kPWM_Automatic;
+ /* PWM fault level is set to logic 0 */
+ config->faultLevel = false;
+ /* Combinational Path from fault input is enabled */
+ config->enableCombinationalPath = true;
+ /* PWM output will stay inactive when recovering from a fault */
+ config->recoverMode = kPWM_NoRecovery;
+}
+
+/*!
+ * brief Selects the signal to output on a PWM pin when a FORCE_OUT signal is asserted.
+ *
+ * The user specifies which channel to configure by supplying the submodule number and whether
+ * to modify PWM A or PWM B within that submodule.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel Channel to configure
+ * param mode Signal to output when a FORCE_OUT is triggered
+ */
+void PWM_SetupForceSignal(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, pwm_force_signal_t mode)
+
+{
+ uint16_t shift;
+ uint16_t reg;
+
+ /* DTSRCSEL register has 4 bits per submodule; 2 bits for PWM A and 2 bits for PWM B */
+ shift = ((uint16_t)subModule * 4U) + ((uint16_t)pwmChannel * 2U);
+
+ /* Setup the signal to be passed upon occurrence of a FORCE_OUT signal */
+ reg = base->DTSRCSEL;
+ reg &= ~((uint16_t)0x3U << shift);
+ reg |= (uint16_t)((uint16_t)mode << shift);
+ base->DTSRCSEL = reg;
+}
+
+/*!
+ * brief Enables the selected PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ /* Upper 16 bits are for related to the submodule */
+ base->SM[subModule].INTEN |= ((uint16_t)mask & 0xFFFFU);
+ /* Fault related interrupts */
+ base->FCTRL |= ((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
+}
+
+/*!
+ * brief Disables the selected PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ base->SM[subModule].INTEN &= ~((uint16_t)mask & 0xFFFFU);
+ base->FCTRL &= ~((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
+}
+
+/*!
+ * brief Gets the enabled PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule)
+{
+ uint32_t enabledInterrupts;
+
+ enabledInterrupts = base->SM[subModule].INTEN;
+ enabledInterrupts |= (((uint32_t)base->FCTRL & PWM_FCTRL_FIE_MASK) << 16UL);
+ return enabledInterrupts;
+}
+
+/*!
+ * brief Gets the PWM status flags
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule)
+{
+ uint32_t statusFlags;
+
+ statusFlags = base->SM[subModule].STS;
+ statusFlags |= (((uint32_t)base->FSTS & PWM_FSTS_FFLAG_MASK) << 16UL);
+
+ return statusFlags;
+}
+
+/*!
+ * brief Clears the PWM status flags
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ uint16_t reg;
+
+ base->SM[subModule].STS = ((uint16_t)mask & 0xFFFFU);
+ reg = base->FSTS;
+ /* Clear the fault flags and set only the ones we wish to clear as the fault flags are cleared
+ * by writing a login one
+ */
+ reg &= ~(uint16_t)(PWM_FSTS_FFLAG_MASK);
+ reg |= (uint16_t)((mask >> 16U) & PWM_FSTS_FFLAG_MASK);
+ base->FSTS = reg;
+}
+
+/*!
+ * brief Set PWM output in idle status (high or low).
+ *
+ * note This API should call after PWM_SetupPwm() APIs, and PWMX submodule is not supported.
+ *
+ * param base PWM peripheral base address
+ * param pwmChannel PWM channel to configure
+ * param subModule PWM submodule to configure
+ * param idleStatus True: PWM output is high in idle status; false: PWM output is low in idle status.
+ *
+ * return kStatus_Fail if there was error setting up the signal; kStatus_Success if set output idle success
+ */
+status_t PWM_SetOutputToIdle(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule, bool idleStatus)
+{
+ uint16_t valOn = 0, valOff = 0;
+ uint16_t ldmod;
+
+ /* Clear LDOK bit if it is set */
+ if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
+ {
+ base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
+ }
+
+ valOff = base->SM[subModule].INIT;
+ valOn = base->SM[subModule].VAL1 + 0x1U;
+
+ if ((valOff + 1U) == valOn)
+ {
+ return kStatus_Fail;
+ }
+
+ /* Should not PWM_X channel */
+ if (kPWM_PwmA == pwmChannel)
+ {
+ if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLA_MASK))
+ {
+ if (!idleStatus)
+ {
+ valOn = base->SM[subModule].INIT;
+ valOff = base->SM[subModule].VAL1 + 0x1U;
+ }
+ }
+ else
+ {
+ if (idleStatus)
+ {
+ valOn = base->SM[subModule].INIT;
+ valOff = base->SM[subModule].VAL1 + 0x1U;
+ }
+ }
+ base->SM[subModule].VAL2 = valOn;
+ base->SM[subModule].VAL3 = valOff;
+ }
+ else if (kPWM_PwmB == pwmChannel)
+ {
+ if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLB_MASK))
+ {
+ if (!idleStatus)
+ {
+ valOn = base->SM[subModule].INIT;
+ valOff = base->SM[subModule].VAL1 + 0x1U;
+ }
+ }
+ else
+ {
+ if (idleStatus)
+ {
+ valOn = base->SM[subModule].INIT;
+ valOff = base->SM[subModule].VAL1 + 0x1U;
+ }
+ }
+ base->SM[subModule].VAL4 = valOn;
+ base->SM[subModule].VAL5 = valOff;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+
+ /* Record Load mode */
+ ldmod = base->SM[subModule].CTRL;
+ /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
+ base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
+ /* Set LDOK bit to load buffer registers */
+ base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
+ /* Restore Load mode */
+ base->SM[subModule].CTRL = ldmod;
+
+ /* Get pwm duty cycle */
+ s_pwmGetPwmDutyCycle[subModule][pwmChannel] = 0x0U;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get the dutycycle value.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel PWM channel to configure
+ *
+ * return Current channel dutycycle value.
+ */
+uint8_t PWM_GetPwmChannelState(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel)
+{
+ return s_pwmGetPwmDutyCycle[subModule][pwmChannel];
+}
+
+/*!
+ * brief Set the pwm submodule prescaler.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param prescaler Set prescaler value
+ */
+void PWM_SetClockMode(PWM_Type *base, pwm_submodule_t subModule, pwm_clock_prescale_t prescaler)
+{
+ uint16_t reg = base->SM[subModule].CTRL;
+
+ /* Clear LDOK bit if it is set */
+ if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
+ {
+ base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
+ }
+ /* Set submodule prescaler. */
+ reg &= ~(uint16_t)PWM_CTRL_PRSC_MASK;
+ reg |= PWM_CTRL_PRSC(prescaler);
+ base->SM[subModule].CTRL = reg;
+ /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
+ base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
+ /* Set LDOK bit to load buffer registers */
+ base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
+ /* Restore Load mode */
+ base->SM[subModule].CTRL = reg;
+}
+
+/*!
+ * brief This function enables-disables the forcing of the output of a given eFlexPwm channel to logic 0.
+ *
+ * param base PWM peripheral base address
+ * param pwmChannel PWM channel to configure
+ * param subModule PWM submodule to configure
+ * param forcetozero True: Enable the pwm force output to zero; False: Disable the pwm output resumes normal
+ * function.
+ */
+void PWM_SetPwmForceOutputToZero(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, bool forcetozero)
+{
+ uint16_t reg = base->SM[subModule].CTRL2;
+ uint16_t mask;
+
+ if (kPWM_PwmA == pwmChannel)
+ {
+ mask = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
+ }
+ else if (kPWM_PwmB == pwmChannel)
+ {
+ mask = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
+ }
+ else
+ {
+ mask = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
+ }
+
+ if (forcetozero)
+ {
+ /* Disables the channel output, forcing output level to 0 */
+ base->MASK |= mask;
+ }
+ else
+ {
+ /* Enables the channel output */
+ base->MASK &= ~mask;
+ }
+
+ /* Select local force signal */
+ base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
+ /* Issue a local Force trigger event */
+ base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
+ /* Restore the source of FORCE OUTPUT signal */
+ base->SM[subModule].CTRL2 = reg;
+}
+
+/*!
+ * brief This function set the output state of the PWM pin as requested for the current cycle.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel PWM channel to configure
+ * param outputstate Set pwm output state, see @ref pwm_output_state_t.
+ */
+void PWM_SetChannelOutput(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ pwm_output_state_t outputstate)
+{
+ uint16_t mask, swcout, sourceShift;
+ uint16_t reg = base->SM[subModule].CTRL2;
+
+ if (kPWM_PwmA == pwmChannel)
+ {
+ mask = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
+ swcout = (uint16_t)PWM_SWCOUT_SM0OUT23_MASK << ((uint8_t)subModule * 2U);
+ sourceShift = PWM_DTSRCSEL_SM0SEL23_SHIFT + ((uint16_t)subModule * 4U);
+ }
+ else if (kPWM_PwmB == pwmChannel)
+ {
+ mask = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
+ swcout = (uint16_t)PWM_SWCOUT_SM0OUT45_MASK << ((uint8_t)subModule * 2U);
+ sourceShift = PWM_DTSRCSEL_SM0SEL45_SHIFT + ((uint16_t)subModule * 4U);
+ }
+ else
+ {
+ mask = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
+ swcout = 0U;
+ sourceShift = 0U;
+ }
+
+ if (kPWM_MaskState == outputstate)
+ {
+ /* Disables the channel output, forcing output level to 0 */
+ base->MASK |= mask;
+ }
+ else
+ {
+ /* Enables the channel output first */
+ base->MASK &= ~mask;
+ /* PwmX only support MASK mode */
+ if (kPWM_PwmX != pwmChannel)
+ {
+ if (kPWM_HighState == outputstate)
+ {
+ base->SWCOUT |= swcout;
+ base->DTSRCSEL =
+ (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
+ }
+ else if (kPWM_LowState == outputstate)
+ {
+ base->SWCOUT &= ~swcout;
+ base->DTSRCSEL =
+ (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
+ }
+ else if (kPWM_NormalState == outputstate)
+ {
+ base->DTSRCSEL &= ~(uint16_t)(0x3UL << sourceShift);
+ }
+ else
+ {
+ base->DTSRCSEL =
+ (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x1UL << sourceShift);
+ }
+ }
+ }
+
+ /* Select local force signal */
+ base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
+ /* Issue a local Force trigger event */
+ base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
+ /* Restore the source of FORCE OUTPUT signal */
+ base->SM[subModule].CTRL2 = reg;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.h b/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.h
new file mode 100644
index 0000000000..f90f384a4a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pwm/fsl_pwm.h
@@ -0,0 +1,1225 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PWM_H_
+#define _FSL_PWM_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup pwm_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @name Driver version */
+/*@{*/
+#define FSL_PWM_DRIVER_VERSION (MAKE_VERSION(2, 5, 1)) /*!< Version 2.5.1 */
+/*@}*/
+
+/*! Number of bits per submodule for software output control */
+#define PWM_SUBMODULE_SWCONTROL_WIDTH 2
+/*! Because setting the pwm duty cycle doesn't support PWMX, getting the pwm duty cycle also doesn't support PWMX. */
+#define PWM_SUBMODULE_CHANNEL 2
+
+/*! @brief List of PWM submodules */
+typedef enum _pwm_submodule
+{
+ kPWM_Module_0 = 0U, /*!< Submodule 0 */
+ kPWM_Module_1, /*!< Submodule 1 */
+ kPWM_Module_2, /*!< Submodule 2 */
+ kPWM_Module_3 /*!< Submodule 3 */
+} pwm_submodule_t;
+
+/*! @brief List of PWM channels in each module */
+typedef enum _pwm_channels
+{
+ kPWM_PwmB = 0U,
+ kPWM_PwmA,
+ kPWM_PwmX
+} pwm_channels_t;
+
+/*! @brief List of PWM value registers */
+typedef enum _pwm_value_register
+{
+ kPWM_ValueRegister_0 = 0U, /*!< PWM Value0 register */
+ kPWM_ValueRegister_1, /*!< PWM Value1 register */
+ kPWM_ValueRegister_2, /*!< PWM Value2 register */
+ kPWM_ValueRegister_3, /*!< PWM Value3 register */
+ kPWM_ValueRegister_4, /*!< PWM Value4 register */
+ kPWM_ValueRegister_5 /*!< PWM Value5 register */
+} pwm_value_register_t;
+
+/*! @brief List of PWM value registers mask */
+enum _pwm_value_register_mask
+{
+ kPWM_ValueRegisterMask_0 = (1U << 0), /*!< PWM Value0 register mask */
+ kPWM_ValueRegisterMask_1 = (1U << 1), /*!< PWM Value1 register mask */
+ kPWM_ValueRegisterMask_2 = (1U << 2), /*!< PWM Value2 register mask */
+ kPWM_ValueRegisterMask_3 = (1U << 3), /*!< PWM Value3 register mask */
+ kPWM_ValueRegisterMask_4 = (1U << 4), /*!< PWM Value4 register mask */
+ kPWM_ValueRegisterMask_5 = (1U << 5) /*!< PWM Value5 register mask */
+};
+
+/*! @brief PWM clock source selection.*/
+typedef enum _pwm_clock_source
+{
+ kPWM_BusClock = 0U, /*!< The IPBus clock is used as the clock */
+ kPWM_ExternalClock, /*!< EXT_CLK is used as the clock */
+ kPWM_Submodule0Clock /*!< Clock of the submodule 0 (AUX_CLK) is used as the source clock */
+} pwm_clock_source_t;
+
+/*! @brief PWM prescaler factor selection for clock source*/
+typedef enum _pwm_clock_prescale
+{
+ kPWM_Prescale_Divide_1 = 0U, /*!< PWM clock frequency = fclk/1 */
+ kPWM_Prescale_Divide_2, /*!< PWM clock frequency = fclk/2 */
+ kPWM_Prescale_Divide_4, /*!< PWM clock frequency = fclk/4 */
+ kPWM_Prescale_Divide_8, /*!< PWM clock frequency = fclk/8 */
+ kPWM_Prescale_Divide_16, /*!< PWM clock frequency = fclk/16 */
+ kPWM_Prescale_Divide_32, /*!< PWM clock frequency = fclk/32 */
+ kPWM_Prescale_Divide_64, /*!< PWM clock frequency = fclk/64 */
+ kPWM_Prescale_Divide_128 /*!< PWM clock frequency = fclk/128 */
+} pwm_clock_prescale_t;
+
+/*! @brief Options that can trigger a PWM FORCE_OUT */
+typedef enum _pwm_force_output_trigger
+{
+ kPWM_Force_Local = 0U, /*!< The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
+ kPWM_Force_Master, /*!< The master force signal from submodule 0 is used to force updates */
+ kPWM_Force_LocalReload, /*!< The local reload signal from this submodule is used to force updates without regard to
+ the state of LDOK */
+ kPWM_Force_MasterReload, /*!< The master reload signal from submodule 0 is used to force updates if LDOK is set */
+ kPWM_Force_LocalSync, /*!< The local sync signal from this submodule is used to force updates */
+ kPWM_Force_MasterSync, /*!< The master sync signal from submodule0 is used to force updates */
+ kPWM_Force_External, /*!< The external force signal, EXT_FORCE, from outside the PWM module causes updates */
+ kPWM_Force_ExternalSync /*!< The external sync signal, EXT_SYNC, from outside the PWM module causes updates */
+} pwm_force_output_trigger_t;
+
+/*! @brief PWM channel output status */
+typedef enum _pwm_output_state
+{
+ kPWM_HighState = 0, /*!< The output state of PWM channel is high */
+ kPWM_LowState, /*!< The output state of PWM channel is low */
+ kPWM_NormalState, /*!< The output state of PWM channel is normal */
+ kPWM_InvertState, /*!< The output state of PWM channel is invert */
+ kPWM_MaskState /*!< The output state of PWM channel is mask */
+} pwm_output_state_t;
+
+/*! @brief PWM counter initialization options */
+typedef enum _pwm_init_source
+{
+ kPWM_Initialize_LocalSync = 0U, /*!< Local sync causes initialization */
+ kPWM_Initialize_MasterReload, /*!< Master reload from submodule 0 causes initialization */
+ kPWM_Initialize_MasterSync, /*!< Master sync from submodule 0 causes initialization */
+ kPWM_Initialize_ExtSync /*!< EXT_SYNC causes initialization */
+} pwm_init_source_t;
+
+/*! @brief PWM load frequency selection */
+typedef enum _pwm_load_frequency
+{
+ kPWM_LoadEveryOportunity = 0U, /*!< Every PWM opportunity */
+ kPWM_LoadEvery2Oportunity, /*!< Every 2 PWM opportunities */
+ kPWM_LoadEvery3Oportunity, /*!< Every 3 PWM opportunities */
+ kPWM_LoadEvery4Oportunity, /*!< Every 4 PWM opportunities */
+ kPWM_LoadEvery5Oportunity, /*!< Every 5 PWM opportunities */
+ kPWM_LoadEvery6Oportunity, /*!< Every 6 PWM opportunities */
+ kPWM_LoadEvery7Oportunity, /*!< Every 7 PWM opportunities */
+ kPWM_LoadEvery8Oportunity, /*!< Every 8 PWM opportunities */
+ kPWM_LoadEvery9Oportunity, /*!< Every 9 PWM opportunities */
+ kPWM_LoadEvery10Oportunity, /*!< Every 10 PWM opportunities */
+ kPWM_LoadEvery11Oportunity, /*!< Every 11 PWM opportunities */
+ kPWM_LoadEvery12Oportunity, /*!< Every 12 PWM opportunities */
+ kPWM_LoadEvery13Oportunity, /*!< Every 13 PWM opportunities */
+ kPWM_LoadEvery14Oportunity, /*!< Every 14 PWM opportunities */
+ kPWM_LoadEvery15Oportunity, /*!< Every 15 PWM opportunities */
+ kPWM_LoadEvery16Oportunity /*!< Every 16 PWM opportunities */
+} pwm_load_frequency_t;
+
+/*! @brief List of PWM fault selections */
+typedef enum _pwm_fault_input
+{
+ kPWM_Fault_0 = 0U, /*!< Fault 0 input pin */
+ kPWM_Fault_1, /*!< Fault 1 input pin */
+ kPWM_Fault_2, /*!< Fault 2 input pin */
+ kPWM_Fault_3 /*!< Fault 3 input pin */
+} pwm_fault_input_t;
+
+/*! @brief List of PWM fault disable mapping selections */
+typedef enum _pwm_fault_disable
+{
+ kPWM_FaultDisable_0 = (1U << 0), /*!< Fault 0 disable mapping */
+ kPWM_FaultDisable_1 = (1U << 1), /*!< Fault 1 disable mapping */
+ kPWM_FaultDisable_2 = (1U << 2), /*!< Fault 2 disable mapping */
+ kPWM_FaultDisable_3 = (1U << 3) /*!< Fault 3 disable mapping */
+} pwm_fault_disable_t;
+
+/*! @brief List of PWM fault channels */
+typedef enum _pwm_fault_channels
+{
+ kPWM_faultchannel_0 = 0U,
+ kPWM_faultchannel_1
+} pwm_fault_channels_t;
+
+/*! @brief PWM capture edge select */
+typedef enum _pwm_input_capture_edge
+{
+ kPWM_Disable = 0U, /*!< Disabled */
+ kPWM_FallingEdge, /*!< Capture on falling edge only */
+ kPWM_RisingEdge, /*!< Capture on rising edge only */
+ kPWM_RiseAndFallEdge /*!< Capture on rising or falling edge */
+} pwm_input_capture_edge_t;
+
+/*! @brief PWM output options when a FORCE_OUT signal is asserted */
+typedef enum _pwm_force_signal
+{
+ kPWM_UsePwm = 0U, /*!< Generated PWM signal is used by the deadtime logic.*/
+ kPWM_InvertedPwm, /*!< Inverted PWM signal is used by the deadtime logic.*/
+ kPWM_SoftwareControl, /*!< Software controlled value is used by the deadtime logic. */
+ kPWM_UseExternal /*!< PWM_EXTA signal is used by the deadtime logic. */
+} pwm_force_signal_t;
+
+/*! @brief Options available for the PWM A & B pair operation */
+typedef enum _pwm_chnl_pair_operation
+{
+ kPWM_Independent = 0U, /*!< PWM A & PWM B operate as 2 independent channels */
+ kPWM_ComplementaryPwmA, /*!< PWM A & PWM B are complementary channels, PWM A generates the signal */
+ kPWM_ComplementaryPwmB /*!< PWM A & PWM B are complementary channels, PWM B generates the signal */
+} pwm_chnl_pair_operation_t;
+
+/*! @brief Options available on how to load the buffered-registers with new values */
+typedef enum _pwm_register_reload
+{
+ kPWM_ReloadImmediate = 0U, /*!< Buffered-registers get loaded with new values as soon as LDOK bit is set */
+ kPWM_ReloadPwmHalfCycle, /*!< Registers loaded on a PWM half cycle */
+ kPWM_ReloadPwmFullCycle, /*!< Registers loaded on a PWM full cycle */
+ kPWM_ReloadPwmHalfAndFullCycle /*!< Registers loaded on a PWM half & full cycle */
+} pwm_register_reload_t;
+
+/*! @brief Options available on how to re-enable the PWM output when recovering from a fault */
+typedef enum _pwm_fault_recovery_mode
+{
+ kPWM_NoRecovery = 0U, /*!< PWM output will stay inactive */
+ kPWM_RecoverHalfCycle, /*!< PWM output re-enabled at the first half cycle */
+ kPWM_RecoverFullCycle, /*!< PWM output re-enabled at the first full cycle */
+ kPWM_RecoverHalfAndFullCycle /*!< PWM output re-enabled at the first half or full cycle */
+} pwm_fault_recovery_mode_t;
+
+/*! @brief List of PWM interrupt options */
+typedef enum _pwm_interrupt_enable
+{
+ kPWM_CompareVal0InterruptEnable = (1U << 0), /*!< PWM VAL0 compare interrupt */
+ kPWM_CompareVal1InterruptEnable = (1U << 1), /*!< PWM VAL1 compare interrupt */
+ kPWM_CompareVal2InterruptEnable = (1U << 2), /*!< PWM VAL2 compare interrupt */
+ kPWM_CompareVal3InterruptEnable = (1U << 3), /*!< PWM VAL3 compare interrupt */
+ kPWM_CompareVal4InterruptEnable = (1U << 4), /*!< PWM VAL4 compare interrupt */
+ kPWM_CompareVal5InterruptEnable = (1U << 5), /*!< PWM VAL5 compare interrupt */
+ kPWM_CaptureX0InterruptEnable = (1U << 6), /*!< PWM capture X0 interrupt */
+ kPWM_CaptureX1InterruptEnable = (1U << 7), /*!< PWM capture X1 interrupt */
+ kPWM_CaptureB0InterruptEnable = (1U << 8), /*!< PWM capture B0 interrupt */
+ kPWM_CaptureB1InterruptEnable = (1U << 9), /*!< PWM capture B1 interrupt */
+ kPWM_CaptureA0InterruptEnable = (1U << 10), /*!< PWM capture A0 interrupt */
+ kPWM_CaptureA1InterruptEnable = (1U << 11), /*!< PWM capture A1 interrupt */
+ kPWM_ReloadInterruptEnable = (1U << 12), /*!< PWM reload interrupt */
+ kPWM_ReloadErrorInterruptEnable = (1U << 13), /*!< PWM reload error interrupt */
+ kPWM_Fault0InterruptEnable = (1U << 16), /*!< PWM fault 0 interrupt */
+ kPWM_Fault1InterruptEnable = (1U << 17), /*!< PWM fault 1 interrupt */
+ kPWM_Fault2InterruptEnable = (1U << 18), /*!< PWM fault 2 interrupt */
+ kPWM_Fault3InterruptEnable = (1U << 19) /*!< PWM fault 3 interrupt */
+} pwm_interrupt_enable_t;
+
+/*! @brief List of PWM status flags */
+typedef enum _pwm_status_flags
+{
+ kPWM_CompareVal0Flag = (1U << 0), /*!< PWM VAL0 compare flag */
+ kPWM_CompareVal1Flag = (1U << 1), /*!< PWM VAL1 compare flag */
+ kPWM_CompareVal2Flag = (1U << 2), /*!< PWM VAL2 compare flag */
+ kPWM_CompareVal3Flag = (1U << 3), /*!< PWM VAL3 compare flag */
+ kPWM_CompareVal4Flag = (1U << 4), /*!< PWM VAL4 compare flag */
+ kPWM_CompareVal5Flag = (1U << 5), /*!< PWM VAL5 compare flag */
+ kPWM_CaptureX0Flag = (1U << 6), /*!< PWM capture X0 flag */
+ kPWM_CaptureX1Flag = (1U << 7), /*!< PWM capture X1 flag */
+ kPWM_CaptureB0Flag = (1U << 8), /*!< PWM capture B0 flag */
+ kPWM_CaptureB1Flag = (1U << 9), /*!< PWM capture B1 flag */
+ kPWM_CaptureA0Flag = (1U << 10), /*!< PWM capture A0 flag */
+ kPWM_CaptureA1Flag = (1U << 11), /*!< PWM capture A1 flag */
+ kPWM_ReloadFlag = (1U << 12), /*!< PWM reload flag */
+ kPWM_ReloadErrorFlag = (1U << 13), /*!< PWM reload error flag */
+ kPWM_RegUpdatedFlag = (1U << 14), /*!< PWM registers updated flag */
+ kPWM_Fault0Flag = (1U << 16), /*!< PWM fault 0 flag */
+ kPWM_Fault1Flag = (1U << 17), /*!< PWM fault 1 flag */
+ kPWM_Fault2Flag = (1U << 18), /*!< PWM fault 2 flag */
+ kPWM_Fault3Flag = (1U << 19) /*!< PWM fault 3 flag */
+} pwm_status_flags_t;
+
+/*! @brief List of PWM DMA options */
+typedef enum _pwm_dma_enable
+{
+ kPWM_CaptureX0DMAEnable = (1U << 0), /*!< PWM capture X0 DMA */
+ kPWM_CaptureX1DMAEnable = (1U << 1), /*!< PWM capture X1 DMA */
+ kPWM_CaptureB0DMAEnable = (1U << 2), /*!< PWM capture B0 DMA */
+ kPWM_CaptureB1DMAEnable = (1U << 3), /*!< PWM capture B1 DMA */
+ kPWM_CaptureA0DMAEnable = (1U << 4), /*!< PWM capture A0 DMA */
+ kPWM_CaptureA1DMAEnable = (1U << 5) /*!< PWM capture A1 DMA */
+} pwm_dma_enable_t;
+
+/*! @brief List of PWM capture DMA enable source select */
+typedef enum _pwm_dma_source_select
+{
+ kPWM_DMARequestDisable = 0U, /*!< Read DMA requests disabled */
+ kPWM_DMAWatermarksEnable, /*!< Exceeding a FIFO watermark sets the DMA read request */
+ kPWM_DMALocalSync, /*!< A local sync (VAL1 matches counter) sets the read DMA request */
+ kPWM_DMALocalReload /*!< A local reload (STS[RF] being set) sets the read DMA request */
+} pwm_dma_source_select_t;
+
+/*! @brief PWM FIFO Watermark AND Control */
+typedef enum _pwm_watermark_control
+{
+ kPWM_FIFOWatermarksOR = 0U, /*!< Selected FIFO watermarks are OR'ed together */
+ kPWM_FIFOWatermarksAND /*!< Selected FIFO watermarks are AND'ed together */
+} pwm_watermark_control_t;
+
+/*! @brief PWM operation mode */
+typedef enum _pwm_mode
+{
+ kPWM_SignedCenterAligned = 0U, /*!< Signed center-aligned */
+ kPWM_CenterAligned, /*!< Unsigned cente-aligned */
+ kPWM_SignedEdgeAligned, /*!< Signed edge-aligned */
+ kPWM_EdgeAligned /*!< Unsigned edge-aligned */
+} pwm_mode_t;
+
+/*! @brief PWM output pulse mode, high-true or low-true */
+typedef enum _pwm_level_select
+{
+ kPWM_HighTrue = 0U, /*!< High level represents "on" or "active" state */
+ kPWM_LowTrue /*!< Low level represents "on" or "active" state */
+} pwm_level_select_t;
+
+/*! @brief PWM output fault status */
+typedef enum _pwm_fault_state
+{
+ kPWM_PwmFaultState0 =
+ 0U, /*!< Output is forced to logic 0 state prior to consideration of output polarity control. */
+ kPWM_PwmFaultState1, /*!< Output is forced to logic 1 state prior to consideration of output polarity control. */
+ kPWM_PwmFaultState2, /*!< Output is tristated. */
+ kPWM_PwmFaultState3 /*!< Output is tristated. */
+} pwm_fault_state_t;
+
+/*! @brief PWM reload source select */
+typedef enum _pwm_reload_source_select
+{
+ kPWM_LocalReload = 0U, /*!< The local reload signal is used to reload registers */
+ kPWM_MasterReload /*!< The master reload signal (from submodule 0) is used to reload */
+} pwm_reload_source_select_t;
+
+/*! @brief PWM fault clearing options */
+typedef enum _pwm_fault_clear
+{
+ kPWM_Automatic = 0U, /*!< Automatic fault clearing */
+ kPWM_ManualNormal, /*!< Manual fault clearing with no fault safety mode */
+ kPWM_ManualSafety /*!< Manual fault clearing with fault safety mode */
+} pwm_fault_clear_t;
+
+/*! @brief Options for submodule master control operation */
+typedef enum _pwm_module_control
+{
+ kPWM_Control_Module_0 = (1U << 0), /*!< Control submodule 0's start/stop,buffer reload operation */
+ kPWM_Control_Module_1 = (1U << 1), /*!< Control submodule 1's start/stop,buffer reload operation */
+ kPWM_Control_Module_2 = (1U << 2), /*!< Control submodule 2's start/stop,buffer reload operation */
+ kPWM_Control_Module_3 = (1U << 3) /*!< Control submodule 3's start/stop,buffer reload operation */
+} pwm_module_control_t;
+
+/*! @brief Structure for the user to define the PWM signal characteristics */
+typedef struct _pwm_signal_param
+{
+ pwm_channels_t pwmChannel; /*!< PWM channel being configured; PWM A or PWM B */
+ uint8_t dutyCyclePercent; /*!< PWM pulse width, value should be between 0 to 100
+ 0=inactive signal(0% duty cycle)...
+ 100=always active signal (100% duty cycle)*/
+ pwm_level_select_t level; /*!< PWM output active level select */
+ uint16_t deadtimeValue; /*!< The deadtime value; only used if channel pair is operating in complementary mode */
+ pwm_fault_state_t faultState; /*!< PWM output fault status */
+ bool pwmchannelenable; /*!< Enable PWM output */
+} pwm_signal_param_t;
+
+/*!
+ * @brief PWM config structure
+ *
+ * This structure holds the configuration settings for the PWM peripheral. To initialize this
+ * structure to reasonable defaults, call the PWM_GetDefaultConfig() function and pass a
+ * pointer to your config structure instance.
+ *
+ * The config struct can be made const so it resides in flash
+ */
+typedef struct _pwm_config
+{
+ bool enableDebugMode; /*!< true: PWM continues to run in debug mode;
+ false: PWM is paused in debug mode */
+#if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
+ bool enableWait; /*!< true: PWM continues to run in WAIT mode;
+ false: PWM is paused in WAIT mode */
+#endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
+ pwm_init_source_t initializationControl; /*!< Option to initialize the counter */
+ pwm_clock_source_t clockSource; /*!< Clock source for the counter */
+ pwm_clock_prescale_t prescale; /*!< Pre-scaler to divide down the clock */
+ pwm_chnl_pair_operation_t pairOperation; /*!< Channel pair in indepedent or complementary mode */
+ pwm_register_reload_t reloadLogic; /*!< PWM Reload logic setup */
+ pwm_reload_source_select_t reloadSelect; /*!< Reload source select */
+ pwm_load_frequency_t reloadFrequency; /*!< Specifies when to reload, used when user's choice
+ is not immediate reload */
+ pwm_force_output_trigger_t forceTrigger; /*!< Specify which signal will trigger a FORCE_OUT */
+} pwm_config_t;
+
+/*! @brief Structure for the user to configure the fault input filter. */
+typedef struct _pwm_fault_input_filter_param
+{
+ uint8_t faultFilterCount; /*!< Fault filter count */
+ uint8_t faultFilterPeriod; /*!< Fault filter period;value of 0 will bypass the filter */
+ bool faultGlitchStretch; /*!< Fault Glitch Stretch Enable: A logic 1 means that input
+ fault signals will be stretched to at least 2 IPBus clock cycles */
+} pwm_fault_input_filter_param_t;
+
+/*! @brief Structure is used to hold the parameters to configure a PWM fault */
+typedef struct _pwm_fault_param
+{
+ pwm_fault_clear_t faultClearingMode; /*!< Fault clearing mode to use */
+ bool faultLevel; /*!< true: Logic 1 indicates fault;
+ false: Logic 0 indicates fault */
+ bool enableCombinationalPath; /*!< true: Combinational Path from fault input is enabled;
+ false: No combination path is available */
+ pwm_fault_recovery_mode_t recoverMode; /*!< Specify when to re-enable the PWM output */
+} pwm_fault_param_t;
+
+/*!
+ * @brief Structure is used to hold parameters to configure the capture capability of a signal pin
+ */
+typedef struct _pwm_input_capture_param
+{
+ bool captureInputSel; /*!< true: Use the edge counter signal as source
+ false: Use the raw input signal from the pin as source */
+ uint8_t edgeCompareValue; /*!< Compare value, used only if edge counter is used as source */
+ pwm_input_capture_edge_t edge0; /*!< Specify which edge causes a capture for input circuitry 0 */
+ pwm_input_capture_edge_t edge1; /*!< Specify which edge causes a capture for input circuitry 1 */
+ bool enableOneShotCapture; /*!< true: Use one-shot capture mode;
+ false: Use free-running capture mode */
+ uint8_t fifoWatermark; /*!< Watermark level for capture FIFO. The capture flags in
+ the status register will set if the word count in the FIFO
+ is greater than this watermark level */
+} pwm_input_capture_param_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Ungates the PWM submodule clock and configures the peripheral for basic operation.
+ *
+ * @note This API should be called at the beginning of the application using the PWM driver.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param config Pointer to user's PWM config structure.
+ *
+ * @return kStatus_Success means success; else failed.
+ */
+status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config);
+
+/*!
+ * @brief Gate the PWM submodule clock
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to deinitialize
+ */
+void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule);
+
+/*!
+ * @brief Fill in the PWM config struct with the default settings
+ *
+ * The default values are:
+ * @code
+ * config->enableDebugMode = false;
+ * config->enableWait = false;
+ * config->reloadSelect = kPWM_LocalReload;
+ * config->clockSource = kPWM_BusClock;
+ * config->prescale = kPWM_Prescale_Divide_1;
+ * config->initializationControl = kPWM_Initialize_LocalSync;
+ * config->forceTrigger = kPWM_Force_Local;
+ * config->reloadFrequency = kPWM_LoadEveryOportunity;
+ * config->reloadLogic = kPWM_ReloadImmediate;
+ * config->pairOperation = kPWM_Independent;
+ * @endcode
+ * @param config Pointer to user's PWM config structure.
+ */
+void PWM_GetDefaultConfig(pwm_config_t *config);
+
+/*! @}*/
+
+/*!
+ * @name Module PWM output
+ * @{
+ */
+/*!
+ * @brief Sets up the PWM signals for a PWM submodule.
+ *
+ * The function initializes the submodule according to the parameters passed in by the user. The function
+ * also sets up the value compare registers to match the PWM signal requirements.
+ * If the dead time insertion logic is enabled, the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param chnlParams Array of PWM channel parameters to configure the channel(s), PWMX submodule is not supported.
+ * @param numOfChnls Number of channels to configure, this should be the size of the array passed in.
+ * Array size should not be more than 2 as each submodule has 2 pins to output PWM
+ * @param mode PWM operation mode, options available in enumeration ::pwm_mode_t
+ * @param pwmFreq_Hz PWM signal frequency in Hz
+ * @param srcClock_Hz PWM main counter clock in Hz.
+ *
+ * @return Returns kStatus_Fail if there was error setting up the signal; kStatus_Success otherwise
+ */
+status_t PWM_SetupPwm(PWM_Type *base,
+ pwm_submodule_t subModule,
+ const pwm_signal_param_t *chnlParams,
+ uint8_t numOfChnls,
+ pwm_mode_t mode,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Set PWM phase shift for PWM channel running on channel PWM_A, PWM_B which with 50% duty cycle..
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel PWM channel to configure
+ * @param pwmFreq_Hz PWM signal frequency in Hz
+ * @param srcClock_Hz PWM main counter clock in Hz.
+ * @param shiftvalue Phase shift value
+ * @param doSync true: Set LDOK bit for the submodule list;
+ * false: LDOK bit don't set, need to call PWM_SetPwmLdok to sync update.
+ *
+ * @return Returns kStatus_Fail if there was error setting up the signal; kStatus_Success otherwise
+ */
+status_t PWM_SetupPwmPhaseShift(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz,
+ uint8_t shiftvalue,
+ bool doSync);
+
+/*!
+ * @brief Updates the PWM signal's dutycycle.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmSignal Signal (PWM A or PWM B) to update
+ * @param currPwmMode The current PWM mode set during PWM setup
+ * @param dutyCyclePercent New PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycle(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmSignal,
+ pwm_mode_t currPwmMode,
+ uint8_t dutyCyclePercent);
+
+/*!
+ * @brief Updates the PWM signal's dutycycle with 16-bit accuracy.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmSignal Signal (PWM A or PWM B) to update
+ * @param currPwmMode The current PWM mode set during PWM setup
+ * @param dutyCycle New PWM pulse width, value should be between 0 to 65535
+ * 0=inactive signal(0% duty cycle)...
+ * 65535=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycleHighAccuracy(
+ PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle);
+
+/*! @}*/
+
+/*!
+ * @brief Sets up the PWM input capture
+ *
+ * Each PWM submodule has 3 pins that can be configured for use as input capture pins. This function
+ * sets up the capture parameters for each pin and enables the pin for input capture operation.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel Channel in the submodule to setup
+ * @param inputCaptureParams Parameters passed in to set up the input pin
+ */
+void PWM_SetupInputCapture(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ const pwm_input_capture_param_t *inputCaptureParams);
+
+/*!
+ * @brief Sets up the PWM fault input filter.
+ *
+ * @param base PWM peripheral base address
+ * @param faultInputFilterParams Parameters passed in to set up the fault input filter.
+ */
+void PWM_SetupFaultInputFilter(PWM_Type *base, const pwm_fault_input_filter_param_t *faultInputFilterParams);
+
+/*!
+ * @brief Sets up the PWM fault protection.
+ *
+ * PWM has 4 fault inputs.
+ *
+ * @param base PWM peripheral base address
+ * @param faultNum PWM fault to configure.
+ * @param faultParams Pointer to the PWM fault config structure
+ */
+void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams);
+
+/*!
+ * @brief Fill in the PWM fault config struct with the default settings
+ *
+ * The default values are:
+ * @code
+ * config->faultClearingMode = kPWM_Automatic;
+ * config->faultLevel = false;
+ * config->enableCombinationalPath = true;
+ * config->recoverMode = kPWM_NoRecovery;
+ * @endcode
+ * @param config Pointer to user's PWM fault config structure.
+ */
+void PWM_FaultDefaultConfig(pwm_fault_param_t *config);
+
+/*!
+ * @brief Selects the signal to output on a PWM pin when a FORCE_OUT signal is asserted.
+ *
+ * The user specifies which channel to configure by supplying the submodule number and whether
+ * to modify PWM A or PWM B within that submodule.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel Channel to configure
+ * @param mode Signal to output when a FORCE_OUT is triggered
+ */
+void PWM_SetupForceSignal(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ pwm_force_signal_t mode);
+
+/*!
+ * @name Interrupts Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected PWM interrupts
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask);
+
+/*!
+ * @brief Disables the selected PWM interrupts
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask);
+
+/*!
+ * @brief Gets the enabled PWM interrupts
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule);
+
+/*! @}*/
+
+/*!
+ * @name DMA Interface
+ * @{
+ */
+
+/*!
+ * @brief Capture DMA Enable Source Select.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwm_watermark_control PWM FIFO watermark and control
+ */
+static inline void PWM_DMAFIFOWatermarkControl(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_watermark_control_t pwm_watermark_control)
+{
+ uint16_t reg = base->SM[subModule].DMAEN;
+ if (pwm_watermark_control == kPWM_FIFOWatermarksOR)
+ {
+ reg &= ~((uint16_t)PWM_DMAEN_FAND_MASK);
+ }
+ else
+ {
+ reg |= ((uint16_t)PWM_DMAEN_FAND_MASK);
+ }
+ base->SM[subModule].DMAEN = reg;
+}
+
+/*!
+ * @brief Capture DMA Enable Source Select.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwm_dma_source_select PWM capture DMA enable source select
+ */
+static inline void PWM_DMACaptureSourceSelect(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_dma_source_select_t pwm_dma_source_select)
+{
+ uint16_t reg = base->SM[subModule].DMAEN;
+
+ reg &= ~((uint16_t)PWM_DMAEN_CAPTDE_MASK);
+ reg |= (((uint16_t)pwm_dma_source_select << (uint16_t)PWM_DMAEN_CAPTDE_SHIFT) & (uint16_t)PWM_DMAEN_CAPTDE_MASK);
+
+ base->SM[subModule].DMAEN = reg;
+}
+
+/*!
+ * @brief Enables or disables the selected PWM DMA Capture read request.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param mask The DMA to enable or disable. This is a logical OR of members of the
+ * enumeration ::pwm_dma_enable_t
+ * @param activate true: Enable DMA read request; false: Disable DMA read request
+ */
+static inline void PWM_EnableDMACapture(PWM_Type *base, pwm_submodule_t subModule, uint16_t mask, bool activate)
+{
+ uint16_t reg = base->SM[subModule].DMAEN;
+ if (activate)
+ {
+ reg |= (uint16_t)(mask);
+ }
+ else
+ {
+ reg &= ~((uint16_t)(mask));
+ }
+ base->SM[subModule].DMAEN = reg;
+}
+
+/*!
+ * @brief Enables or disables the PWM DMA write request.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param activate true: Enable DMA write request; false: Disable DMA write request
+ */
+static inline void PWM_EnableDMAWrite(PWM_Type *base, pwm_submodule_t subModule, bool activate)
+{
+ uint16_t reg = base->SM[subModule].DMAEN;
+ if (activate)
+ {
+ reg |= ((uint16_t)PWM_DMAEN_VALDE_MASK);
+ }
+ else
+ {
+ reg &= ~((uint16_t)PWM_DMAEN_VALDE_MASK);
+ }
+ base->SM[subModule].DMAEN = reg;
+}
+
+/*! @}*/
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Gets the PWM status flags
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule);
+
+/*!
+ * @brief Clears the PWM status flags
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask);
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+
+/*!
+ * @brief Starts the PWM counter for a single or multiple submodules.
+ *
+ * Sets the Run bit which enables the clocks to the PWM submodule. This function can start multiple
+ * submodules at the same time.
+ *
+ * @param base PWM peripheral base address
+ * @param subModulesToStart PWM submodules to start. This is a logical OR of members of the
+ * enumeration ::pwm_module_control_t
+ */
+static inline void PWM_StartTimer(PWM_Type *base, uint8_t subModulesToStart)
+{
+ base->MCTRL |= PWM_MCTRL_RUN(subModulesToStart);
+}
+
+/*!
+ * @brief Stops the PWM counter for a single or multiple submodules.
+ *
+ * Clears the Run bit which resets the submodule's counter. This function can stop multiple
+ * submodules at the same time.
+ *
+ * @param base PWM peripheral base address
+ * @param subModulesToStop PWM submodules to stop. This is a logical OR of members of the
+ * enumeration ::pwm_module_control_t
+ */
+static inline void PWM_StopTimer(PWM_Type *base, uint8_t subModulesToStop)
+{
+ base->MCTRL &= ~(PWM_MCTRL_RUN(subModulesToStop));
+}
+
+/*! @}*/
+
+/*!
+ * @brief Set the PWM VALx registers.
+ *
+ * This function allows the user to write value into VAL registers directly. And it will destroying the PWM clock period
+ * set by the PWM_SetupPwm()/PWM_SetupPwmPhaseShift() functions.
+ * Due to VALx registers are bufferd, the new value will not active uless call PWM_SetPwmLdok() and the reload point is
+ * reached.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param valueRegister VALx register that will be writen new value
+ * @param value Value that will been write into VALx register
+ */
+static inline void PWM_SetVALxValue(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_value_register_t valueRegister,
+ uint16_t value)
+{
+ switch (valueRegister)
+ {
+ case kPWM_ValueRegister_0:
+ base->SM[subModule].VAL0 = value;
+ break;
+ case kPWM_ValueRegister_1:
+ base->SM[subModule].VAL1 = value;
+ break;
+ case kPWM_ValueRegister_2:
+ base->SM[subModule].VAL2 = value;
+ break;
+ case kPWM_ValueRegister_3:
+ base->SM[subModule].VAL3 = value;
+ break;
+ case kPWM_ValueRegister_4:
+ base->SM[subModule].VAL4 = value;
+ break;
+ case kPWM_ValueRegister_5:
+ base->SM[subModule].VAL5 = value;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Get the PWM VALx registers.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param valueRegister VALx register that will be read value
+ * @return The VALx register value
+ */
+static inline uint16_t PWM_GetVALxValue(PWM_Type *base, pwm_submodule_t subModule, pwm_value_register_t valueRegister)
+{
+ uint16_t temp = 0U;
+
+ switch (valueRegister)
+ {
+ case kPWM_ValueRegister_0:
+ temp = base->SM[subModule].VAL0;
+ break;
+ case kPWM_ValueRegister_1:
+ temp = base->SM[subModule].VAL1;
+ break;
+ case kPWM_ValueRegister_2:
+ temp = base->SM[subModule].VAL2;
+ break;
+ case kPWM_ValueRegister_3:
+ temp = base->SM[subModule].VAL3;
+ break;
+ case kPWM_ValueRegister_4:
+ temp = base->SM[subModule].VAL4;
+ break;
+ case kPWM_ValueRegister_5:
+ temp = base->SM[subModule].VAL5;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ return temp;
+}
+
+/*!
+ * @brief Enables or disables the PWM output trigger.
+ *
+ * This function allows the user to enable or disable the PWM trigger. The PWM has 2 triggers. Trigger 0
+ * is activated when the counter matches VAL 0, VAL 2, or VAL 4 register. Trigger 1 is activated
+ * when the counter matches VAL 1, VAL 3, or VAL 5 register.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param valueRegister Value register that will activate the trigger
+ * @param activate true: Enable the trigger; false: Disable the trigger
+ */
+static inline void PWM_OutputTriggerEnable(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_value_register_t valueRegister,
+ bool activate)
+{
+ if (activate)
+ {
+ base->SM[subModule].TCTRL |= ((uint16_t)1U << (uint16_t)valueRegister);
+ }
+ else
+ {
+ base->SM[subModule].TCTRL &= ~((uint16_t)1U << (uint16_t)valueRegister);
+ }
+}
+
+/*!
+ * @brief Enables the PWM output trigger.
+ *
+ * This function allows the user to enable one or more (VAL0-5) PWM trigger.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param valueRegisterMask Value register mask that will activate one or more (VAL0-5) trigger
+ * enumeration ::_pwm_value_register_mask
+ */
+static inline void PWM_ActivateOutputTrigger(PWM_Type *base, pwm_submodule_t subModule, uint16_t valueRegisterMask)
+{
+ base->SM[subModule].TCTRL |= (PWM_TCTRL_OUT_TRIG_EN_MASK & (valueRegisterMask));
+}
+
+/*!
+ * @brief Disables the PWM output trigger.
+ *
+ * This function allows the user to disables one or more (VAL0-5) PWM trigger.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param valueRegisterMask Value register mask that will Deactivate one or more (VAL0-5) trigger
+ * enumeration ::_pwm_value_register_mask
+ */
+static inline void PWM_DeactivateOutputTrigger(PWM_Type *base, pwm_submodule_t subModule, uint16_t valueRegisterMask)
+{
+ base->SM[subModule].TCTRL &= ~(PWM_TCTRL_OUT_TRIG_EN_MASK & (valueRegisterMask));
+}
+
+/*!
+ * @brief Sets the software control output for a pin to high or low.
+ *
+ * The user specifies which channel to modify by supplying the submodule number and whether
+ * to modify PWM A or PWM B within that submodule.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel Channel to configure
+ * @param value true: Supply a logic 1, false: Supply a logic 0.
+ */
+static inline void PWM_SetupSwCtrlOut(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, bool value)
+{
+ if (value)
+ {
+ base->SWCOUT |=
+ ((uint16_t)1U << (((uint16_t)subModule * (uint16_t)PWM_SUBMODULE_SWCONTROL_WIDTH) + (uint16_t)pwmChannel));
+ }
+ else
+ {
+ base->SWCOUT &=
+ ~((uint16_t)1U << (((uint16_t)subModule * (uint16_t)PWM_SUBMODULE_SWCONTROL_WIDTH) + (uint16_t)pwmChannel));
+ }
+}
+
+/*!
+ * @brief Sets or clears the PWM LDOK bit on a single or multiple submodules
+ *
+ * Set LDOK bit to load buffered values into CTRL[PRSC] and the INIT, FRACVAL and VAL registers. The
+ * values are loaded immediately if kPWM_ReloadImmediate option was choosen during config. Else the
+ * values are loaded at the next PWM reload point.
+ * This function can issue the load command to multiple submodules at the same time.
+ *
+ * @param base PWM peripheral base address
+ * @param subModulesToUpdate PWM submodules to update with buffered values. This is a logical OR of
+ * members of the enumeration ::pwm_module_control_t
+ * @param value true: Set LDOK bit for the submodule list; false: Clear LDOK bit
+ */
+static inline void PWM_SetPwmLdok(PWM_Type *base, uint8_t subModulesToUpdate, bool value)
+{
+ if (value)
+ {
+ base->MCTRL |= PWM_MCTRL_LDOK(subModulesToUpdate);
+ }
+ else
+ {
+ base->MCTRL |= PWM_MCTRL_CLDOK(subModulesToUpdate);
+ }
+}
+
+/*!
+ * @brief Set PWM output fault status
+ *
+ * These bits determine the fault state for the PWM_A output in fault conditions
+ * and STOP mode. It may also define the output state in WAIT and DEBUG modes
+ * depending on the settings of CTRL2[WAITEN] and CTRL2[DBGEN].
+ * This function can update PWM output fault status.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel Channel to configure
+ * @param faultState PWM output fault status
+ */
+static inline void PWM_SetPwmFaultState(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ pwm_fault_state_t faultState)
+{
+ uint16_t reg = base->SM[subModule].OCTRL;
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ reg &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ reg |= (((uint16_t)faultState << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) & (uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ break;
+ case kPWM_PwmB:
+ reg &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ reg |= (((uint16_t)faultState << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) & (uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ break;
+ case kPWM_PwmX:
+ reg &= ~((uint16_t)PWM_OCTRL_PWMXFS_MASK);
+ reg |= (((uint16_t)faultState << (uint16_t)PWM_OCTRL_PWMXFS_SHIFT) & (uint16_t)PWM_OCTRL_PWMXFS_MASK);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].OCTRL = reg;
+}
+
+/*!
+ * @brief Set PWM fault disable mapping
+ *
+ * Each of the four bits of this read/write field is one-to-one associated
+ * with the four FAULTx inputs of fault channel 0/1. The PWM output will be turned
+ * off if there is a logic 1 on an FAULTx input and a 1 in the corresponding
+ * bit of this field. A reset sets all bits in this field.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel PWM channel to configure
+ * @param pwm_fault_channels PWM fault channel to configure
+ * @param value Fault disable mapping mask value
+ * enumeration ::pwm_fault_disable_t
+ */
+static inline void PWM_SetupFaultDisableMap(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ pwm_fault_channels_t pwm_fault_channels,
+ uint16_t value)
+{
+ uint16_t reg = base->SM[subModule].DISMAP[pwm_fault_channels];
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0A_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0A_SHIFT) & (uint16_t)PWM_DISMAP_DIS0A_MASK);
+ break;
+ case kPWM_PwmB:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0B_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0B_SHIFT) & (uint16_t)PWM_DISMAP_DIS0B_MASK);
+ break;
+ case kPWM_PwmX:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0X_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0X_SHIFT) & (uint16_t)PWM_DISMAP_DIS0X_MASK);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].DISMAP[pwm_fault_channels] = reg;
+}
+
+/*!
+ * @brief Set PWM output enable
+ *
+ * This feature allows the user to enable the PWM Output.
+ *
+ * @param base PWM peripheral base address
+ * @param pwmChannel PWM channel to configure
+ * @param subModule PWM submodule to configure
+ */
+static inline void PWM_OutputEnable(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule)
+{
+ /* Set PWM output */
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ base->OUTEN |= ((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmB:
+ base->OUTEN |= ((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmX:
+ base->OUTEN |= ((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Set PWM output disable
+ *
+ *This feature allows the user to disable the PWM output.
+ *
+ * @param base PWM peripheral base address
+ * @param pwmChannel PWM channel to configure
+ * @param subModule PWM submodule to configure
+ */
+static inline void PWM_OutputDisable(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule)
+{
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ base->OUTEN &= ~((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmB:
+ base->OUTEN &= ~((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmX:
+ base->OUTEN &= ~((uint16_t)1U << ((uint16_t)PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Get the dutycycle value.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel PWM channel to configure
+ *
+ * @return Current channel dutycycle value.
+ */
+uint8_t PWM_GetPwmChannelState(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel);
+
+/*!
+ * @brief Set PWM output in idle status (high or low).
+ *
+ * @note This API should call after PWM_SetupPwm() APIs, and PWMX submodule is not supported.
+ *
+ * @param base PWM peripheral base address
+ * @param pwmChannel PWM channel to configure
+ * @param subModule PWM submodule to configure
+ * @param idleStatus True: PWM output is high in idle status; false: PWM output is low in idle status.
+ *
+ * @return kStatus_Fail if there was error setting up the signal; kStatus_Success if set output idle success
+ */
+status_t PWM_SetOutputToIdle(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule, bool idleStatus);
+
+/*!
+ * @brief Set the pwm submodule prescaler.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param prescaler Set prescaler value
+ */
+void PWM_SetClockMode(PWM_Type *base, pwm_submodule_t subModule, pwm_clock_prescale_t prescaler);
+
+/*!
+ * @brief This function enables-disables the forcing of the output of a given eFlexPwm channel to logic 0.
+ *
+ * @param base PWM peripheral base address
+ * @param pwmChannel PWM channel to configure
+ * @param subModule PWM submodule to configure
+ * @param forcetozero True: Enable the pwm force output to zero; False: Disable the pwm output resumes normal
+ * function.
+ */
+void PWM_SetPwmForceOutputToZero(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ bool forcetozero);
+
+/*!
+ * @brief This function set the output state of the PWM pin as requested for the current cycle.
+ *
+ * @param base PWM peripheral base address
+ * @param subModule PWM submodule to configure
+ * @param pwmChannel PWM channel to configure
+ * @param outputstate Set pwm output state, see @ref pwm_output_state_t.
+ */
+void PWM_SetChannelOutput(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ pwm_output_state_t outputstate);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PWM_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.c b/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.c
new file mode 100644
index 0000000000..ccd1332349
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.c
@@ -0,0 +1,2188 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pxp.h"
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#include "fsl_memory.h"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pxp"
+#endif
+
+/* The CSC2 coefficient is ###.####_#### */
+#define PXP_CSC2_COEF_INT_WIDTH 2
+#define PXP_CSC2_COEF_FRAC_WIDTH 8
+
+/* Compatibility map macro. */
+#if defined(PXP_PS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_PS_CLRKEYLOW_PIXEL_MASK))
+#define PS_CLRKEYLOW PS_CLRKEYLOW_0
+#define PS_CLRKEYHIGH PS_CLRKEYHIGH_0
+#endif
+#if defined(PXP_AS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_AS_CLRKEYLOW_PIXEL_MASK))
+#define AS_CLRKEYLOW AS_CLRKEYLOW_0
+#define AS_CLRKEYHIGH AS_CLRKEYHIGH_0
+#endif
+
+#define PXP_MAX_HEIGHT ((PXP_OUT_LRC_Y_MASK >> PXP_OUT_LRC_Y_SHIFT) + 1U)
+
+/* Compatibility macro remap. */
+#if (!defined(PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK) && defined(PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK))
+#define PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK
+#endif
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#define PXP_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
+#else
+#define PXP_ADDR_CPU_2_IP(addr) (addr)
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)
+#define S1_COLOR_MODE PXP_PORTER_DUFF_CTRL_S1_COLOR_MODE
+#define S1_ALPHA_MODE PXP_PORTER_DUFF_CTRL_S1_ALPHA_MODE
+#define S1_GLOBAL_ALPHA_MODE PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE
+#define S1_S0_FACTOR_MODE PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE
+#define S0_COLOR_MODE PXP_PORTER_DUFF_CTRL_S0_COLOR_MODE
+#define S0_ALPHA_MODE PXP_PORTER_DUFF_CTRL_S0_ALPHA_MODE
+#define S0_GLOBAL_ALPHA_MODE PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE
+#define S0_S1_FACTOR_MODE PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE
+#define PORTER_DUFF_ENABLE_MASK PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK
+#endif /* FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+#define S1_COLOR_MODE PXP_ALPHA_A_CTRL_S1_COLOR_MODE
+#define S1_ALPHA_MODE PXP_ALPHA_A_CTRL_S1_ALPHA_MODE
+#define S1_GLOBAL_ALPHA_MODE PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE
+#define S1_S0_FACTOR_MODE PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE
+#define S0_COLOR_MODE PXP_ALPHA_A_CTRL_S0_COLOR_MODE
+#define S0_ALPHA_MODE PXP_ALPHA_A_CTRL_S0_ALPHA_MODE
+#define S0_GLOBAL_ALPHA_MODE PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE
+#define S0_S1_FACTOR_MODE PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE
+#define PORTER_DUFF_ENABLE_MASK PXP_ALPHA_A_CTRL_PORTER_DUFF_ENABLE_MASK
+#endif /* FSL_FEATURE_PXP_V3 */
+
+typedef union _u32_f32
+{
+ float f32;
+ uint32_t u32;
+} u32_f32_t;
+
+typedef union _pxp_pvoid_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pxp_pvoid_u32_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base PXP peripheral base address
+ *
+ * @return The PXP module instance
+ */
+static uint32_t PXP_GetInstance(PXP_Type *base);
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+/*!
+ * @brief Convert IEEE 754 float value to the value could be written to registers.
+ *
+ * This function converts the float value to integer value to set the scaler
+ * and CSC parameters.
+ *
+ * This function is an alternative implemention of the following code with no
+ * MISRA 2004 rule 10.4 error:
+ *
+ * @code
+ return (uint32_t)(floatValue * (float)(1 << fracBits));
+ @endcode
+ *
+ * @param floatValue The float value to convert.
+ * @param intBits Bits number of integer part in result.
+ * @param fracBits Bits number of fractional part in result.
+ * @return The value to set to register.
+ */
+static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits);
+#endif
+
+/*!
+ * @brief Convert the desired scale fact to DEC and PS_SCALE.
+ *
+ * @param inputDimension Input dimension.
+ * @param outputDimension Output dimension.
+ * @param dec The decimation filter contr0l value.
+ * @param scale The scale value set to register PS_SCALE.
+ */
+static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale);
+
+/*!
+ * @brief Copy rectangle.
+ *
+ * @param base PXP peripheral base address.
+ * @param srcAddr Start address of the soruce rectangle.
+ * @param srcPitchBytes Pitch of source buffer.
+ * @param destAddr Start address of the destination rectangle.
+ * @param destPitchBytes Pitch of destination buffer.
+ * @param width How many pixels one line to copy.
+ * @param height How many lines to copy.
+ * @param pixelFormat Pixel format.
+ */
+static void PXP_StartRectCopy(PXP_Type *base,
+ uint32_t srcAddr,
+ uint16_t srcPitchBytes,
+ uint32_t destAddr,
+ uint16_t destPitchBytes,
+ uint16_t width,
+ uint16_t height,
+ pxp_as_pixel_format_t pixelFormat);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PXP bases for each instance. */
+static PXP_Type *const s_pxpBases[] = PXP_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PXP clocks for each PXP submodule. */
+static const clock_ip_name_t s_pxpClocks[] = PXP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t PXP_GetInstance(PXP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pxpBases); instance++)
+ {
+ if (s_pxpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pxpBases));
+
+ return instance;
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits)
+{
+ /* One bit reserved for sign bit. */
+ assert(intBits + fracBits < 32U);
+
+ u32_f32_t u32_f32;
+ uint32_t ret;
+
+ u32_f32.f32 = floatValue;
+ uint32_t floatBits = u32_f32.u32;
+ int32_t expValue = (int32_t)((uint16_t)((floatBits & 0x7F800000UL) >> 23U)) - 127;
+
+ ret = (floatBits & 0x007FFFFFU) | 0x00800000U;
+ expValue += (int32_t)fracBits;
+
+ if (expValue < 0)
+ {
+ return 0U;
+ }
+ else if (expValue > 23)
+ {
+ /* should not exceed 31-bit when left shift. */
+ assert((expValue - 23) <= 7);
+ ret <<= ((uint16_t)expValue - 23U);
+ }
+ else
+ {
+ ret >>= (23U - (uint16_t)expValue);
+ }
+
+ /* Set the sign bit. */
+ if ((floatBits & 0x80000000UL) != 0U)
+ {
+ ret = ((~ret) + 1UL) & ~(((uint32_t)-1) << ((uint32_t)intBits + (uint32_t)fracBits + 1UL));
+ }
+
+ return ret;
+}
+#endif
+
+static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale)
+{
+ uint32_t scaleFact = ((uint32_t)inputDimension << 12U) / outputDimension;
+
+ if (scaleFact >= (16UL << 12U))
+ {
+ /* Desired fact is two large, use the largest support value. */
+ *dec = 3U;
+ *scale = 0x2000U;
+ }
+ else
+ {
+ if (scaleFact > (8UL << 12U))
+ {
+ *dec = 3U;
+ }
+ else if (scaleFact > (4UL << 12U))
+ {
+ *dec = 2U;
+ }
+ else if (scaleFact > (2UL << 12U))
+ {
+ *dec = 1U;
+ }
+ else
+ {
+ *dec = 0U;
+ }
+
+ *scale = scaleFact >> (*dec);
+
+ if (0U == *scale)
+ {
+ *scale = 1U;
+ }
+ }
+}
+
+/*!
+ * brief Reset the PXP and the control register to initialized state.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_ResetControl(PXP_Type *base)
+{
+ uint32_t ctrl = 0U;
+
+ PXP_Reset(base);
+
+/* Enable the process engine in primary processing flow. */
+#if defined(PXP_CTRL_ENABLE_ROTATE0_MASK)
+ ctrl |= PXP_CTRL_ENABLE_ROTATE0_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_ROTATE1_MASK)
+ ctrl |= PXP_CTRL_ENABLE_ROTATE1_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_CSC2_MASK)
+ ctrl |= PXP_CTRL_ENABLE_CSC2_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_LUT_MASK)
+ ctrl |= PXP_CTRL_ENABLE_LUT_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_PS_AS_OUT_MASK)
+ ctrl |= PXP_CTRL_ENABLE_PS_AS_OUT_MASK;
+#endif
+
+ base->CTRL = ctrl;
+}
+
+/*!
+ * brief Initialize the PXP.
+ *
+ * This function enables the PXP peripheral clock, and resets the PXP registers
+ * to default status.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Init(PXP_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = PXP_GetInstance(base);
+ CLOCK_EnableClock(s_pxpClocks[instance]);
+#endif
+
+ PXP_ResetControl(base);
+
+ /* Disable the alpha surface. */
+ PXP_SetAlphaSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
+}
+
+/*!
+ * brief De-initialize the PXP.
+ *
+ * This function disables the PXP peripheral clock.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Deinit(PXP_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = PXP_GetInstance(base);
+ CLOCK_DisableClock(s_pxpClocks[instance]);
+#endif
+}
+
+/*!
+ * brief Reset the PXP.
+ *
+ * This function resets the PXP peripheral registers to default status.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Reset(PXP_Type *base)
+{
+ base->CTRL_SET = PXP_CTRL_SFTRST_MASK;
+ base->CTRL_CLR = (PXP_CTRL_SFTRST_MASK | PXP_CTRL_CLKGATE_MASK);
+}
+
+/*!
+ * brief Set the alpha surface input buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetAlphaSurfaceBufferConfig(PXP_Type *base, const pxp_as_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->AS_CTRL = (base->AS_CTRL & ~PXP_AS_CTRL_FORMAT_MASK) | PXP_AS_CTRL_FORMAT(config->pixelFormat);
+
+ base->AS_BUF = PXP_ADDR_CPU_2_IP(config->bufferAddr);
+ base->AS_PITCH = config->pitchBytes;
+}
+
+/*!
+ * brief Set the alpha surface blending configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void PXP_SetAlphaSurfaceBlendConfig(PXP_Type *base, const pxp_as_blend_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ reg = base->AS_CTRL;
+ reg &=
+ ~(PXP_AS_CTRL_ALPHA0_INVERT_MASK | PXP_AS_CTRL_ROP_MASK | PXP_AS_CTRL_ALPHA_MASK | PXP_AS_CTRL_ALPHA_CTRL_MASK);
+ reg |= (PXP_AS_CTRL_ROP(config->ropMode) | PXP_AS_CTRL_ALPHA(config->alpha) |
+ PXP_AS_CTRL_ALPHA_CTRL(config->alphaMode));
+
+ if (config->invertAlpha)
+ {
+ reg |= PXP_AS_CTRL_ALPHA0_INVERT_MASK;
+ }
+
+ base->AS_CTRL = reg;
+}
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * brief Set the alpha surface blending configuration for the secondary engine.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void PXP_SetAlphaSurfaceBlendSecondaryConfig(PXP_Type *base, const pxp_as_blend_secondary_config_t *config)
+{
+ assert(NULL != config);
+
+ base->ALPHA_B_CTRL_1 =
+ (base->ALPHA_B_CTRL_1 & ~(PXP_ALPHA_B_CTRL_1_ROP_MASK | PXP_ALPHA_B_CTRL_1_ROP_ENABLE_MASK)) |
+ PXP_ALPHA_B_CTRL_1_ROP((uint32_t)config->ropMode) | PXP_ALPHA_B_CTRL_1_ROP_ENABLE((uint32_t)config->ropEnable);
+
+ if (config->invertAlpha)
+ {
+ base->AS_CTRL |= PXP_AS_CTRL_ALPHA1_INVERT_MASK;
+ }
+ else
+ {
+ base->AS_CTRL &= ~PXP_AS_CTRL_ALPHA1_INVERT_MASK;
+ }
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * brief Set the alpha surface position in output buffer.
+ *
+ * param base PXP peripheral base address.
+ * param upperLeftX X of the upper left corner.
+ * param upperLeftY Y of the upper left corner.
+ * param lowerRightX X of the lower right corner.
+ * param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetAlphaSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
+{
+ base->OUT_AS_ULC = PXP_OUT_AS_ULC_Y(upperLeftY) | PXP_OUT_AS_ULC_X(upperLeftX);
+ base->OUT_AS_LRC = PXP_OUT_AS_LRC_Y(lowerRightY) | PXP_OUT_AS_LRC_X(lowerRightX);
+}
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * brief Set the alpha surface overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
+ * pixel value for that location. If no PS image is present or if the PS image also
+ * matches its colorkey range, the PS background color is used.
+ *
+ * param base PXP peripheral base address.
+ * param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ *
+ * note Colorkey operations are higher priority than alpha or ROP operations
+ */
+void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ switch (num)
+ {
+ case 0:
+ base->AS_CLRKEYLOW = colorKeyLow;
+ base->AS_CLRKEYHIGH = colorKeyHigh;
+ break;
+
+ case 1:
+ base->AS_CLRKEYLOW_1 = colorKeyLow;
+ base->AS_CLRKEYHIGH_1 = colorKeyHigh;
+ break;
+
+ default:
+ /* Only 2 alpha process engine instances are supported. */
+ assert(false);
+ break;
+ }
+}
+#else
+/*!
+ * brief Set the alpha surface overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
+ * pixel value for that location. If no PS image is present or if the PS image also
+ * matches its colorkey range, the PS background color is used.
+ *
+ * param base PXP peripheral base address.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ *
+ * note Colorkey operations are higher priority than alpha or ROP operations
+ */
+void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ base->AS_CLRKEYLOW = colorKeyLow;
+ base->AS_CLRKEYHIGH = colorKeyHigh;
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * brief Set the process surface input buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetProcessSurfaceBufferConfig(PXP_Type *base, const pxp_ps_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->PS_CTRL = ((base->PS_CTRL & ~(PXP_PS_CTRL_FORMAT_MASK | PXP_PS_CTRL_WB_SWAP_MASK)) |
+ PXP_PS_CTRL_FORMAT(config->pixelFormat) | PXP_PS_CTRL_WB_SWAP(config->swapByte));
+
+ base->PS_BUF = PXP_ADDR_CPU_2_IP(config->bufferAddr);
+ base->PS_UBUF = PXP_ADDR_CPU_2_IP(config->bufferAddrU);
+ base->PS_VBUF = PXP_ADDR_CPU_2_IP(config->bufferAddrV);
+ base->PS_PITCH = config->pitchBytes;
+}
+
+/*!
+ * brief Set the process surface scaler configuration.
+ *
+ * The valid down scale fact is 1/(2^12) ~ 16.
+ *
+ * param base PXP peripheral base address.
+ * param inputWidth Input image width.
+ * param inputHeight Input image height.
+ * param outputWidth Output image width.
+ * param outputHeight Output image height.
+ */
+void PXP_SetProcessSurfaceScaler(
+ PXP_Type *base, uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight)
+{
+ uint8_t decX, decY;
+ uint32_t scaleX, scaleY;
+
+ PXP_GetScalerParam(inputWidth, outputWidth, &decX, &scaleX);
+ PXP_GetScalerParam(inputHeight, outputHeight, &decY, &scaleY);
+
+ base->PS_CTRL = (base->PS_CTRL & ~(PXP_PS_CTRL_DECX_MASK | PXP_PS_CTRL_DECY_MASK)) | PXP_PS_CTRL_DECX(decX) |
+ PXP_PS_CTRL_DECY(decY);
+
+ base->PS_SCALE = PXP_PS_SCALE_XSCALE(scaleX) | PXP_PS_SCALE_YSCALE(scaleY);
+}
+
+/*!
+ * brief Set the process surface position in output buffer.
+ *
+ * param base PXP peripheral base address.
+ * param upperLeftX X of the upper left corner.
+ * param upperLeftY Y of the upper left corner.
+ * param lowerRightX X of the lower right corner.
+ * param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetProcessSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
+{
+ base->OUT_PS_ULC = PXP_OUT_PS_ULC_Y(upperLeftY) | PXP_OUT_PS_ULC_X(upperLeftX);
+ base->OUT_PS_LRC = PXP_OUT_PS_LRC_Y(lowerRightY) | PXP_OUT_PS_LRC_X(lowerRightX);
+}
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * brief Set the process surface color key.
+ *
+ * If the PS image matches colorkey range, the PS background color is output. Set
+ * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
+ *
+ * param base PXP peripheral base address.
+ * param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ */
+void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ switch (num)
+ {
+ case 0:
+ base->PS_CLRKEYLOW = colorKeyLow;
+ base->PS_CLRKEYHIGH = colorKeyHigh;
+ break;
+
+ case 1:
+ base->PS_CLRKEYLOW_1 = colorKeyLow;
+ base->PS_CLRKEYHIGH_1 = colorKeyHigh;
+ break;
+
+ default:
+ /* Only 2 alpha process engine instances are supported. */
+ assert(false);
+ break;
+ }
+}
+#else
+/*!
+ * brief Set the process surface color key.
+ *
+ * If the PS image matches colorkey range, the PS background color is output. Set
+ * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
+ *
+ * param base PXP peripheral base address.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ */
+void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ base->PS_CLRKEYLOW = colorKeyLow;
+ base->PS_CLRKEYHIGH = colorKeyHigh;
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * brief Set the PXP outpt buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetOutputBufferConfig(PXP_Type *base, const pxp_output_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->OUT_CTRL = (base->OUT_CTRL & ~(PXP_OUT_CTRL_FORMAT_MASK | PXP_OUT_CTRL_INTERLACED_OUTPUT_MASK)) |
+ PXP_OUT_CTRL_FORMAT(config->pixelFormat) | PXP_OUT_CTRL_INTERLACED_OUTPUT(config->interlacedMode);
+
+ base->OUT_BUF = PXP_ADDR_CPU_2_IP(config->buffer0Addr);
+ base->OUT_BUF2 = PXP_ADDR_CPU_2_IP(config->buffer1Addr);
+
+ base->OUT_PITCH = config->pitchBytes;
+ base->OUT_LRC = PXP_OUT_LRC_Y((uint32_t)config->height - 1U) | PXP_OUT_LRC_X((uint32_t)config->width - 1U);
+
+/*
+ * The dither store size must be set to the same with the output buffer size,
+ * otherwise the dither engine could not work.
+ */
+#if defined(PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH_MASK)
+ base->DITHER_STORE_SIZE_CH0 = PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->width - 1U) |
+ PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->height - 1U);
+#endif
+}
+
+/*!
+ * brief Build a solid rectangle of given pixel value.
+ *
+ * param base PXP peripheral base address.
+ * param outFormat output pixel format.
+ * param value The value of the pixel to be filled in the rectangle in ARGB8888 format.
+ * param width width of the rectangle.
+ * param height height of the rectangle.
+ * param pitch output pitch in byte.
+ * param outAddr address of the memory to store the rectangle.
+ */
+void PXP_BuildRect(PXP_Type *base,
+ pxp_output_pixel_format_t outFormat,
+ uint32_t value,
+ uint16_t width,
+ uint16_t height,
+ uint16_t pitch,
+ uint32_t outAddr)
+{
+ /* Only support RGB format output. */
+ assert((uint8_t)outFormat <= (uint8_t)kPXP_OutputPixelFormatRGB565);
+
+ /* PS configuration */
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ PXP_SetProcessSurfaceBackGroundColor(base, 0U, value);
+#else
+ PXP_SetProcessSurfaceBackGroundColor(base, value);
+#endif
+ PXP_SetProcessSurfacePosition(base, 0xFFFF, 0xFFFF, 0, 0);
+
+ if ((outFormat == kPXP_OutputPixelFormatARGB8888) || (outFormat == kPXP_OutputPixelFormatARGB1555) ||
+ (outFormat == kPXP_OutputPixelFormatARGB4444))
+ {
+ uint8_t alpha = (uint8_t)(value >> 24U);
+ pxp_as_buffer_config_t asBufferConfig = {
+ .pixelFormat = kPXP_AsPixelFormatARGB8888,
+ .bufferAddr = outAddr,
+ .pitchBytes = pitch,
+ };
+ PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
+
+ pxp_as_blend_config_t asBlendConfig = {
+ .alpha = alpha, .invertAlpha = false, .alphaMode = kPXP_AlphaOverride, .ropMode = kPXP_RopMergeAs};
+ PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ PXP_SetAlphaSurfaceOverlayColorKey(base, 0U, 0U, 0xFFFFFFFFUL);
+ PXP_EnableAlphaSurfaceOverlayColorKey(base, 0U, true);
+#else
+ PXP_SetAlphaSurfaceOverlayColorKey(base, 0U, 0xFFFFFFFFUL);
+ PXP_EnableAlphaSurfaceOverlayColorKey(base, true);
+#endif
+ PXP_SetAlphaSurfacePosition(base, 0, 0, width, height);
+ }
+ else
+ {
+ /* No need to configure AS for formats that do not have alpha value. */
+ PXP_SetAlphaSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0, 0);
+ }
+
+ /* Output config. */
+ pxp_output_buffer_config_t outputBufferConfig;
+ outputBufferConfig.pixelFormat = outFormat;
+ outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
+ outputBufferConfig.buffer0Addr = outAddr;
+ outputBufferConfig.buffer1Addr = 0U;
+ outputBufferConfig.pitchBytes = pitch;
+ outputBufferConfig.width = width;
+ outputBufferConfig.height = height;
+ PXP_SetOutputBufferConfig(base, &outputBufferConfig);
+
+ PXP_EnableCsc1(base, false);
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ PXP_SetPath(PXP, kPXP_Mux3SelectCsc1Engine);
+ PXP_SetPath(PXP, kPXP_Mux8SelectAlphaBlending0);
+ PXP_SetPath(PXP, kPXP_Mux11SelectMux8);
+ PXP_SetPath(PXP, kPXP_Mux14SelectMux11);
+ PXP_SetPath(PXP, kPXP_Mux0SelectNone);
+ PXP_SetPath(PXP, kPXP_Mux6SelectNone);
+ PXP_SetPath(PXP, kPXP_Mux9SelectNone);
+ PXP_SetPath(PXP, kPXP_Mux12SelectNone);
+#endif
+
+ PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
+ /* Start PXP. */
+ PXP_Start(base);
+ /* Wait for process complete. */
+ while (0UL == ((uint32_t)kPXP_CompleteFlag & PXP_GetStatusFlags(base)))
+ {
+ }
+}
+
+/*!
+ * brief Set the next command.
+ *
+ * The PXP supports a primitive ability to queue up one operation while the current
+ * operation is running. Workflow:
+ *
+ * 1. Prepare the PXP register values except STAT, CSCCOEFn, NEXT in the memory
+ * in the order they appear in the register map.
+ * 2. Call this function sets the new operation to PXP.
+ * 3. There are two methods to check whether the PXP has loaded the new operation.
+ * The first method is using ref PXP_IsNextCommandPending. If there is new operation
+ * not loaded by the PXP, this function returns true. The second method is checking
+ * the flag ref kPXP_CommandLoadFlag, if command loaded, this flag asserts. User
+ * could enable interrupt ref kPXP_CommandLoadInterruptEnable to get the loaded
+ * signal in interrupt way.
+ * 4. When command loaded by PXP, a new command could be set using this function.
+ *
+ * param base PXP peripheral base address.
+ * param commandAddr Address of the new command.
+ */
+void PXP_SetNextCommand(PXP_Type *base, void *commandAddr)
+{
+ pxp_pvoid_u32_t addr;
+
+ /* Make sure commands have been saved to memory. */
+ __DSB();
+
+ addr.pvoid = commandAddr;
+
+ base->NEXT = PXP_ADDR_CPU_2_IP(addr.u32) & PXP_NEXT_POINTER_MASK;
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+/*!
+ * brief Set the CSC2 configuration.
+ *
+ * The CSC2 module receives pixels in any color space and can convert the pixels
+ * into any of RGB, YUV, or YCbCr color spaces. The output pixels are passed
+ * onto the LUT and rotation engine for further processing
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetCsc2Config(PXP_Type *base, const pxp_csc2_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t tempReg;
+
+ base->CSC2_CTRL = (base->CSC2_CTRL & ~PXP_CSC2_CTRL_CSC_MODE_MASK) | PXP_CSC2_CTRL_CSC_MODE(config->mode);
+
+ tempReg =
+ (PXP_ConvertFloat(config->A1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A1_SHIFT);
+ base->CSC2_COEF0 = tempReg | (PXP_ConvertFloat(config->A2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
+ << PXP_CSC2_COEF0_A2_SHIFT);
+
+ tempReg =
+ (PXP_ConvertFloat(config->A3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_A3_SHIFT);
+ base->CSC2_COEF1 = tempReg | (PXP_ConvertFloat(config->B1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
+ << PXP_CSC2_COEF1_B1_SHIFT);
+
+ tempReg =
+ (PXP_ConvertFloat(config->B2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B2_SHIFT);
+ base->CSC2_COEF2 = tempReg | (PXP_ConvertFloat(config->B3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
+ << PXP_CSC2_COEF2_B3_SHIFT);
+
+ tempReg =
+ (PXP_ConvertFloat(config->C1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C1_SHIFT);
+ base->CSC2_COEF3 = tempReg | (PXP_ConvertFloat(config->C2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
+ << PXP_CSC2_COEF3_C2_SHIFT);
+
+ tempReg =
+ (PXP_ConvertFloat(config->C3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF4_C3_SHIFT);
+ base->CSC2_COEF4 = tempReg | PXP_CSC2_COEF4_D1(config->D1);
+
+ base->CSC2_COEF5 = PXP_CSC2_COEF5_D2(config->D2) | PXP_CSC2_COEF5_D3(config->D3);
+}
+#endif
+
+/*!
+ * brief Set the CSC1 mode.
+ *
+ * The CSC1 module receives scaled YUV/YCbCr444 pixels from the scale engine and
+ * converts the pixels to the RGB888 color space. It could only be used by process
+ * surface.
+ *
+ * param base PXP peripheral base address.
+ * param mode The conversion mode.
+ */
+void PXP_SetCsc1Mode(PXP_Type *base, pxp_csc1_mode_t mode)
+{
+ /*
+ * The equations used for Colorspace conversion are:
+ *
+ * R = C0*(Y+Y_OFFSET) + C1(V+UV_OFFSET)
+ * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
+ * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
+ */
+
+ if (kPXP_Csc1YUV2RGB == mode)
+ {
+ base->CSC1_COEF0 = (base->CSC1_COEF0 & ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK |
+ PXP_CSC1_COEF0_UV_OFFSET_MASK | PXP_CSC1_COEF0_YCBCR_MODE_MASK)) |
+ PXP_CSC1_COEF0_C0(0x100U) /* 1.00. */
+ | PXP_CSC1_COEF0_Y_OFFSET(0x0U) /* 0. */
+ | PXP_CSC1_COEF0_UV_OFFSET(0x0U); /* 0. */
+ base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0123U) /* 1.140. */
+ | PXP_CSC1_COEF1_C4(0x0208U); /* 2.032. */
+ base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x076BU) /* -0.851. */
+ | PXP_CSC1_COEF2_C3(0x079BU); /* -0.394. */
+ }
+ else
+ {
+ base->CSC1_COEF0 = (base->CSC1_COEF0 &
+ ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK | PXP_CSC1_COEF0_UV_OFFSET_MASK)) |
+ PXP_CSC1_COEF0_YCBCR_MODE_MASK | PXP_CSC1_COEF0_C0(0x12AU) /* 1.164. */
+ | PXP_CSC1_COEF0_Y_OFFSET(0x1F0U) /* -16. */
+ | PXP_CSC1_COEF0_UV_OFFSET(0x180U); /* -128. */
+ base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0198U) /* 1.596. */
+ | PXP_CSC1_COEF1_C4(0x0204U); /* 2.017. */
+ base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x0730U) /* -0.813. */
+ | PXP_CSC1_COEF2_C3(0x079CU); /* -0.392. */
+ }
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+/*!
+ * brief Set the LUT configuration.
+ *
+ * The lookup table (LUT) is used to modify pixels in a manner that is not linear
+ * and that cannot be achieved by the color space conversion modules. To setup
+ * the LUT, the complete workflow is:
+ * 1. Use ref PXP_SetLutConfig to set the configuration, such as the lookup mode.
+ * 2. Use ref PXP_LoadLutTable to load the lookup table to PXP.
+ * 3. Use ref PXP_EnableLut to enable the function.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetLutConfig(PXP_Type *base, const pxp_lut_config_t *config)
+{
+ base->LUT_CTRL = (base->LUT_CTRL & ~(PXP_LUT_CTRL_OUT_MODE_MASK | PXP_LUT_CTRL_LOOKUP_MODE_MASK)) |
+ PXP_LUT_CTRL_LRU_UPD_MASK | /* Use Least Recently Used Policy Update Control. */
+ PXP_LUT_CTRL_OUT_MODE(config->outMode) | PXP_LUT_CTRL_LOOKUP_MODE(config->lookupMode);
+
+ if (kPXP_LutOutRGBW4444CFA == config->outMode)
+ {
+ base->CFA = config->cfaValue;
+ }
+}
+
+/*!
+ * brief Set the look up table to PXP.
+ *
+ * If lookup mode is DIRECT mode, this function loads p bytesNum of values
+ * from the address p memAddr into PXP LUT address p lutStartAddr. So this
+ * function allows only update part of the PXP LUT.
+ *
+ * If lookup mode is CACHE mode, this function sets the new address to p memAddr
+ * and invalid the PXP LUT cache.
+ *
+ * param base PXP peripheral base address.
+ * param lookupMode Which lookup mode is used. Note that this parameter is only
+ * used to distinguish DIRECT mode and CACHE mode, it does not change the register
+ * value PXP_LUT_CTRL[LOOKUP_MODE]. To change that value, use function ref PXP_SetLutConfig.
+ * param bytesNum How many bytes to set. This value must be divisable by 8.
+ * param memAddr Address of look up table to set.
+ * param lutStartAddr The LUT value will be loaded to LUT from index lutAddr. It should
+ * be 8 bytes aligned.
+ *
+ * retval kStatus_Success Load successfully.
+ * retval kStatus_InvalidArgument Failed because of invalid argument.
+ */
+status_t PXP_LoadLutTable(
+ PXP_Type *base, pxp_lut_lookup_mode_t lookupMode, uint32_t bytesNum, uint32_t memAddr, uint16_t lutStartAddr)
+{
+ memAddr = PXP_ADDR_CPU_2_IP(memAddr);
+
+ if (kPXP_LutCacheRGB565 == lookupMode)
+ {
+ /* Make sure the previous memory write is finished, especially the LUT data memory. */
+ __DSB();
+
+ base->LUT_EXTMEM = memAddr;
+ /* Invalid cache. */
+ base->LUT_CTRL |= PXP_LUT_CTRL_INVALID_MASK;
+ }
+ else
+ {
+ /* Number of bytes must be divisable by 8. */
+ if (((bytesNum & 0x07U) != 0U) || (bytesNum < 8U) || ((lutStartAddr & 0x07U) != 0U) ||
+ (bytesNum + (uint32_t)lutStartAddr > PXP_LUT_TABLE_BYTE))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ base->LUT_EXTMEM = memAddr;
+ base->LUT_ADDR = PXP_LUT_ADDR_ADDR(lutStartAddr) | PXP_LUT_ADDR_NUM_BYTES(bytesNum);
+
+ base->STAT_CLR = PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK;
+
+ /* Start DMA transfer. */
+ base->LUT_CTRL |= PXP_LUT_CTRL_DMA_START_MASK;
+
+ __DSB();
+
+ /* Wait for transfer completed. */
+ while (0U == (base->STAT & PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK))
+ {
+ }
+ }
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
+
+#if (defined(FSL_FEATURE_PXP_HAS_DITHER) && FSL_FEATURE_PXP_HAS_DITHER)
+/*!
+ * brief Write data to the PXP internal memory.
+ *
+ * param base PXP peripheral base address.
+ * param ram Which internal memory to write.
+ * param bytesNum How many bytes to write.
+ * param data Pointer to the data to write.
+ * param memStartAddr The start address in the internal memory to write the data.
+ */
+void PXP_SetInternalRamData(PXP_Type *base, pxp_ram_t ram, uint32_t bytesNum, uint8_t *data, uint16_t memStartAddr)
+{
+ assert(((uint32_t)memStartAddr + bytesNum) <= (uint32_t)PXP_INTERNAL_RAM_LUT_BYTE);
+
+ base->INIT_MEM_CTRL =
+ PXP_INIT_MEM_CTRL_ADDR(memStartAddr) | PXP_INIT_MEM_CTRL_SELECT(ram) | PXP_INIT_MEM_CTRL_START_MASK;
+
+ while (0U != bytesNum--)
+ {
+ base->INIT_MEM_DATA = (uint32_t)(*data);
+ data++;
+ }
+
+ base->INIT_MEM_CTRL = 0U;
+}
+
+/*!
+ * brief Set the dither final LUT data.
+ *
+ * The dither final LUT is only applicble to dither engine 0. It takes the bits[7:4]
+ * of the output pixel and looks up and 8 bit value from the 16 value LUT to generate
+ * the final output pixel to the next process module.
+ *
+ * param base PXP peripheral base address.
+ * param data Pointer to the LUT data to set.
+ */
+void PXP_SetDitherFinalLutData(PXP_Type *base, const pxp_dither_final_lut_data_t *data)
+{
+ base->DITHER_FINAL_LUT_DATA0 = data->data_3_0;
+ base->DITHER_FINAL_LUT_DATA1 = data->data_7_4;
+ base->DITHER_FINAL_LUT_DATA2 = data->data_11_8;
+ base->DITHER_FINAL_LUT_DATA3 = data->data_15_12;
+}
+
+/*!
+ * brief Enable or disable dither engine in the PXP process path.
+ *
+ * After the initialize function ref PXP_Init, the dither engine is disabled and not
+ * use in the PXP processing path. This function enables the dither engine and
+ * routes the dither engine output to the output buffer. When the dither engine
+ * is enabled using this function, ref PXP_SetDitherConfig must be called to
+ * configure dither engine correctly, otherwise there is not output to the output
+ * buffer.
+ *
+ * param base PXP peripheral base address.
+ * param enable Pass in true to enable, false to disable.
+ */
+void PXP_EnableDither(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_SET = PXP_CTRL_ENABLE_DITHER_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = PXP_CTRL_ENABLE_DITHER_MASK;
+ }
+}
+#endif /* FSL_FEATURE_PXP_HAS_DITHER */
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * brief Set the Porter Duff configuration for one of the alpha process engine.
+ *
+ * param base PXP peripheral base address.
+ * param num instance number.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetPorterDuffConfig(PXP_Type *base, uint8_t num, const pxp_porter_duff_config_t *config)
+{
+ assert(NULL != config);
+
+ union
+ {
+ pxp_porter_duff_config_t pdConfigStruct;
+ uint32_t u32;
+ } pdConfig;
+
+ pdConfig.pdConfigStruct = *config;
+
+ switch (num)
+ {
+ case 0:
+ base->ALPHA_A_CTRL = pdConfig.u32;
+ break;
+
+ case 1:
+ base->ALPHA_B_CTRL = pdConfig.u32;
+ break;
+
+ default:
+ /* Only 2 alpha process engine instances are supported. */
+ assert(false);
+ break;
+ }
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)
+/*!
+ * brief Set the Porter Duff configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetPorterDuffConfig(PXP_Type *base, const pxp_porter_duff_config_t *config)
+{
+ assert(NULL != config);
+
+ union
+ {
+ pxp_porter_duff_config_t pdConfigStruct;
+ uint32_t u32;
+ } pdConfig;
+
+ pdConfig.pdConfigStruct = *config;
+
+ base->PORTER_DUFF_CTRL = pdConfig.u32;
+}
+#endif /* FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
+
+#if (!(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)) || \
+ (defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)
+/*!
+ * brief Get the Porter Duff configuration by blend mode.
+ *
+ * param mode The blend mode.
+ * param config Pointer to the configuration.
+ * retval kStatus_Success Successfully get the configuratoin.
+ * retval kStatus_InvalidArgument The blend mode not supported.
+ */
+status_t PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode, pxp_porter_duff_config_t *config)
+{
+ status_t status;
+
+ union
+ {
+ pxp_porter_duff_config_t pdConfigStruct;
+ uint32_t u32;
+ } pdConfig;
+
+ static const uint32_t pdCtrl[] = {
+ /* kPXP_PorterDuffSrc */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffAtop */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffOver */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffIn */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffOut */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffDst */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
+
+ /* kPXP_PorterDuffDstAtop */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
+
+ /* kPXP_PorterDuffDstOver */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
+
+ /* kPXP_PorterDuffDstIn */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
+
+ /* kPXP_PorterDuffDstOut */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffXor */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffClear */
+ PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+ };
+
+ if (mode >= kPXP_PorterDuffMax)
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ pdConfig.u32 = pdCtrl[(uint32_t)mode] | S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) | S0_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) |
+ S1_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) | S0_ALPHA_MODE(kPXP_PorterDuffAlphaStraight) |
+ S1_ALPHA_MODE(kPXP_PorterDuffAlphaStraight);
+
+ *config = pdConfig.pdConfigStruct;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_PXP_V3 || FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
+
+static void PXP_StartRectCopy(PXP_Type *base,
+ uint32_t srcAddr,
+ uint16_t srcPitchBytes,
+ uint32_t destAddr,
+ uint16_t destPitchBytes,
+ uint16_t width,
+ uint16_t height,
+ pxp_as_pixel_format_t pixelFormat)
+{
+ pxp_output_buffer_config_t outputBufferConfig;
+ pxp_as_buffer_config_t asBufferConfig;
+ uint32_t intMask;
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+ intMask =
+ base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK | PXP_CTRL_LUT_DMA_IRQ_ENABLE_MASK);
+#else
+ intMask = base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK);
+#endif
+
+ PXP_ResetControl(base);
+
+ /* Restore previous interrupt configuration. */
+ PXP_EnableInterrupts(base, intMask);
+
+ /* Disable PS */
+ PXP_SetProcessSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
+
+ /* Input buffer. */
+ asBufferConfig.pixelFormat = pixelFormat;
+ asBufferConfig.bufferAddr = srcAddr;
+ asBufferConfig.pitchBytes = srcPitchBytes;
+
+ PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
+ PXP_SetAlphaSurfacePosition(base, 0U, 0U, width - 1U, height - 1U);
+
+ /* Alpha mode set to ROP, AS OR PS */
+ const pxp_as_blend_config_t asBlendConfig = {
+ .alpha = 0U, .invertAlpha = false, .alphaMode = kPXP_AlphaRop, .ropMode = kPXP_RopMergeAs};
+
+ PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
+
+ /* Output buffer. */
+ outputBufferConfig.pixelFormat = (pxp_output_pixel_format_t)pixelFormat;
+ outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
+ outputBufferConfig.buffer0Addr = destAddr;
+ outputBufferConfig.buffer1Addr = 0U;
+ outputBufferConfig.pitchBytes = destPitchBytes;
+ outputBufferConfig.width = width;
+ outputBufferConfig.height = height;
+
+ PXP_SetOutputBufferConfig(base, &outputBufferConfig);
+
+ PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
+
+ PXP_Start(base);
+}
+
+/*!
+ * brief Copy picture from one buffer to another buffer.
+ *
+ * This function copies a rectangle from one buffer to another buffer.
+ *
+ * param base PXP peripheral base address.
+ * retval kStatus_Success Successfully started the copy process.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartPictureCopy(PXP_Type *base, const pxp_pic_copy_config_t *config)
+{
+ uint8_t bytePerPixel;
+ uint32_t copyFromAddr;
+ uint32_t copyToAddr;
+
+ if ((0U == config->height) || (0U == config->width))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((config->pixelFormat == kPXP_AsPixelFormatARGB8888) || (config->pixelFormat == kPXP_AsPixelFormatRGB888))
+ {
+ bytePerPixel = 4U;
+ }
+ else
+ {
+ bytePerPixel = 2U;
+ }
+
+ copyFromAddr = config->srcPicBaseAddr + ((uint32_t)config->srcOffsetY * (uint32_t)config->srcPitchBytes) +
+ bytePerPixel * config->srcOffsetX;
+ copyToAddr = config->destPicBaseAddr + ((uint32_t)config->destOffsetY * (uint32_t)config->destPitchBytes) +
+ bytePerPixel * config->destOffsetX;
+
+ PXP_StartRectCopy(base, copyFromAddr, config->srcPitchBytes, copyToAddr, config->destPitchBytes, config->width,
+ config->height, config->pixelFormat);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Copy continous memory.
+ *
+ * The copy size should be 512 byte aligned.
+ *
+ * param base PXP peripheral base address.
+ * retval kStatus_Success Successfully started the copy process.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartMemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
+{
+ uint16_t pitchBytes;
+ uint32_t height;
+
+ if ((0U == size) || ((size % 512U) != 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /*
+ * By default, PXP process block is 8x8. For better performance, choose
+ * width and height dividable by block size.
+ */
+ if (size < 8U * 512U)
+ {
+ height = 8U;
+ pitchBytes = (uint16_t)(size / height);
+ }
+ else
+ {
+ pitchBytes = 512U;
+ height = size / pitchBytes;
+ }
+
+ if (height > PXP_MAX_HEIGHT)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
+ kPXP_AsPixelFormatARGB8888);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Copy continous memory.
+ *
+ * param base PXP peripheral base address.
+ * retval kStatus_Success Successfully started the copy process.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_MemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
+{
+ uint16_t pitchBytes;
+ uint32_t height;
+ uint32_t unalignedSize;
+
+ if (0U == size)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* For 512 not aligned part, copy by CPU. */
+ unalignedSize = size % 512U;
+
+ if (0UL != unalignedSize)
+ {
+ (void)memcpy((uint8_t *)destAddr, (uint8_t *)srcAddr, unalignedSize);
+
+ destAddr += unalignedSize;
+ srcAddr += unalignedSize;
+ size -= unalignedSize;
+ }
+
+ if (0UL != size)
+ {
+ /*
+ * By default, PXP process block is 8x8. For better performance, choose
+ * width and height dividable by block size.
+ */
+ if (size < 8U * 512U)
+ {
+ height = 8U;
+ pitchBytes = (uint16_t)(size / height);
+ }
+ else
+ {
+ pitchBytes = 512U;
+ height = size / pitchBytes;
+ }
+
+ if (height > PXP_MAX_HEIGHT)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
+ kPXP_AsPixelFormatARGB8888);
+
+ while (0UL == ((uint32_t)kPXP_CompleteFlag & PXP_GetStatusFlags(base)))
+ {
+ }
+
+ PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
+ }
+
+ return kStatus_Success;
+}
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+
+/*!
+ * brief Configures one channle of some block's fetch engine.
+ *
+ * Fetch engine is 64-bit input and 32-bit output per channel
+ *
+ * param base PXP peripheral base address.
+ * param name which block the fetch engine belongs to.
+ * param channel channel number.
+ * param config pointer to the configuration structure.
+ * retval kStatus_Success Successfully configured the engine.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetFetchEngineConfig(PXP_Type *base,
+ pxp_fetch_engine_name_t name,
+ uint8_t channel,
+ const pxp_fetch_engine_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Check fetch address */
+ if ((config->inputBaseAddr0 == 0U) ||
+ ((config->inputBaseAddr1 == 0U) && (config->pixelFormat == kPXP_FetchFormatYUV422_2P)))
+ {
+ return kStatus_InvalidArgument;
+ }
+ /* Must enable expand when input pixel format is YUV422_2P, to combine Y and UV buffer to one output. */
+ if ((config->expandEnable == false) && (config->pixelFormat == kPXP_FetchFormatYUV422_2P))
+ {
+ return kStatus_InvalidArgument;
+ }
+ /* Must enable block if flip or rotation is enabled. */
+ if ((config->fetchFormat.enableblock == false) &&
+ ((config->flipMode != kPXP_FlipDisable) || (config->rotateDegree != kPXP_Rotate0)))
+ {
+ return kStatus_InvalidArgument;
+ }
+ /* Block mode cannot work in 64-bit mode */
+ if ((config->fetchFormat.enableblock == true) && (config->activeBits == kPXP_Active64Bits))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t ctrlReg = 0U;
+ uint32_t ulcReg = 0U;
+ uint32_t lrcReg = 0U;
+ uint32_t fetchSizeReg = 0U;
+ uint32_t shiftCtrlReg = 0U;
+ uint32_t shiftOffsetReg = 0U;
+ uint32_t shiftWidthReg = 0U;
+ uint8_t scanlineNum = 0U;
+
+ /* When block disabled, handshake scanline mode can only use 1 line mode where scanlineNum = 0. */
+ if (config->fetchFormat.enableblock)
+ {
+ /* */
+ if (config->fetchFormat.blockSize16)
+ {
+ scanlineNum = 2;
+ }
+ else
+ {
+ scanlineNum = 1;
+ }
+ }
+
+ ctrlReg = PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM((uint32_t)scanlineNum) |
+ PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES(config->fetchFormat.burstLength) |
+ PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE((uint32_t)config->rotateDegree) |
+ ((uint32_t)config->flipMode << PXP_INPUT_FETCH_CTRL_CH0_HFLIP_SHIFT) |
+ PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE((uint32_t)config->wordOrder) |
+ ((uint32_t)config->interface << PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN_SHIFT) |
+ PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN((uint32_t)config->fetchFormat.enableblock) |
+ PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16((uint32_t)config->fetchFormat.blockSize16) |
+ PXP_INPUT_FETCH_CTRL_CH0_CH_EN((uint32_t)config->channelEnable);
+ ulcReg = (((uint32_t)config->ulcY) << 16U) | (uint32_t)config->ulcX;
+ lrcReg = (((uint32_t)config->lrcY) << 16U) | (uint32_t)config->lrcX;
+ fetchSizeReg = (((uint32_t)config->totalHeight) << 16U) | ((uint32_t)config->totalWidth);
+ shiftCtrlReg = PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP((uint32_t)config->activeBits) |
+ PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT((uint32_t)config->pixelFormat) |
+ PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN((uint32_t)config->expandEnable) |
+ PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS((uint32_t)config->shiftConfig.shiftBypass);
+ if (!config->shiftConfig.shiftBypass)
+ {
+ shiftOffsetReg = (uint32_t)config->shiftConfig.component0.offset |
+ ((uint32_t)(config->shiftConfig.component1.offset) << 8U) |
+ ((uint32_t)(config->shiftConfig.component2.offset) << 16U) |
+ ((uint32_t)(config->shiftConfig.component3.offset) << 24U);
+ shiftWidthReg = (uint32_t)config->shiftConfig.component0.width |
+ ((uint32_t)(config->shiftConfig.component1.width) << 4U) |
+ ((uint32_t)(config->shiftConfig.component2.width) << 8U) |
+ ((uint32_t)(config->shiftConfig.component3.width) << 12U);
+ }
+
+ if (name == kPXP_FetchInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_FETCH_CTRL_CH0 = ctrlReg;
+ base->INPUT_FETCH_ACTIVE_SIZE_ULC_CH0 = ulcReg;
+ base->INPUT_FETCH_ACTIVE_SIZE_LRC_CH0 = lrcReg;
+ base->INPUT_FETCH_SIZE_CH0 = fetchSizeReg;
+ base->INPUT_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH_MASK) |
+ (uint32_t)config->pitchBytes;
+ base->INPUT_FETCH_SHIFT_CTRL_CH0 = shiftCtrlReg;
+ base->INPUT_FETCH_ADDR_0_CH0 = config->inputBaseAddr0;
+ base->INPUT_FETCH_ADDR_1_CH0 = config->inputBaseAddr1;
+ if (!config->shiftConfig.shiftBypass)
+ {
+ base->INPUT_FETCH_SHIFT_OFFSET_CH0 = shiftOffsetReg;
+ base->INPUT_FETCH_SHIFT_WIDTH_CH0 = shiftWidthReg;
+ }
+ break;
+
+ case 1:
+ base->INPUT_FETCH_CTRL_CH1 = ctrlReg;
+ base->INPUT_FETCH_ACTIVE_SIZE_ULC_CH1 = ulcReg;
+ base->INPUT_FETCH_ACTIVE_SIZE_LRC_CH1 = lrcReg;
+ base->INPUT_FETCH_SIZE_CH1 = fetchSizeReg;
+ base->INPUT_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH_MASK) |
+ ((uint32_t)config->pitchBytes << 16U);
+ base->INPUT_FETCH_SHIFT_CTRL_CH1 = shiftCtrlReg;
+ base->INPUT_FETCH_ADDR_0_CH1 = config->inputBaseAddr0;
+ base->INPUT_FETCH_ADDR_1_CH1 = config->inputBaseAddr1;
+ if (!config->shiftConfig.shiftBypass)
+ {
+ base->INPUT_FETCH_SHIFT_OFFSET_CH1 = shiftOffsetReg;
+ base->INPUT_FETCH_SHIFT_WIDTH_CH1 = shiftWidthReg;
+ }
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_FETCH_CTRL_CH0 = ctrlReg;
+ base->DITHER_FETCH_ACTIVE_SIZE_ULC_CH0 = ulcReg;
+ base->DITHER_FETCH_ACTIVE_SIZE_LRC_CH0 = lrcReg;
+ base->DITHER_FETCH_SIZE_CH0 = fetchSizeReg;
+ base->DITHER_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH_MASK) |
+ (uint32_t)config->pitchBytes;
+ base->DITHER_FETCH_SHIFT_CTRL_CH0 = shiftCtrlReg;
+ base->DITHER_FETCH_ADDR_0_CH0 = config->inputBaseAddr0;
+ base->DITHER_FETCH_ADDR_1_CH0 = config->inputBaseAddr1;
+ if (!config->shiftConfig.shiftBypass)
+ {
+ base->DITHER_FETCH_SHIFT_OFFSET_CH0 = shiftOffsetReg;
+ base->DITHER_FETCH_SHIFT_WIDTH_CH0 = shiftWidthReg;
+ }
+ break;
+
+ case 1:
+ base->DITHER_FETCH_CTRL_CH1 = ctrlReg;
+ base->DITHER_FETCH_ACTIVE_SIZE_ULC_CH1 = ulcReg;
+ base->DITHER_FETCH_ACTIVE_SIZE_LRC_CH1 = lrcReg;
+ base->DITHER_FETCH_SIZE_CH1 = fetchSizeReg;
+ base->DITHER_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH_MASK) |
+ ((uint32_t)config->pitchBytes << 16U);
+ base->DITHER_FETCH_SHIFT_CTRL_CH1 = shiftCtrlReg;
+ base->DITHER_FETCH_ADDR_0_CH1 = config->inputBaseAddr0;
+ base->DITHER_FETCH_ADDR_1_CH1 = config->inputBaseAddr1;
+ if (!config->shiftConfig.shiftBypass)
+ {
+ base->DITHER_FETCH_SHIFT_OFFSET_CH1 = shiftOffsetReg;
+ base->DITHER_FETCH_SHIFT_WIDTH_CH1 = shiftWidthReg;
+ }
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures one channel of some block's store engine.
+ *
+ * Store engine is 32-bit input and 64-bit output per channel.
+ * note: If there is only one channel used for data input, channel 0 must be used rather than channel 1.
+ *
+ * param base PXP peripheral base address.
+ * param name the store engine belongs to which block.
+ * param channel channel number.
+ * param config pointer to the configuration structure.
+ * retval kStatus_Success Successfully configured the engine.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetStoreEngineConfig(PXP_Type *base,
+ pxp_store_engine_name_t name,
+ uint8_t channel,
+ const pxp_store_engine_config_t *config)
+{
+ assert(NULL != config);
+ /* Can only choose one plane for YUV422_2p for one channel output */
+ if ((uint32_t)config->yuvMode == 0x3U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Block mode cannot work in 64-bit mode or YUV422_2p mode */
+ if ((config->storeFormat.enableblock == true) &&
+ ((config->activeBits == kPXP_Active64Bits) || (config->yuvMode != kPXP_StoreYUVDisable)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* When block mode is disabled the interface array size can only be 1. TODO. The availiable fetch engine now are
+ only input&fetch that can only use handshake 1x1, no need to check */
+ // if ((config->storeFormat.enableblock == false) && (config->arraySize != kPXP_StoreHandshake1x1))
+ // {
+ // return kStatus_InvalidArgument;
+ // }
+
+ uint32_t ctrlReg = 0U;
+ uint32_t shiftCtrlReg = 0U;
+ uint32_t sizeReg = 0U;
+ uint32_t dataShiftMaskRegAddr = 0U;
+ uint32_t dataShiftWidthRegAddr = 0U;
+ uint32_t flagShiftMaskRegAddr = 0U;
+ uint32_t flagShiftWidthRegAddr = 0U;
+
+ ctrlReg = PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES((uint32_t)config->storeFormat.burstLength) |
+ PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN((uint32_t)config->useFixedData) |
+ PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL((uint32_t)config->packInSelect) |
+ ((uint32_t)config->interface << PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN_SHIFT) |
+ // PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM((uint32_t)config->arraySize) |
+ PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM(0U) |
+ PXP_INPUT_STORE_CTRL_CH0_BLOCK_16((uint32_t)config->storeFormat.enableblock) |
+ PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN((uint32_t)config->storeFormat.blockSize16) |
+ PXP_INPUT_STORE_CTRL_CH0_CH_EN((uint32_t)config->channelEnable);
+ shiftCtrlReg = PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS((uint32_t)config->shiftConfig.shiftBypass) |
+ ((uint32_t)config->yuvMode << PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN_SHIFT) |
+ PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP((uint32_t)config->activeBits);
+ sizeReg = (((uint32_t)config->totalHeight) << 16U) | ((uint32_t)config->totalWidth);
+
+ if (name == kPXP_StoreInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_STORE_CTRL_CH0 = ctrlReg;
+ base->INPUT_STORE_SIZE_CH0 = sizeReg;
+ base->INPUT_STORE_PITCH = (base->INPUT_STORE_PITCH & PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH_MASK) |
+ (uint32_t)(config->pitchBytes);
+ base->INPUT_STORE_SHIFT_CTRL_CH0 = shiftCtrlReg;
+ base->INPUT_STORE_ADDR_0_CH0 = config->outputBaseAddr0;
+ base->INPUT_STORE_ADDR_1_CH0 = config->outputBaseAddr1;
+ base->INPUT_STORE_FILL_DATA_CH0 = config->fixedData;
+ dataShiftMaskRegAddr = (uint32_t) & (base->INPUT_STORE_D_MASK0_H_CH0);
+ dataShiftWidthRegAddr = (uint32_t) & (base->INPUT_STORE_D_SHIFT_L_CH0);
+ flagShiftMaskRegAddr = (uint32_t) & (base->INPUT_STORE_F_MASK_L_CH0);
+ flagShiftWidthRegAddr = (uint32_t) & (base->INPUT_STORE_F_SHIFT_L_CH0);
+ break;
+
+ case 1:
+ base->INPUT_STORE_CTRL_CH1 = ctrlReg;
+ base->INPUT_STORE_SIZE_CH1 = sizeReg;
+ base->INPUT_STORE_PITCH = (base->INPUT_STORE_PITCH & PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH_MASK) |
+ ((uint32_t)(config->pitchBytes) << 16U);
+ base->INPUT_STORE_SHIFT_CTRL_CH1 = shiftCtrlReg;
+ base->INPUT_STORE_ADDR_0_CH1 = config->outputBaseAddr0;
+ base->INPUT_STORE_ADDR_1_CH1 = config->outputBaseAddr1;
+ dataShiftMaskRegAddr = (uint32_t) & (base->INPUT_STORE_D_MASK0_H_CH0);
+ dataShiftWidthRegAddr = (uint32_t) & (base->INPUT_STORE_D_SHIFT_L_CH0);
+ flagShiftMaskRegAddr = (uint32_t) & (base->INPUT_STORE_F_MASK_L_CH0);
+ flagShiftWidthRegAddr = (uint32_t) & (base->INPUT_STORE_F_SHIFT_L_CH0);
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_STORE_CTRL_CH0 = ctrlReg;
+ base->DITHER_STORE_SIZE_CH0 = sizeReg;
+ base->DITHER_STORE_PITCH = (base->DITHER_STORE_PITCH & PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH_MASK) |
+ (uint32_t)(config->pitchBytes);
+ base->DITHER_STORE_SHIFT_CTRL_CH0 = shiftCtrlReg;
+ base->DITHER_STORE_ADDR_0_CH0 = config->outputBaseAddr0;
+ base->DITHER_STORE_ADDR_1_CH0 = config->outputBaseAddr1;
+ base->DITHER_STORE_FILL_DATA_CH0 = config->fixedData;
+ dataShiftMaskRegAddr = (uint32_t) & (base->DITHER_STORE_D_MASK0_H_CH0);
+ dataShiftWidthRegAddr = (uint32_t) & (base->DITHER_STORE_D_SHIFT_L_CH0);
+ flagShiftMaskRegAddr = (uint32_t) & (base->DITHER_STORE_F_MASK_L_CH0);
+ flagShiftWidthRegAddr = (uint32_t) & (base->DITHER_STORE_F_SHIFT_L_CH0);
+ break;
+
+ case 1:
+ base->DITHER_STORE_CTRL_CH1 = ctrlReg;
+ base->DITHER_STORE_SIZE_CH1 = sizeReg;
+ base->DITHER_STORE_PITCH = (base->DITHER_STORE_PITCH & PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH_MASK) |
+ ((uint32_t)(config->pitchBytes) << 16U);
+ base->DITHER_STORE_SHIFT_CTRL_CH1 = shiftCtrlReg;
+ base->DITHER_STORE_ADDR_0_CH1 = config->outputBaseAddr0;
+ base->DITHER_STORE_ADDR_1_CH1 = config->outputBaseAddr1;
+ dataShiftMaskRegAddr = (uint32_t) & (base->DITHER_STORE_D_MASK0_H_CH0);
+ dataShiftWidthRegAddr = (uint32_t) & (base->DITHER_STORE_D_SHIFT_L_CH0);
+ flagShiftMaskRegAddr = (uint32_t) & (base->DITHER_STORE_F_MASK_L_CH0);
+ flagShiftWidthRegAddr = (uint32_t) & (base->DITHER_STORE_F_SHIFT_L_CH0);
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+
+ /* Shift configuration */
+ if (!config->shiftConfig.shiftBypass)
+ {
+ uint8_t i;
+ uint32_t dataShiftMaskAddr = (uint32_t) & (config->shiftConfig.pDataShiftMask);
+ uint32_t dataShiftWidthAddr = (uint32_t) & (config->shiftConfig.pDataShiftWidth);
+ uint32_t flagShiftMaskAddr = (uint32_t) & (config->shiftConfig.pFlagShiftMask);
+ uint32_t flagShiftWidthAddr = (uint32_t) & (config->shiftConfig.pFlagShiftWidth);
+
+ /* Configure data shift mask */
+ for (i = 0U; i < 8U; i++)
+ {
+ *(uint32_t *)dataShiftMaskRegAddr = (uint32_t)(*(uint64_t *)dataShiftMaskAddr >> 32U);
+ dataShiftMaskRegAddr += 0x10U;
+ *(uint32_t *)dataShiftMaskRegAddr = (uint32_t)(*(uint64_t *)dataShiftMaskAddr);
+ dataShiftMaskRegAddr += 0x10U;
+ dataShiftMaskAddr += 8U;
+ }
+
+ /* Configure data shift width, flag shift mask/width */
+ for (i = 0U; i < 8U; i++)
+ {
+ *(uint8_t *)dataShiftWidthRegAddr = *(uint8_t *)dataShiftWidthAddr;
+ *(uint8_t *)flagShiftMaskRegAddr = *(uint8_t *)flagShiftMaskAddr;
+ *(uint8_t *)flagShiftWidthRegAddr = *(uint8_t *)flagShiftWidthAddr;
+ dataShiftWidthRegAddr++;
+ flagShiftMaskRegAddr++;
+ flagShiftWidthRegAddr++;
+ dataShiftWidthAddr++;
+ flagShiftMaskAddr++;
+ flagShiftWidthAddr++;
+ if (i == 3U)
+ {
+ dataShiftWidthRegAddr += 12U;
+ flagShiftMaskRegAddr += 12U;
+ flagShiftWidthRegAddr += 12U;
+ }
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures the pre-dither CFA engine.
+ *
+ * param base PXP peripheral base address.
+ * param config pointer to the configuration structure.
+ * retval kStatus_Success Successfully configured the engine.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetCfaConfig(PXP_Type *base, const pxp_cfa_config_t *config)
+{
+ assert(NULL != config);
+ /* The CFA array cannot be larger than 15x15. */
+ if ((config->arrayWidth > 15U) || (config->arrayHeight > 15U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t cfaArrayRegAddr = (uint32_t) & (base->CFA_ARRAY0);
+ uint32_t cfaValueAddr = (uint32_t) & (config->cfaValue);
+ uint8_t wordCount = 0U; /* How many 32-bit word does the CFA array need. */
+
+ base->CFA_CTRL = PXP_CFA_CTRL_CFA_ARRAY_HSIZE((uint32_t)config->arrayWidth) |
+ PXP_CFA_CTRL_CFA_ARRAY_VSIZE((uint32_t)config->arrayHeight) |
+ PXP_CFA_CTRL_CFA_IN_RGB444((uint32_t)config->pixelInFormat) |
+ PXP_CFA_CTRL_CFA_BYPASS((uint32_t)config->bypass);
+ base->CFA_SIZE = ((uint32_t)(config->totalWidth) << 16U) | (uint32_t)(config->totalHeight);
+
+ /* Configure the CFA array value. */
+ wordCount = (config->arrayWidth * config->arrayHeight * 2U + 32U) / 32U;
+
+ for (uint8_t i = 0U; i < wordCount; i++)
+ {
+ *(uint32_t *)cfaArrayRegAddr = *(uint32_t *)cfaValueAddr;
+ cfaArrayRegAddr += 0x10U;
+ cfaValueAddr += 4U;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures histogram engine.
+ *
+ * param base PXP peripheral base address.
+ * param num instance number.
+ * param config pointer to the configuration structure.
+ * retval kStatus_Success Successfully configured the engine.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetHistogramConfig(PXP_Type *base, uint8_t num, const pxp_histogram_config_t *config)
+{
+ assert(NULL != config);
+ /* The LUT value width can not be larger than 6. */
+ if ((uint32_t)config->lutValueWidth > 6U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t ctrlReg = 0U;
+ uint32_t maskReg = 0U;
+
+ ctrlReg = PXP_HIST_A_CTRL_ENABLE((uint32_t)config->enable) |
+ PXP_HIST_A_CTRL_PIXEL_OFFSET((uint32_t)config->lutValueOffset) |
+ PXP_HIST_A_CTRL_PIXEL_WIDTH((uint32_t)config->lutValueWidth);
+ maskReg = PXP_HIST_A_MASK_MASK_EN((uint32_t)config->enableMask) |
+ PXP_HIST_A_MASK_MASK_MODE((uint32_t)config->condition) |
+ PXP_HIST_A_MASK_MASK_OFFSET((uint32_t)config->maskOffset) |
+ PXP_HIST_A_MASK_MASK_WIDTH((uint32_t)config->maskWidth) |
+ PXP_HIST_A_MASK_MASK_VALUE0((uint32_t)config->maskValue0) |
+ PXP_HIST_A_MASK_MASK_VALUE1((uint32_t)config->maskValue1);
+
+ switch (num)
+ {
+ case 0:
+ base->HIST_A_CTRL = ctrlReg;
+ base->HIST_A_MASK = maskReg;
+ base->HIST_A_BUF_SIZE = ((uint32_t)(config->totalHeight) << 16U) | (uint32_t)config->totalWidth;
+ break;
+
+ case 1:
+ base->HIST_B_CTRL = ctrlReg;
+ base->HIST_B_MASK = maskReg;
+ base->HIST_B_BUF_SIZE = ((uint32_t)(config->totalHeight) << 16U) | (uint32_t)config->totalWidth;
+ break;
+
+ default:
+ /* Only 2 histogram instances are supported. */
+ assert(false);
+ break;
+ }
+
+ /* Only configure the histogram params when user choose to, otherwise use the registers' reset value as default. */
+ if (config->pParamValue != NULL)
+ {
+ uint32_t paramRegAddr = (uint32_t) & (base->HIST2_PARAM);
+ uint32_t paramValueAddr = (uint32_t) & (config->pParamValue);
+ /* Configure the 2/4/8/16/32-level histogram params. */
+ for (uint8_t i = 0; i < 62U; i++)
+ {
+ *(uint8_t *)paramRegAddr = *(uint8_t *)paramValueAddr;
+ paramValueAddr += 1U;
+ paramRegAddr++;
+ if ((i % 4U) == 1U)
+ {
+ paramRegAddr += 12U;
+ if (i == 1U)
+ {
+ paramRegAddr += 2U;
+ }
+ }
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the results of histogram mask operation.
+ *
+ * param base PXP peripheral base address.
+ * param num instance number.
+ * param result pointer to the result structure.
+ */
+void PXP_GetHistogramMaskResult(PXP_Type *base, uint8_t num, pxp_histogram_mask_result_t *result)
+{
+ assert(NULL != result);
+ /* Initializes the result structure to zero. */
+ (void)memset(result, 0, sizeof(*result));
+
+ switch (num)
+ {
+ case 0:
+ result->pixelCount = base->HIST_A_TOTAL_PIXEL;
+ result->minX = (uint16_t)base->HIST_A_ACTIVE_AREA_X;
+ result->maxX = (uint16_t)(base->HIST_A_ACTIVE_AREA_X >> 16U);
+ result->minY = (uint16_t)base->HIST_A_ACTIVE_AREA_Y;
+ result->maxY = (uint16_t)(base->HIST_A_ACTIVE_AREA_Y >> 16U);
+ result->lutlist = (uint64_t)base->HIST_A_RAW_STAT0 | ((uint64_t)base->HIST_A_RAW_STAT1 << 32U);
+ break;
+
+ case 1:
+ result->pixelCount = base->HIST_B_TOTAL_PIXEL;
+ result->minX = (uint16_t)base->HIST_B_ACTIVE_AREA_X;
+ result->maxX = (uint16_t)(base->HIST_B_ACTIVE_AREA_X >> 16U);
+ result->minY = (uint16_t)base->HIST_B_ACTIVE_AREA_Y;
+ result->maxY = (uint16_t)(base->HIST_B_ACTIVE_AREA_Y >> 16U);
+ result->lutlist = (uint64_t)base->HIST_B_RAW_STAT0 | ((uint64_t)base->HIST_B_RAW_STAT1 << 32U);
+ break;
+
+ default:
+ /* Only 2 histogram instances are supported. */
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Initializes the WFE-A engine for waveform process.
+ *
+ * param base PXP peripheral base address.
+ * param ditherHandshake true to enable handshake mode with upstream dither store engine.
+ */
+void PXP_WfeaInit(PXP_Type *base, bool ditherHandshake)
+{
+ /* FETCH engine configuration, user fetch buffer1 for Y4 data buffer and buffer2 for working buffer. */
+ /* Enable buffer1&2 fetch. 2 bytes in each pixel for the buffer2.
+ Other default configurations: fetch data from external axi bus, normal(not hanshake or by pass) mode, burst
+ length 4, normal border pixels select(not sw reg mode), 1 line fetch, done IRQ disabled. */
+ base->WFA_FETCH_CTRL = PXP_WFA_FETCH_CTRL_BF1_EN(1UL) | PXP_WFA_FETCH_CTRL_BF2_EN(1UL) |
+ PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(1UL) |
+ PXP_WFA_FETCH_CTRL_BF1_HSK_MODE((uint32_t)ditherHandshake);
+ /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 0/3 */
+ /* Other default configurations: x/y offset=0, positive offset. */
+ base->WFA_ARRAY_PIXEL0_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(3UL);
+ /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 4/7 */
+ base->WFA_ARRAY_PIXEL1_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(4UL) |
+ PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(7UL);
+ /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 8/9 */
+ base->WFA_ARRAY_PIXEL2_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(8UL) |
+ PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(9UL);
+ /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 10/15 */
+ base->WFA_ARRAY_PIXEL3_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(10UL) |
+ PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(15UL);
+ /* Select pixel from bufer 1, set the right/left bit position on the original pixel as 4/7 */
+ base->WFA_ARRAY_PIXEL4_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(4UL) | PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(7UL);
+ /* Software define flag0=1, other flags 1~15 =0 */
+ base->WFA_ARRAY_REG2 = 1UL;
+
+ /* STORE engine configuration */
+ /* Channel 0 y4, channel 1 wb */
+ /* Enable channel 0, store data to memory, select low 32 bit shift out data to pack, enable combine 2 channel. */
+ /* Other default configurations: Arbitration disable(if using 2 channels, will output 2 axi bus sets), 8 bytes in a
+ burst, fill data mode disable, block mode disable. */
+ base->WFE_A_STORE_CTRL_CH0 = PXP_WFE_A_STORE_CTRL_CH0_CH_EN(1UL) | PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN(1UL) |
+ PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL(1UL) |
+ PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL(1UL);
+ /* Enable channel 1, store data to memory, select low 32 bit shift out data to pack, 16 bytes in a write burst. */
+ base->WFE_A_STORE_CTRL_CH1 = PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL) | PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(1UL) |
+ PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(1UL) | PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(1UL);
+ /* 8 Bpp, disable YUV planes, disable shift bypass. */
+ base->WFE_A_STORE_SHIFT_CTRL_CH0 = 0UL;
+ /* 16 Bpp, disable YUV planes, disable shift bypass. */
+ base->WFE_A_STORE_SHIFT_CTRL_CH1 = PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(1);
+ base->WFE_A_STORE_FILL_DATA_CH0 = 0UL;
+ /* 8 data masks, mask 0-7. Only use mask 0-4 */
+ /* mask 0: 0xF << 32; mask 1: 0xF00 << 28; mask 2: 0x0 << 24; mask 3: 0x3F00'0000 << 18; mask 4: 0xF'0000'0000 >> 28
+ */
+ base->WFE_A_STORE_D_MASK0_H_CH0 = 0UL;
+ base->WFE_A_STORE_D_MASK0_L_CH0 = PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0xfUL); /* fetch CP */
+ base->WFE_A_STORE_D_MASK1_H_CH0 = 0UL;
+ base->WFE_A_STORE_D_MASK1_L_CH0 = PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0xf00UL); /* fetch NP */
+ base->WFE_A_STORE_D_MASK2_H_CH0 = 0UL;
+ base->WFE_A_STORE_D_MASK2_L_CH0 = 0UL;
+ base->WFE_A_STORE_D_MASK3_H_CH0 = 0UL;
+ base->WFE_A_STORE_D_MASK3_L_CH0 = PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(0x3f000000UL); /* fetch LUT */
+ base->WFE_A_STORE_D_MASK4_H_CH0 = PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(0xfUL);
+ base->WFE_A_STORE_D_MASK4_L_CH0 = 0UL; /* fetch Y4 */
+ base->WFE_A_STORE_D_SHIFT_L_CH0 =
+ PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(32UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(1UL) |
+ PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(28UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1UL) |
+ PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(24UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(1UL) |
+ PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(18UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(1UL);
+ base->WFE_A_STORE_D_SHIFT_H_CH0 = PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(28UL);
+
+ /* 8 flag masks, mask 0-7. Only use mask 0-3 */
+ /* mask 0: 0x1 << 1; mask 1: 0x2 >> 1; mask 2: 0x4 << 38; mask 3: 0x8 << 38 */
+ /* Switch flag bit 0&1, bit 2&3 << 38 */
+ base->WFE_A_STORE_F_MASK_H_CH0 = 0UL;
+ base->WFE_A_STORE_F_MASK_L_CH0 =
+ PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0(0x1UL) | PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1(0x2UL) |
+ PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2(0x4UL) | PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3(0x8UL);
+ base->WFE_A_STORE_F_SHIFT_H_CH0 = 0UL;
+ base->WFE_A_STORE_F_SHIFT_L_CH0 =
+ PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(1UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1UL) |
+ PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(1UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0UL) |
+ PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(32UL + 6UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(1UL) |
+ PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(32UL + 6UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(1UL);
+
+ /* Enable and bypass the ALU process. */
+ base->ALU_A_INST_ENTRY = 0UL;
+ base->ALU_A_PARAM = 0UL;
+ base->ALU_A_CONFIG = 0UL;
+ base->ALU_A_LUT_CONFIG = 0UL;
+ base->ALU_A_LUT_DATA0 = 0UL;
+ base->ALU_A_LUT_DATA1 = 0UL;
+ base->ALU_A_CTRL = PXP_ALU_A_CTRL_BYPASS(1UL) | PXP_ALU_A_CTRL_ENABLE(1UL);
+
+ /* WFE A */
+ base->WFE_A_STAGE1_MUX0 = 0x3F3F0303UL;
+ base->WFE_A_STAGE1_MUX1 = 0x0C00000CUL;
+ base->WFE_A_STAGE1_MUX2 = 0x01040000UL;
+ base->WFE_A_STAGE1_MUX3 = 0x0A0A0904UL;
+ base->WFE_A_STAGE1_MUX4 = 0x00000B0BUL;
+ base->WFE_A_STAGE2_MUX0 = 0x1800280EUL;
+ base->WFE_A_STAGE2_MUX1 = 0x00280E01UL;
+ base->WFE_A_STAGE2_MUX2 = 0x280E0118UL;
+ base->WFE_A_STAGE2_MUX3 = 0x00011800UL;
+ base->WFE_A_STAGE2_MUX4 = 0UL;
+ base->WFE_A_STAGE2_MUX5 = 0x1800280EUL;
+ base->WFE_A_STAGE2_MUX6 = 0x00280E01UL;
+ base->WFE_A_STAGE2_MUX7 = 0x1A0E0118UL;
+ base->WFE_A_STAGE2_MUX8 = 0x1B012911UL;
+ base->WFE_A_STAGE2_MUX9 = 0x00002911UL;
+ base->WFE_A_STAGE2_MUX10 = 0UL;
+ base->WFE_A_STAGE2_MUX11 = 0UL;
+ base->WFE_A_STAGE2_MUX12 = 0UL;
+ base->WFE_A_STAGE3_MUX0 = 0x07060504UL;
+ base->WFE_A_STAGE3_MUX1 = 0x3F3F3F08UL;
+ base->WFE_A_STAGE3_MUX2 = 0x03020100UL;
+ base->WFE_A_STAGE3_MUX3 = 0x3F3F3F3FUL;
+
+ /* WFE_A_STG1_8X1_OUT0_0/1 is used to store LUT occupation status */
+ /* Set LUT64-255 to occupied since we only have 64 LUTs in EPDC */
+ base->WFE_A_STG1_8X1_OUT0_2 = 0xFFFFFFFFUL;
+ base->WFE_A_STG1_8X1_OUT0_3 = 0xFFFFFFFFUL;
+ base->WFE_A_STG1_8X1_OUT0_4 = 0xFFFFFFFFUL;
+ base->WFE_A_STG1_8X1_OUT0_5 = 0xFFFFFFFFUL;
+ base->WFE_A_STG1_8X1_OUT0_6 = 0xFFFFFFFFUL;
+ base->WFE_A_STG1_8X1_OUT0_7 = 0xFFFFFFFFUL;
+ /* OUT1.2.3 LUT0-255 */
+ base->WFE_A_STG1_8X1_OUT1_0 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_1 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_2 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_3 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_4 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_5 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_6 = 0UL;
+ base->WFE_A_STG1_8X1_OUT1_7 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_0 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_1 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_2 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_3 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_4 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_5 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_6 = 0UL;
+ base->WFE_A_STG1_8X1_OUT2_7 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_0 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_1 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_2 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_3 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_4 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_5 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_6 = 0UL;
+ base->WFE_A_STG1_8X1_OUT3_7 = 0UL;
+ /* LUTOUT0-31 for OUT0-3.
+ The 5x6 LUT output value for input value n. This output value determines which input to select (flag, data). */
+ base->WFE_A_STG2_5X6_OUT0_0 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_1 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_2 = 0x04050505UL;
+ base->WFE_A_STG2_5X6_OUT0_3 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_4 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_5 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_6 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT0_7 = 0x04040404UL;
+ base->WFE_A_STG2_5X6_OUT1_0 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_1 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_2 = 0x05080808UL;
+ base->WFE_A_STG2_5X6_OUT1_3 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_4 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_5 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_6 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT1_7 = 0x05050505UL;
+ base->WFE_A_STG2_5X6_OUT2_0 = 0x07070707UL;
+ base->WFE_A_STG2_5X6_OUT2_1 = 0x07070707UL;
+ base->WFE_A_STG2_5X6_OUT2_2 = 0x070C0C0CUL;
+ base->WFE_A_STG2_5X6_OUT2_3 = 0x07070707UL;
+ base->WFE_A_STG2_5X6_OUT2_4 = 0X0F0F0F0FUL;
+ base->WFE_A_STG2_5X6_OUT2_5 = 0X0F0F0F0FUL;
+ base->WFE_A_STG2_5X6_OUT2_6 = 0X0F0F0F0FUL;
+ base->WFE_A_STG2_5X6_OUT2_7 = 0X0F0F0F0FUL;
+ base->WFE_A_STG2_5X6_OUT3_0 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_1 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_2 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_3 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_4 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_5 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_6 = 0UL;
+ base->WFE_A_STG2_5X6_OUT3_7 = 0UL;
+ /* MASK0-3, 5 bits each mask.
+ Each set mask bit enables one of the corresponding flag input bits. There is one mask per 5x6 LUT. */
+ base->WFE_A_STAGE2_5X6_MASKS_0 = 0x001F1F1FUL;
+ /* MUXADDR 0-3, 6 bits each.
+ Each Address specifies the MUX position in the MUX array. There is one MUXADDR per 5x6 LUT.*/
+ base->WFE_A_STAGE2_5X6_ADDR_0 = 0x3f030100UL;
+ /* Flag of LUTOUT0-31 for OUT0-3.
+ The 5x1 LUT output value for input value n. This output value results in a flag that is added to the flag array.
+ */
+ base->WFE_A_STG2_5X1_OUT0 = 0x00000700UL;
+ base->WFE_A_STG2_5X1_OUT1 = 0x00007000UL;
+ base->WFE_A_STG2_5X1_OUT2 = 0x0000A000UL;
+ base->WFE_A_STG2_5X1_OUT3 = 0x000000C0UL;
+ /* MASK0-3, 5 bits each mask.
+ Each set mask bit enables one of the corresponding flag input bits. There is one mask per 5x1 LUT. */
+ base->WFE_A_STG2_5X1_MASKS = 0x071F1F1FUL;
+}
+
+/*!
+ * brief Configure the WFE-A engine
+ *
+ * param base PXP peripheral base address.
+ * param config pointer to the configuration structure.
+ */
+void PXP_SetWfeaConfig(PXP_Type *base, const pxp_wfea_engine_config_t *config)
+{
+ /* Fetch */
+ base->WFA_FETCH_BUF1_ADDR = config->y4Addr;
+ base->WFA_FETCH_BUF1_PITCH = config->updatePitch;
+ base->WFA_FETCH_BUF1_SIZE = PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight - 1UL) |
+ PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH((uint32_t)config->updateWidth - 1UL);
+ base->WFA_FETCH_BUF1_CORD = 0UL;
+ base->WFA_FETCH_BUF2_ADDR = config->wbAddr;
+ base->WFA_FETCH_BUF2_PITCH = (uint32_t)config->resX * 2U; /* 2 bytes per pixel */
+ base->WFA_FETCH_BUF2_SIZE = PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight - 1UL) |
+ PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH((uint32_t)config->updateWidth - 1UL);
+ base->WFA_FETCH_BUF2_CORD =
+ PXP_WFA_FETCH_BUF2_CORD_YCORD((uint32_t)config->ulcY) | PXP_WFA_FETCH_BUF2_CORD_XCORD((uint32_t)config->ulcX);
+
+ /* Store */
+ base->WFE_A_STORE_SIZE_CH0 = PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->updateWidth - 1UL) |
+ PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->updateHeight - 1UL);
+ base->WFE_A_STORE_SIZE_CH1 = PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->updateWidth - 1UL) |
+ PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->updateHeight - 1UL);
+ /* Channel 1: 2 byte per pixel. */
+ base->WFE_A_STORE_PITCH = PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH((uint32_t)config->resX) |
+ PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH((uint32_t)config->resX * 2U);
+ base->WFE_A_STORE_ADDR_0_CH0 = PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(config->y4cAddr);
+ base->WFE_A_STORE_ADDR_1_CH0 = 0U;
+ /* Channel 1: 2 bytes per pixel. */
+ base->WFE_A_STORE_ADDR_0_CH1 = PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(
+ (uint32_t)config->wbAddr + ((uint32_t)config->ulcX + (uint32_t)config->ulcY * (uint32_t)config->resX) * 2UL);
+ base->WFE_A_STORE_ADDR_1_CH1 = 0U;
+
+ /* ALU */
+ base->ALU_A_BUF_SIZE = PXP_ALU_A_BUF_SIZE_BUF_WIDTH((uint32_t)config->updateWidth) |
+ PXP_ALU_A_BUF_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight);
+
+ /* WFE */
+ /* Height and width of the updete region */
+ base->WFE_A_DIMENSIONS =
+ PXP_WFE_A_DIMENSIONS_WIDTH(config->updateWidth) | PXP_WFE_A_DIMENSIONS_HEIGHT(config->updateHeight);
+ /* The distance from the frame origin to the update region origin in the X/Y direction. */
+ base->WFE_A_OFFSET = PXP_WFE_A_OFFSET_X_OFFSET(config->ulcX) | PXP_WFE_A_OFFSET_Y_OFFSET(config->ulcY);
+ /* val3,val2=0, val1=F, val0=lutNum */
+ base->WFE_A_SW_DATA_REGS = (config->lutNum & 0x000000FFUL) | 0x00000F00UL;
+ /* val3,val2=0, val1=0(disable reagl/-d), val0=partial(1)full(0) */
+ base->WFE_A_SW_FLAG_REGS = ((uint32_t)(!config->fullUpdateEnable) | (0U << 1U));
+ /* Enable and reset WFE-A state. Disable register of ALU inside waveform as default. */
+ base->WFE_A_CTRL = PXP_WFE_A_CTRL_ENABLE(1UL) | PXP_WFE_A_CTRL_SW_RESET(1UL);
+
+ if (config->alphaEnable)
+ {
+ base->WFA_ARRAY_FLAG0_MASK = 0U;
+ }
+ else
+ {
+ base->WFA_ARRAY_FLAG0_MASK = PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL(2UL);
+ }
+
+ /* disable CH1 when only doing detection */
+ if (config->detectionOnly)
+ {
+ base->WFE_A_STORE_CTRL_CH1 &= ~PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL);
+ }
+ else
+ {
+ base->WFE_A_STORE_CTRL_CH1 |= PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL);
+ }
+ /* Enable engine */
+ base->CTRL_SET = PXP_CTRL_ENABLE_WFE_A(1UL);
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+#if PXP_USE_PATH
+/*!
+ * brief Sets the path for one of the MUX
+ *
+ * param base PXP peripheral base address.
+ * param path the path configuration for one of the mux.
+ */
+void PXP_SetPath(PXP_Type *base, pxp_path_t path)
+{
+ volatile uint32_t *pathReg;
+ uint32_t mux = PXP_GET_MUX_FROM_PATH((uint32_t)path);
+ uint32_t sel = PXP_GET_SEL_FROM_PATH((uint32_t)path);
+
+ if (mux > 15U)
+ {
+ pathReg = &(base->DATA_PATH_CTRL1);
+ mux -= 15U;
+ }
+ else
+ {
+ pathReg = &(base->DATA_PATH_CTRL0);
+ }
+
+ /* Convert mux to the register shift. */
+ mux *= 2U;
+ *pathReg = (*pathReg & ~(3UL << mux)) | (sel << mux);
+}
+#endif /* PXP_USE_PATH */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.h b/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.h
new file mode 100644
index 0000000000..69fabf7836
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pxp/fsl_pxp.h
@@ -0,0 +1,2712 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_PXP_H_
+#define _FSL_PXP_H_
+
+#include "fsl_common.h"
+
+/* Compatibility macro map. */
+#if defined(PXP_AS_CTRL_ALPHA_INVERT_MASK) && (!defined(PXP_AS_CTRL_ALPHA0_INVERT_MASK))
+#define PXP_AS_CTRL_ALPHA0_INVERT_MASK PXP_AS_CTRL_ALPHA_INVERT_MASK
+#endif
+
+#if defined(PXP_AS_CTRL_ALPHA_INVERT_MASK) && (!defined(PXP_AS_CTRL_ALPHA_INVERT_MASK))
+#define PXP_AS_CTRL_ALPHA0_INVERT_MASK PXP_AS_CTRL_ALPHA_INVERT_MASK
+#endif
+
+#if defined(PXP_STAT_IRQ_MASK) && (!defined(PXP_STAT_IRQ0_MASK))
+#define PXP_STAT_IRQ0_MASK PXP_STAT_IRQ_MASK
+#endif
+
+#if defined(PXP_STAT_AXI_READ_ERROR_MASK) && (!defined(PXP_STAT_AXI_READ_ERROR_0_MASK))
+#define PXP_STAT_AXI_READ_ERROR_0_MASK PXP_STAT_AXI_READ_ERROR_MASK
+#endif
+
+#if defined(PXP_STAT_AXI_WRITE_ERROR_MASK) && (!defined(PXP_STAT_AXI_WRITE_ERROR_0_MASK))
+#define PXP_STAT_AXI_WRITE_ERROR_0_MASK PXP_STAT_AXI_WRITE_ERROR_MASK
+#endif
+
+/*!
+ * @addtogroup pxp_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* PXP global LUT table is 16K. */
+#define PXP_LUT_TABLE_BYTE (16UL * 1024UL)
+/* Intenral memory for LUT, the size is 256 bytes. */
+#define PXP_INTERNAL_RAM_LUT_BYTE (256)
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PXP_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/* This macto indicates whether the rotate sub module is shared by process surface and output buffer. */
+#if defined(PXP_CTRL_ROT_POS_MASK)
+#define PXP_SHARE_ROTATE 1
+#else
+#define PXP_SHARE_ROTATE 0
+#endif
+
+/* This macto indicates whether PXP needs mux the process path. */
+#if defined(PXP_DATA_PATH_CTRL0_MUX0_SEL_MASK)
+#define PXP_USE_PATH 1
+#else
+#define PXP_USE_PATH 0
+#endif
+
+#if PXP_USE_PATH
+#define PXP_PATH(mux, sel) (((mux) << 8U) | (sel))
+#define PXP_GET_MUX_FROM_PATH(path) ((path) >> 8U)
+#define PXP_GET_SEL_FROM_PATH(path) ((path)&0x03U)
+#endif /* PXP_USE_PATH */
+
+/*! @brief PXP interrupts to enable. */
+enum _pxp_interrupt_enable
+{
+ kPXP_CompleteInterruptEnable = PXP_CTRL_IRQ_ENABLE_MASK, /*!< PXP process completed. bit 1 */
+ kPXP_CommandLoadInterruptEnable = PXP_CTRL_NEXT_IRQ_ENABLE_MASK, /*!< Interrupt to show that the command set by @ref
+ PXP_SetNextCommand has been loaded. bit 2 */
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+ kPXP_LutDmaLoadInterruptEnable =
+ PXP_CTRL_LUT_DMA_IRQ_ENABLE_MASK, /*!< The LUT table has been loaded by DMA. bit 3 */
+#endif
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ kPXP_CompressDoneInterruptEnable =
+ PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN_MASK >> 16U, /*!< Compress done interrupt enable. bit 15 */
+ kPXP_InputFetchCh0InterruptEnable = PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN_MASK
+ << 16U, /*!< Input fetch channel 0 completed. bit 16 */
+ kPXP_InputFetchCh1InterruptEnable = PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN_MASK
+ << 16U, /*!< Input fetch channel 1 completed. bit 17 */
+ kPXP_InputStoreCh0InterruptEnable = PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN_MASK
+ << 16U, /*!< Input store channel 0 completed. bit 18 */
+ kPXP_InputStoreCh1InterruptEnable = PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN_MASK
+ << 16U, /*!< Input store channel 1 completed. bit 19 */
+ kPXP_DitherFetchCh0InterruptEnable = PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN_MASK
+ << 16U, /*!< Dither fetch channel 0 completed. bit 20 */
+ kPXP_DitherFetchCh1InterruptEnable = PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN_MASK
+ << 16U, /*!< Dither fetch channel 1 completed. bit 21 */
+ kPXP_DitherStoreCh0InterruptEnable = PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN_MASK
+ << 16U, /*!< Dither store channle 0 completed. bit 22 */
+ kPXP_DitherStoreCh1InterruptEnable = PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN_MASK
+ << 16U, /*!< Dither store channle 1 completed. bit 23 */
+ kPXP_WfeaStoreCh0InterruptEnable = PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN_MASK
+ << 16U, /*!< WFE-A store channel 0 completed. bit 24 */
+ kPXP_WfeaStoreCh1InterruptEnable = PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN_MASK
+ << 16U, /*!< WFE-A store channel 1 completed. bit 25 */
+ kPXP_WfebStoreCh0InterruptEnable = PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN_MASK
+ << 16U, /*!< WFE-B store channel 0 completed. bit 26 */
+ kPXP_WfebStoreCh1InterruptEnable = PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN_MASK
+ << 16U, /*!< WFE-B store channel 1 completed. bit 27 */
+ kPXP_InputStoreInterruptEnable = PXP_IRQ_MASK_FIRST_STORE_IRQ_EN_MASK << 16U, /*!< Input store completed. bit 28 */
+ kPXP_DitherStoreInterruptEnable = PXP_IRQ_MASK_DITHER_STORE_IRQ_EN_MASK
+ << 16U, /*!< Dither store completed. bit 29 */
+ kPXP_WfeaStoreInterruptEnable = PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN_MASK << 16U, /*!< WFE-A store completed. bit 30 */
+ kPXP_WfebStoreInterruptEnable = PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN_MASK << 16U, /*!< WFE-B store completed. bit 31 */
+#endif /* FSL_FEATURE_PXP_V3 */
+};
+
+/*!
+ * @brief PXP status flags.
+ *
+ * @note These enumerations are meant to be OR'd together to form a bit mask.
+ */
+enum _pxp_flags
+{
+ kPXP_CompleteFlag = PXP_STAT_IRQ0_MASK, /*!< PXP process completed. bit 0 */
+ kPXP_Axi0WriteErrorFlag = PXP_STAT_AXI_WRITE_ERROR_0_MASK, /*!< PXP encountered an AXI write error and processing
+ has been terminated. bit 1*/
+ kPXP_Axi0ReadErrorFlag = PXP_STAT_AXI_READ_ERROR_0_MASK, /*!< PXP encountered an AXI read error and processing has
+ been terminated. bit 2 */
+ kPXP_CommandLoadFlag = PXP_STAT_NEXT_IRQ_MASK, /*!< The command set by @ref PXP_SetNextCommand has been loaded,
+ could set new command. bit 3 */
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+ kPXP_LutDmaLoadFlag = PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK, /*!< The LUT table has been loaded by DMA. bit 8 */
+#endif
+#if defined(PXP_STAT_AXI_READ_ERROR_1_MASK)
+ kPXP_Axi1WriteErrorFlag = PXP_STAT_AXI_WRITE_ERROR_1_MASK, /*!< PXP encountered an AXI write error and processing
+ has been terminated. bit 9 */
+ kPXP_Axi1ReadErrorFlag = PXP_STAT_AXI_READ_ERROR_1_MASK, /*!< PXP encountered an AXI read error and processing has
+ been terminated. bit 10 */
+#endif
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ kPXP_CompressDoneFlag = PXP_IRQ_COMPRESS_DONE_IRQ_MASK >> 16U, /*!< Compress done. bit 15 */
+ kPXP_InputFetchCh0CompleteFlag = PXP_IRQ_FIRST_CH0_PREFETCH_IRQ_MASK
+ << 16U, /*!< Input fetch channel 0 completed. bit 16 */
+ kPXP_InputFetchCh1CompleteFlag = PXP_IRQ_FIRST_CH1_PREFETCH_IRQ_MASK
+ << 16U, /*!< Input fetch channel 1 completed. bit 17 */
+ kPXP_InputStoreCh0CompleteFlag = PXP_IRQ_FIRST_CH0_STORE_IRQ_MASK
+ << 16U, /*!< Input store channel 0 completed. bit 18 */
+ kPXP_InputStoreCh1CompleteFlag = PXP_IRQ_FIRST_CH1_STORE_IRQ_MASK
+ << 16U, /*!< Input store channel 1 completed. bit 19 */
+ kPXP_DitherFetchCh0CompleteFlag = PXP_IRQ_DITHER_CH0_PREFETCH_IRQ_MASK
+ << 16U, /*!< Dither fetch channel 0 completed. bit 20 */
+ kPXP_DitherFetchCh1CompleteFlag = PXP_IRQ_DITHER_CH1_PREFETCH_IRQ_MASK
+ << 16U, /*!< Dither fetch channel 1 completed. bit 21 */
+ kPXP_DitherStoreCh0CompleteFlag = PXP_IRQ_DITHER_CH0_STORE_IRQ_MASK
+ << 16U, /*!< Dither store channel 0 completed. bit 22 */
+ kPXP_DitherStoreCh1CompleteFlag = PXP_IRQ_DITHER_CH1_STORE_IRQ_MASK
+ << 16U, /*!< Dither store channel 1 completed. bit 23 */
+ kPXP_WfeaStoreCh0CompleteFlag = PXP_IRQ_WFE_A_CH0_STORE_IRQ_MASK
+ << 16U, /*!< WFE-A store channel 0 completed. bit 24 */
+ kPXP_WfeaStoreCh1CompleteFlag = PXP_IRQ_WFE_A_CH1_STORE_IRQ_MASK
+ << 16U, /*!< WFE-A store channel 1 completed. bit 25 */
+ kPXP_WfebStoreCh0CompleteFlag = PXP_IRQ_WFE_B_CH0_STORE_IRQ_MASK
+ << 16U, /*!< WFE-B store channel 0 completed. bit 26 */
+ kPXP_WfebStoreCh1CompleteFlag = PXP_IRQ_WFE_B_CH1_STORE_IRQ_MASK
+ << 16U, /*!< WFE-B store channel 1 completed. bit 27 */
+ kPXP_InputStoreCompleteFlag = PXP_IRQ_FIRST_STORE_IRQ_MASK << 16U, /*!< Input store completed. bit 28 */
+ kPXP_DitherStoreCompleteFlag = PXP_IRQ_DITHER_STORE_IRQ_MASK << 16U, /*!< Dither store completed. bit 29 */
+ kPXP_WfeaStoreCompleteFlag = PXP_IRQ_WFE_A_STORE_IRQ_MASK << 16U, /*!< WFE-A store completed. bit 30 */
+ kPXP_WfebStoreCompleteFlag = PXP_IRQ_WFE_B_STORE_IRQ_MASK << 16U, /*!< WFE-B store completed. bit 31 */
+#endif /* FSL_FEATURE_PXP_V3 */
+};
+
+#if PXP_USE_PATH
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+typedef enum _pxp_path
+{
+ kPXP_Mux0SelectProcessSurfaceEngine = PXP_PATH(0U, 0U), /*!< MUX0 select Process Surface engine. */
+ kPXP_Mux0SelectInputFetchEngineChannel0 = PXP_PATH(0U, 1U), /*!< MUX0 select input Fetch engine channel 0. */
+ kPXP_Mux0SelectInputFetchEngineChannel1 = PXP_PATH(0U, 2U), /*!< MUX0 select input Fetch engine channel 1. */
+ kPXP_Mux0SelectNone = PXP_PATH(0U, 3U), /*!< MUX0 select no output. */
+ kPXP_Mux1SelectInputFetchEngineChannel0 = PXP_PATH(1U, 0U), /*!< MUX1 select input Fetch engine channel 0. */
+ kPXP_Mux1SelectRotation1Engine = PXP_PATH(1U, 1U), /*!< MUX1 select Rotation1 engine output. */
+ kPXP_Mux1SelectNone = PXP_PATH(1U, 2U), /*!< MUX1 select no output. */
+ kPXP_Mux2SelectInputFetchEngineChannel1 = PXP_PATH(2U, 0U), /*!< MUX2 select input Fetch engine channel 1. */
+ kPXP_Mux2SelectRotation1Engine = PXP_PATH(2U, 1U), /*!< MUX2 select Rotation1 engine output. */
+ kPXP_Mux2SelectNone = PXP_PATH(2U, 2U), /*!< MUX2 select no output. */
+ kPXP_Mux3SelectCsc1Engine = PXP_PATH(3U, 0U), /*!< MUX3 select output of CSC1 engine. */
+ kPXP_Mux3SelectRotation1Engine = PXP_PATH(3U, 1U), /*!< MUX3 select output of Rotation1 engine. */
+ kPXP_Mux3SelectNone = PXP_PATH(3U, 2U), /*!< MUX3 select no output. */
+ kPXP_Mux5SelectMux1 = PXP_PATH(5U, 0U), /*!< MUX5 select output of MUX1. */
+ kPXP_Mux5SelectAlphaBlending1 = PXP_PATH(5U, 1U), /*!< MUX5 select output of alpha blending / color key 1. */
+ kPXP_Mux5SelectNone = PXP_PATH(5U, 2U), /*!< MUX5 select no output. */
+ kPXP_Mux6SelectAlphaBlending1 = PXP_PATH(6U, 0U), /*!< MUX6 select output of alpha blending / color key 1. */
+ kPXP_Mux6SelectAlphaBlending0 = PXP_PATH(6U, 1U), /*!< MUX6 select output of alpha blending / color key 0. */
+ kPXP_Mux6SelectNone = PXP_PATH(6U, 2U), /*!< MUX6 select no output. */
+ kPXP_Mux7SelectMux5 = PXP_PATH(7U, 0U), /*!< MUX7 select output of MUX5. */
+ kPXP_Mux7SelectCsc2Engine = PXP_PATH(7U, 1U), /*!< MUX7 select output of CSC2 engine. */
+ kPXP_Mux7SelectNone = PXP_PATH(7U, 2U), /*!< MUX7 select no output. */
+ kPXP_Mux8SelectCsc2Engine = PXP_PATH(8U, 0U), /*!< MUX8 select output of CSC2 engine. */
+ kPXP_Mux8SelectAlphaBlending0 = PXP_PATH(8U, 1U), /*!< MUX8 select output of alpha blending / color key 0. */
+ kPXP_Mux8SelectNone = PXP_PATH(8U, 2U), /*!< MUX8 select no output. */
+ kPXP_Mux9SelectMux7 = PXP_PATH(9U, 0U), /*!< MUX9 select output of MUX7. */
+ kPXP_Mux9SelectMux8 = PXP_PATH(9U, 1U), /*!< MUX9 select output of MUX8. */
+ kPXP_Mux9SelectNone = PXP_PATH(9U, 2U), /*!< MUX9 select no output. */
+ kPXP_Mux10SelectMux7 = PXP_PATH(10U, 0U), /*!< MUX10 select output of MUX7. */
+ kPXP_Mux10SelectLut = PXP_PATH(10U, 1U), /*!< MUX10 select output of LUT. */
+ kPXP_Mux10SelectNone = PXP_PATH(10U, 2U), /*!< MUX10 select no output. */
+ kPXP_Mux11SelectLut = PXP_PATH(11U, 0U), /*!< MUX11 select output of LUT. */
+ kPXP_Mux11SelectMux8 = PXP_PATH(11U, 1U), /*!< MUX11 select output of MUX8. */
+ kPXP_Mux11SelectNone = PXP_PATH(11U, 2U), /*!< MUX11 select no output. */
+ kPXP_Mux12SelectMux10 = PXP_PATH(12U, 0U), /*!< MUX12 select output of MUX10. */
+ kPXP_Mux12SelectMux11 = PXP_PATH(12U, 1U), /*!< MUX12 select output of MUX11. */
+ kPXP_Mux12SelectNone = PXP_PATH(12U, 2U), /*!< MUX12 select no output. */
+ kPXP_Mux13SelectNone = PXP_PATH(13U, 0U), /*!< MUX13 select no output. */
+ kPXP_Mux13SelectFetchEngineChannel1 = PXP_PATH(13U, 1U), /*!< MUX13 select input Fetch engine channel 1. */
+ kPXP_Mux14SelectRotation0Engine = PXP_PATH(14U, 0U), /*!< MUX14 select output of Rotation0 engine. */
+ kPXP_Mux14SelectMux11 = PXP_PATH(14U, 1U), /*!< MUX14 select output of MUX11. */
+ kPXP_Mux14SelectNone = PXP_PATH(14U, 2U), /*!< MUX14 select no output. */
+ kPXP_Mux15SelectFetchEngineChannel0 = PXP_PATH(15U, 0U), /*!< MUX15 select input Fetch engine channel 0. */
+ kPXP_Mux15SelectMux10 = PXP_PATH(15U, 1U), /*!< MUX15 select output of MUX10. */
+ kPXP_Mux15SelectNone = PXP_PATH(15U, 2U), /*!< MUX15 select no output. */
+ kPXP_Mux16SelectAluA = PXP_PATH(16U, 0U), /*!< MUX16 select output of ALU A. */
+ kPXP_Mux16SelectOutput = PXP_PATH(16U, 1U), /*!< MUX16 select output of legacy output. */
+ kPXP_Mux16SelectAluB = PXP_PATH(16U, 2U), /*!< MUX16 select output of ALU B. */
+ kPXP_Mux16SelectNone = PXP_PATH(16U, 3U), /*!< MUX16 select no output. */
+ kPXP_Mux17SelectAluA = PXP_PATH(17U, 0U), /*!< MUX17 select output of ALU A. */
+ kPXP_Mux17SelectAluB = PXP_PATH(17U, 1U), /*!< MUX17 select output of ALU B. */
+ kPXP_Mux17SelectNone = PXP_PATH(17U, 2U), /*!< MUX17 select no output. */
+} pxp_path_t;
+#else
+typedef enum _pxp_path
+{
+ kPXP_Mux0SelectFetchDataArray = PXP_PATH(0U, 0U), /*!< MUX0 select Fetch Data Array. */
+ kPXP_Mux0SelectAlu = PXP_PATH(0U, 1U), /*!< MUX0 select output of ALU. */
+ kPXP_Mux0SelectNone = PXP_PATH(0U, 2U), /*!< MUX0 select no output. */
+ kPXP_Mux1SelectLut = PXP_PATH(1U, 0U), /*!< MUX1 select output of LUT. */
+ kPXP_Mux1SelectMux0 = PXP_PATH(1U, 1U), /*!< MUX1 select output of MUX0. */
+ kPXP_Mux1SelectNone = PXP_PATH(1U, 2U), /*!< MUX1 select no output. */
+ kPXP_Mux3SelectRotation1Engine = PXP_PATH(3U, 0U), /*!< MUX3 select output of Rotation1 engine. */
+ kPXP_Mux3SelectCsc1Engine = PXP_PATH(3U, 1U), /*!< MUX3 select output of CSC1 engine. */
+ kPXP_Mux3SelectNone = PXP_PATH(3U, 2U), /*!< MUX3 select no output. */
+ kPXP_Mux8SelectCsc2Engine = PXP_PATH(8U, 0U), /*!< MUX8 select output of CSC2 engine. */
+ kPXP_Mux8SelectAlphaBlending0 = PXP_PATH(8U, 1U), /*!< MUX8 select output of alpha blending / color key 0. */
+ kPXP_Mux8SelectNone = PXP_PATH(8U, 2U), /*!< MUX8 select no output. */
+ kPXP_Mux9SelectMux0 = PXP_PATH(9U, 0U), /*!< MUX9 select output of MUX0. */
+ kPXP_Mux9SelectMux8 = PXP_PATH(9U, 1U), /*!< MUX9 select output of MUX8. */
+ kPXP_Mux9SelectNone = PXP_PATH(9U, 2U), /*!< MUX9 select no output. */
+ kPXP_Mux11SelectLut = PXP_PATH(11U, 0U), /*!< MUX11 select output of LUT. */
+ kPXP_Mux11SelectMux8 = PXP_PATH(11U, 1U), /*!< MUX11 select output of MUX8. */
+ kPXP_Mux11SelectNone = PXP_PATH(11U, 2U), /*!< MUX11 select no output. */
+ kPXP_Mux12SelectRotation0Engine = PXP_PATH(12U, 0U), /*!< MUX12 select output of Rotation0 engine. */
+ kPXP_Mux12SelectMux11 = PXP_PATH(12U, 1U), /*!< MUX12 select output of MUX11. */
+ kPXP_Mux12SelectNone = PXP_PATH(12U, 2U), /*!< MUX12 select no output. */
+ kPXP_Mux14SelectDitherEngine = PXP_PATH(14U, 0U), /*!< MUX14 select output of Dither engine. */
+ kPXP_Mux14SelectMux12 = PXP_PATH(14U, 1U), /*!< MUX14 select output of MUX12. */
+ kPXP_Mux14SelectNone = PXP_PATH(14U, 2U), /*!< MUX14 select no output. */
+ kPXP_Mux16SelectOutputBuffer = PXP_PATH(16U, 0U), /*!< MUX16 select output of output buffer. */
+ kPXP_Mux16SelectStoreEngine = PXP_PATH(16U, 1U), /*!< MUX16 select output of store engine. */
+ kPXP_Mux16SelectNone = PXP_PATH(16U, 2U), /*!< MUX16 select no output. */
+ kPXP_Mux17SelectOutputBuffer = PXP_PATH(17U, 0U), /*!< MUX17 select output of output buffer. */
+ kPXP_Mux17SelectStoreEngine = PXP_PATH(17U, 1U), /*!< MUX17 select output of store engine. */
+ kPXP_Mux17SelectNone = PXP_PATH(17U, 2U), /*!< MUX17 select no output. */
+} pxp_path_t;
+#endif /* FSL_FEATURE_PXP_V3 */
+#endif /* PXP_USE_PATH */
+
+/*! @brief PXP output flip mode. */
+typedef enum _pxp_flip_mode
+{
+ kPXP_FlipDisable = 0U, /*!< Flip disable. */
+ kPXP_FlipHorizontal = 0x01U, /*!< Horizontal flip. */
+ kPXP_FlipVertical = 0x02U, /*!< Vertical flip. */
+ kPXP_FlipBoth = 0x03U, /*!< Flip both directions. */
+} pxp_flip_mode_t;
+
+/*! @brief PXP rotate mode. */
+typedef enum _pxp_rotate_position
+{
+ kPXP_RotateOutputBuffer = 0U, /*!< Rotate the output buffer. */
+ kPXP_RotateProcessSurface, /*!< Rotate the process surface. */
+} pxp_rotate_position_t;
+
+/*! @brief PXP rotate degree. */
+typedef enum _pxp_rotate_degree
+{
+ kPXP_Rotate0 = 0U, /*!< Clock wise rotate 0 deg. */
+ kPXP_Rotate90, /*!< Clock wise rotate 90 deg. */
+ kPXP_Rotate180, /*!< Clock wise rotate 180 deg. */
+ kPXP_Rotate270, /*!< Clock wise rotate 270 deg. */
+} pxp_rotate_degree_t;
+
+/*! @brief PXP interlaced output mode. */
+typedef enum _pxp_interlaced_output_mode
+{
+ kPXP_OutputProgressive = 0U, /*!< All data written in progressive format to output buffer 0. */
+ kPXP_OutputField0, /*!< Only write field 0 data to output buffer 0. */
+ kPXP_OutputField1, /*!< Only write field 1 data to output buffer 0. */
+ kPXP_OutputInterlaced, /*!< Field 0 write to buffer 0, field 1 write to buffer 1. */
+} pxp_interlaced_output_mode_t;
+
+/*! @brief PXP output buffer format. */
+typedef enum _pxp_output_pixel_format
+{
+ kPXP_OutputPixelFormatARGB8888 = 0x0, /*!< 32-bit pixels with alpha. */
+ kPXP_OutputPixelFormatRGB888 = 0x4, /*!< 32-bit pixels without alpha (unpacked 24-bit format) */
+ kPXP_OutputPixelFormatRGB888P = 0x5, /*!< 24-bit pixels without alpha (packed 24-bit format) */
+ kPXP_OutputPixelFormatARGB1555 = 0x8, /*!< 16-bit pixels with alpha. */
+ kPXP_OutputPixelFormatARGB4444 = 0x9, /*!< 16-bit pixels with alpha. */
+ kPXP_OutputPixelFormatRGB555 = 0xC, /*!< 16-bit pixels without alpha. */
+ kPXP_OutputPixelFormatRGB444 = 0xD, /*!< 16-bit pixels without alpha. */
+ kPXP_OutputPixelFormatRGB565 = 0xE, /*!< 16-bit pixels without alpha. */
+ kPXP_OutputPixelFormatYUV1P444 = 0x10, /*!< 32-bit pixels (1-plane XYUV unpacked). */
+ kPXP_OutputPixelFormatUYVY1P422 = 0x12, /*!< 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
+ kPXP_OutputPixelFormatVYUY1P422 = 0x13, /*!< 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
+ kPXP_OutputPixelFormatY8 = 0x14, /*!< 8-bit monochrome pixels (1-plane Y luma output) */
+ kPXP_OutputPixelFormatY4 = 0x15, /*!< 4-bit monochrome pixels (1-plane Y luma, 4 bit truncation) */
+ kPXP_OutputPixelFormatYUV2P422 = 0x18, /*!< 16-bit pixels (2-plane UV interleaved bytes) */
+ kPXP_OutputPixelFormatYUV2P420 = 0x19, /*!< 16-bit pixels (2-plane UV) */
+ kPXP_OutputPixelFormatYVU2P422 = 0x1A, /*!< 16-bit pixels (2-plane VU interleaved bytes) */
+ kPXP_OutputPixelFormatYVU2P420 = 0x1B, /*!< 16-bit pixels (2-plane VU) */
+} pxp_output_pixel_format_t;
+
+/*! @brief PXP output buffer configuration. */
+typedef struct _pxp_output_buffer_config
+{
+ pxp_output_pixel_format_t pixelFormat; /*!< Output buffer pixel format. */
+ pxp_interlaced_output_mode_t interlacedMode; /*!< Interlaced output mode. */
+ uint32_t buffer0Addr; /*!< Output buffer 0 address. */
+ uint32_t buffer1Addr; /*!< Output buffer 1 address, used for UV data in YUV 2-plane mode, or
+ field 1 in output interlaced mode. */
+ uint16_t pitchBytes; /*!< Number of bytes between two vertically adjacent pixels. */
+ uint16_t width; /*!< Pixels per line. */
+ uint16_t height; /*!< How many lines in output buffer. */
+} pxp_output_buffer_config_t;
+
+/*! @brief PXP process surface buffer pixel format. */
+typedef enum _pxp_ps_pixel_format
+{
+ kPXP_PsPixelFormatRGB888 = 0x4, /*!< 32-bit pixels without alpha (unpacked 24-bit format) */
+ kPXP_PsPixelFormatRGB555 = 0xC, /*!< 16-bit pixels without alpha. */
+ kPXP_PsPixelFormatRGB444 = 0xD, /*!< 16-bit pixels without alpha. */
+ kPXP_PsPixelFormatRGB565 = 0xE, /*!< 16-bit pixels without alpha. */
+ kPXP_PsPixelFormatYUV1P444 = 0x10, /*!< 32-bit pixels (1-plane XYUV unpacked). */
+ kPXP_PsPixelFormatUYVY1P422 = 0x12, /*!< 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
+ kPXP_PsPixelFormatVYUY1P422 = 0x13, /*!< 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
+ kPXP_PsPixelFormatY8 = 0x14, /*!< 8-bit monochrome pixels (1-plane Y luma output) */
+ kPXP_PsPixelFormatY4 = 0x15, /*!< 4-bit monochrome pixels (1-plane Y luma, 4 bit truncation) */
+ kPXP_PsPixelFormatYUV2P422 = 0x18, /*!< 16-bit pixels (2-plane UV interleaved bytes) */
+ kPXP_PsPixelFormatYUV2P420 = 0x19, /*!< 16-bit pixels (2-plane UV) */
+ kPXP_PsPixelFormatYVU2P422 = 0x1A, /*!< 16-bit pixels (2-plane VU interleaved bytes) */
+ kPXP_PsPixelFormatYVU2P420 = 0x1B, /*!< 16-bit pixels (2-plane VU) */
+ kPXP_PsPixelFormatYVU422 = 0x1E, /*!< 16-bit pixels (3-plane) */
+ kPXP_PsPixelFormatYVU420 = 0x1F, /*!< 16-bit pixels (3-plane) */
+} pxp_ps_pixel_format_t;
+
+/*! @brief PXP process surface buffer YUV format. */
+typedef enum _pxp_ps_yuv_format
+{
+ kPXP_PsYUVFormatYUV = 0U, /*!< YUV format. */
+ kPXP_PsYUVFormatYCbCr, /*!< YCbCr format. */
+} pxp_ps_yuv_format_t;
+
+/*! @brief PXP process surface buffer configuration. */
+typedef struct _pxp_ps_buffer_config
+{
+ pxp_ps_pixel_format_t pixelFormat; /*!< PS buffer pixel format. */
+ bool swapByte; /*!< For each 16 bit word, set true to swap the two bytes. */
+ uint32_t bufferAddr; /*!< Input buffer address for the first panel. */
+ uint32_t bufferAddrU; /*!< Input buffer address for the second panel. */
+ uint32_t bufferAddrV; /*!< Input buffer address for the third panel. */
+ uint16_t pitchBytes; /*!< Number of bytes between two vertically adjacent pixels. */
+} pxp_ps_buffer_config_t;
+
+/*! @brief PXP alpha surface buffer pixel format. */
+typedef enum _pxp_as_pixel_format
+{
+ kPXP_AsPixelFormatARGB8888 = 0x0, /*!< 32-bit pixels with alpha. */
+ kPXP_AsPixelFormatRGB888 = 0x4, /*!< 32-bit pixels without alpha (unpacked 24-bit format) */
+ kPXP_AsPixelFormatARGB1555 = 0x8, /*!< 16-bit pixels with alpha. */
+ kPXP_AsPixelFormatARGB4444 = 0x9, /*!< 16-bit pixels with alpha. */
+ kPXP_AsPixelFormatRGB555 = 0xC, /*!< 16-bit pixels without alpha. */
+ kPXP_AsPixelFormatRGB444 = 0xD, /*!< 16-bit pixels without alpha. */
+ kPXP_AsPixelFormatRGB565 = 0xE, /*!< 16-bit pixels without alpha. */
+} pxp_as_pixel_format_t;
+
+/*! @brief PXP alphs surface buffer configuration. */
+typedef struct _pxp_as_buffer_config
+{
+ pxp_as_pixel_format_t pixelFormat; /*!< AS buffer pixel format. */
+ uint32_t bufferAddr; /*!< Input buffer address. */
+ uint16_t pitchBytes; /*!< Number of bytes between two vertically adjacent pixels. */
+} pxp_as_buffer_config_t;
+
+/*!
+ * @brief PXP alpha mode during blending.
+ */
+typedef enum _pxp_alpha_mode
+{
+ kPXP_AlphaEmbedded, /*!< The alpha surface pixel alpha value will be used for blend. */
+ kPXP_AlphaOverride, /*!< The user defined alpha value will be used for blend directly. */
+ kPXP_AlphaMultiply, /*!< The alpha surface pixel alpha value scaled the user defined
+ alpha value will be used for blend, for example, pixel alpha set
+ set to 200, user defined alpha set to 100, then the reault alpha
+ is 200 * 100 / 255. */
+ kPXP_AlphaRop /*!< Raster operation. */
+} pxp_alpha_mode_t;
+
+/*!
+ * @brief PXP ROP mode during blending.
+ *
+ * Explanation:
+ * - AS: Alpha surface
+ * - PS: Process surface
+ * - nAS: Alpha surface NOT value
+ * - nPS: Process surface NOT value
+ */
+typedef enum _pxp_rop_mode
+{
+ kPXP_RopMaskAs = 0x0, /*!< AS AND PS. */
+ kPXP_RopMaskNotAs = 0x1, /*!< nAS AND PS. */
+ kPXP_RopMaskAsNot = 0x2, /*!< AS AND nPS. */
+ kPXP_RopMergeAs = 0x3, /*!< AS OR PS. */
+ kPXP_RopMergeNotAs = 0x4, /*!< nAS OR PS. */
+ kPXP_RopMergeAsNot = 0x5, /*!< AS OR nPS. */
+ kPXP_RopNotCopyAs = 0x6, /*!< nAS. */
+ kPXP_RopNot = 0x7, /*!< nPS. */
+ kPXP_RopNotMaskAs = 0x8, /*!< AS NAND PS. */
+ kPXP_RopNotMergeAs = 0x9, /*!< AS NOR PS. */
+ kPXP_RopXorAs = 0xA, /*!< AS XOR PS. */
+ kPXP_RopNotXorAs = 0xB /*!< AS XNOR PS. */
+} pxp_rop_mode_t;
+
+/*!
+ * @brief PXP alpha surface blending configuration.
+ */
+typedef struct _pxp_as_blend_config
+{
+ uint8_t alpha; /*!< User defined alpha value, only used when @ref alphaMode is @ref kPXP_AlphaOverride or @ref
+ kPXP_AlphaRop. */
+ bool invertAlpha; /*!< Set true to invert the alpha. */
+ pxp_alpha_mode_t alphaMode; /*!< Alpha mode. */
+ pxp_rop_mode_t ropMode; /*!< ROP mode, only valid when @ref alphaMode is @ref kPXP_AlphaRop. */
+} pxp_as_blend_config_t;
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief PXP secondary alpha surface blending engine configuration.
+ */
+typedef struct _pxp_as_blend_secondary_config
+{
+ bool invertAlpha; /*!< Set true to invert the alpha. */
+ bool ropEnable; /*!< Enable rop mode. */
+ pxp_rop_mode_t ropMode; /*!< ROP mode, only valid when ropEnable is true. */
+} pxp_as_blend_secondary_config_t;
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*! @brief PXP process block size. */
+typedef enum _pxp_block_size
+{
+ kPXP_BlockSize8 = 0U, /*!< Process 8x8 pixel blocks. */
+ kPXP_BlockSize16, /*!< Process 16x16 pixel blocks. */
+} pxp_block_size_t;
+
+/*! @brief PXP CSC1 mode. */
+typedef enum _pxp_csc1_mode
+{
+ kPXP_Csc1YUV2RGB = 0U, /*!< YUV to RGB. */
+ kPXP_Csc1YCbCr2RGB, /*!< YCbCr to RGB. */
+} pxp_csc1_mode_t;
+
+/*! @brief PXP CSC2 mode. */
+typedef enum _pxp_csc2_mode
+{
+ kPXP_Csc2YUV2RGB = 0U, /*!< YUV to RGB. */
+ kPXP_Csc2YCbCr2RGB, /*!< YCbCr to RGB. */
+ kPXP_Csc2RGB2YUV, /*!< RGB to YUV. */
+ kPXP_Csc2RGB2YCbCr, /*!< RGB to YCbCr. */
+} pxp_csc2_mode_t;
+
+/*!
+ * @brief PXP CSC2 configuration.
+ *
+ * Converting from YUV/YCbCr color spaces to the RGB color space uses the
+ * following equation structure:
+ *
+ * R = A1(Y+D1) + A2(U+D2) + A3(V+D3)
+ * G = B1(Y+D1) + B2(U+D2) + B3(V+D3)
+ * B = C1(Y+D1) + C2(U+D2) + C3(V+D3)
+ *
+ * Converting from the RGB color space to YUV/YCbCr color spaces uses the
+ * following equation structure:
+ *
+ * Y = A1*R + A2*G + A3*B + D1
+ * U = B1*R + B2*G + B3*B + D2
+ * V = C1*R + C2*G + C3*B + D3
+ */
+typedef struct _pxp_csc2_config
+{
+ pxp_csc2_mode_t mode; /*!< Convertion mode. */
+ float A1; /*!< A1. */
+ float A2; /*!< A2. */
+ float A3; /*!< A3. */
+ float B1; /*!< B1. */
+ float B2; /*!< B2. */
+ float B3; /*!< B3. */
+ float C1; /*!< C1. */
+ float C2; /*!< C2. */
+ float C3; /*!< C3. */
+ int16_t D1; /*!< D1. */
+ int16_t D2; /*!< D2. */
+ int16_t D3; /*!< D3. */
+} pxp_csc2_config_t;
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+/*! @brief PXP LUT lookup mode. */
+typedef enum _pxp_lut_lookup_mode
+{
+ kPXP_LutCacheRGB565 = 0U, /*!< LUT ADDR = R[7:3],G[7:2],B[7:3]. Use all 16KB of LUT
+ for indirect cached 128KB lookup. */
+ kPXP_LutDirectY8, /*!< LUT ADDR = 16'b0,Y[7:0]. Use the first 256 bytes of LUT.
+ Only third data path byte is tranformed. */
+ kPXP_LutDirectRGB444, /*!< LUT ADDR = R[7:4],G[7:4],B[7:4]. Use one 8KB bank of LUT
+ selected by @ref PXP_Select8kLutBank. */
+ kPXP_LutDirectRGB454, /*!< LUT ADDR = R[7:4],G[7:3],B[7:4]. Use all 16KB of LUT. */
+} pxp_lut_lookup_mode_t;
+
+/*! @brief PXP LUT output mode. */
+typedef enum _pxp_lut_out_mode
+{
+ kPXP_LutOutY8 = 1U, /*!< R/Y byte lane 2 lookup, bytes 1,0 bypassed. */
+ kPXP_LutOutRGBW4444CFA, /*!< Byte lane 2 = CFA_Y8, byte lane 1,0 = RGBW4444. */
+ kPXP_LutOutRGB888, /*!< RGB565->RGB888 conversion for Gamma correction. */
+} pxp_lut_out_mode_t;
+
+/*! @brief PXP LUT 8K bank index used when lookup mode is @ref kPXP_LutDirectRGB444. */
+typedef enum _pxp_lut_8k_bank
+{
+ kPXP_Lut8kBank0 = 0U, /*!< The first 8K bank used. */
+ kPXP_Lut8kBank1, /*!< The second 8K bank used. */
+} pxp_lut_8k_bank_t;
+
+/*! @brief PXP LUT configuration. */
+typedef struct _pxp_lut_config
+{
+ pxp_lut_lookup_mode_t lookupMode; /*!< Look up mode. */
+ pxp_lut_out_mode_t outMode; /*!< Out mode. */
+ uint32_t cfaValue; /*!< The CFA value used when look up mode is @ref kPXP_LutOutRGBW4444CFA. */
+} pxp_lut_config_t;
+#endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
+
+/*! @brief PXP internal memory. */
+typedef enum _pxp_ram
+{
+ kPXP_RamDither0Lut = 0U, /*!< Dither 0 LUT memory. */
+ kPXP_RamDither1Lut = 3U, /*!< Dither 1 LUT memory. */
+ kPXP_RamDither2Lut = 4U, /*!< Dither 2 LUT memory. */
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ kPXP_RamDither0Err0 = 1U, /*!< Dither 0 ERR0 memory. */
+ kPXP_RamDither0Err1 = 2U, /*!< Dither 0 ERR1 memory. */
+ kPXP_RamAluA = 5U, /*!< ALU A instr memory. */
+ kPXP_RamAluB = 6U, /*!< ALU B instr memory. */
+ kPXP_WfeAFetch = 7U, /*!< WFE-A fetch memory. */
+ kPXP_WfeBFetch = 8U, /*!< WFE-B fetch memory. */
+#endif /* FSL_FEATURE_PXP_V3 */
+} pxp_ram_t;
+
+/*! @brief PXP dither mode. */
+enum _pxp_dither_mode
+{
+ kPXP_DitherPassThrough = 0U, /*!< Pass through, no dither. */
+ kPXP_DitherFloydSteinberg = 1U, /*!< Floyd-Steinberg. For dither engine 0 only. */
+ kPXP_DitherAtkinson = 2U, /*!< Atkinson. For dither engine 0 only. */
+ kPXP_DitherOrdered = 3U, /*!< Ordered dither. */
+ kPXP_DitherQuantOnly = 4U, /*!< No dithering, only quantization. */
+ kPXP_DitherSierra = 5U, /*!< Sierra. For dither engine 0 only. */
+};
+
+/*! @brief PXP dither LUT mode. */
+enum _pxp_dither_lut_mode
+{
+ kPXP_DitherLutOff = 0U, /*!< The LUT memory is not used for LUT, could be used as ordered dither index matrix. */
+ kPXP_DitherLutPreDither, /*!< Use LUT at the pre-dither stage, The pre-dither LUT could only be used in Floyd mode
+ or Atkinson mode, which are not supported by current PXP module. */
+ kPXP_DitherLutPostDither, /*!< Use LUT at the post-dither stage. */
+};
+
+/*! @brief PXP dither matrix size. */
+enum _pxp_dither_matrix_size
+{
+ kPXP_DitherMatrix4 = 0, /*!< The dither index matrix is 4x4. */
+ kPXP_DitherMatrix8, /*!< The dither index matrix is 8x8. */
+ kPXP_DitherMatrix16, /*!< The dither index matrix is 16x16. */
+};
+
+/*! @brief PXP dither final LUT data. */
+typedef struct _pxp_dither_final_lut_data
+{
+ uint32_t data_3_0; /*!< Data 3 to data 0. Data 0 is the least significant byte. */
+ uint32_t data_7_4; /*!< Data 7 to data 4. Data 4 is the least significant byte. */
+ uint32_t data_11_8; /*!< Data 11 to data 8. Data 8 is the least significant byte. */
+ uint32_t data_15_12; /*!< Data 15 to data 12. Data 12 is the least significant byte. */
+} pxp_dither_final_lut_data_t;
+
+/*! @brief PXP dither configuration. */
+typedef struct _pxp_dither_config
+{
+ uint32_t enableDither0 : 1; /*!< Enable dither engine 0 or not, set 1 to enable, 0 to disable. */
+ uint32_t enableDither1 : 1; /*!< Enable dither engine 1 or not, set 1 to enable, 0 to disable. */
+ uint32_t enableDither2 : 1; /*!< Enable dither engine 2 or not, set 1 to enable, 0 to disable. */
+ uint32_t ditherMode0 : 3; /*!< Dither mode for dither engine 0. See @ref _pxp_dither_mode. */
+ uint32_t ditherMode1 : 3; /*!< Dither mode for dither engine 1. See @ref _pxp_dither_mode. */
+ uint32_t ditherMode2 : 3; /*!< Dither mode for dither engine 2. See @ref _pxp_dither_mode. */
+ uint32_t quantBitNum : 3; /*!< Number of bits quantize down to, the valid value is 1~7. */
+ uint32_t lutMode : 2; /*!< How to use the memory LUT, see @ref _pxp_dither_lut_mode. This must be set to @ref
+ kPXP_DitherLutOff
+ if any dither engine uses @ref kPXP_DitherOrdered mode. */
+ uint32_t idxMatrixSize0 : 2; /*!< Size of index matrix used for dither for dither engine 0, see @ref
+ _pxp_dither_matrix_size. */
+ uint32_t idxMatrixSize1 : 2; /*!< Size of index matrix used for dither for dither engine 1, see @ref
+ _pxp_dither_matrix_size. */
+ uint32_t idxMatrixSize2 : 2; /*!< Size of index matrix used for dither for dither engine 2, see @ref
+ _pxp_dither_matrix_size. */
+ uint32_t enableFinalLut : 1; /*!< Enable the final LUT, set 1 to enable, 0 to disable. */
+ uint32_t : 8;
+} pxp_dither_config_t;
+
+/*!
+ * @brief Porter Duff factor mode.
+ * @anchor pxp_porter_duff_factor_mode
+ */
+enum
+{
+ kPXP_PorterDuffFactorOne = 0U, /*!< Use 1. */
+ kPXP_PorterDuffFactorZero, /*!< Use 0. */
+ kPXP_PorterDuffFactorStraight, /*!< Use straight alpha. */
+ kPXP_PorterDuffFactorInversed, /*!< Use inversed alpha. */
+};
+
+/*!
+ * @brief Porter Duff global alpha mode.
+ * @anchor pxp_porter_duff_global_alpha_mode
+ */
+enum
+{
+ kPXP_PorterDuffGlobalAlpha = 0U, /*!< Use global alpha. */
+ kPXP_PorterDuffLocalAlpha, /*!< Use local alpha in each pixel. */
+ kPXP_PorterDuffScaledAlpha, /*!< Use global alpha * local alpha. */
+};
+
+/*!
+ * @brief Porter Duff alpha mode.
+ * @anchor pxp_porter_duff_alpha_mode
+ */
+enum
+{
+ kPXP_PorterDuffAlphaStraight = 0U, /*!< Use straight alpha, s0_alpha' = s0_alpha. */
+ kPXP_PorterDuffAlphaInversed /*!< Use inversed alpha, s0_alpha' = 0xFF - s0_alpha. */
+};
+
+/*!
+ * @brief Porter Duff color mode.
+ * @anchor pxp_porter_duff_color_mode
+ */
+enum
+{
+ kPXP_PorterDuffColorStraight = 0, /*!< @deprecated Use kPXP_PorterDuffColorNoAlpha. */
+ kPXP_PorterDuffColorInversed = 1, /*!< @deprecated Use kPXP_PorterDuffColorWithAlpha. */
+ kPXP_PorterDuffColorNoAlpha = 0, /*!< s0_pixel' = s0_pixel. */
+ kPXP_PorterDuffColorWithAlpha = 1, /*!< s0_pixel' = s0_pixel * s0_alpha". */
+};
+
+/*! @brief PXP Porter Duff configuration. */
+typedef struct
+{
+ uint32_t enable : 1; /*!< Enable or disable Porter Duff. */
+ uint32_t srcFactorMode : 2; /*!< Source layer (or AS, s1) factor mode, see @ref pxp_porter_duff_factor_mode. */
+ uint32_t dstGlobalAlphaMode : 2; /*!< Destination layer (or PS, s0) global alpha mode, see
+ @ref pxp_porter_duff_global_alpha_mode. */
+ uint32_t dstAlphaMode : 1; /*!< Destination layer (or PS, s0) alpha mode, see @ref pxp_porter_duff_alpha_mode. */
+ uint32_t dstColorMode : 1; /*!< Destination layer (or PS, s0) color mode, see @ref pxp_porter_duff_color_mode. */
+ uint32_t : 1;
+ uint32_t dstFactorMode : 2; /*!< Destination layer (or PS, s0) factor mode, see @ref pxp_porter_duff_factor_mode. */
+ uint32_t srcGlobalAlphaMode : 2; /*!< Source layer (or AS, s1) global alpha mode, see
+ @ref pxp_porter_duff_global_alpha_mode. */
+ uint32_t srcAlphaMode : 1; /*!< Source layer (or AS, s1) alpha mode, see @ref pxp_porter_duff_alpha_mode. */
+ uint32_t srcColorMode : 1; /*!< Source layer (or AS, s1) color mode, see @ref pxp_porter_duff_color_mode. */
+ uint32_t : 2;
+ uint32_t dstGlobalAlpha : 8; /*!< Destination layer (or PS, s0) global alpha value, 0~255. */
+ uint32_t srcGlobalAlpha : 8; /*!< Source layer (or AS, s1) global alpha value, 0~255. */
+} pxp_porter_duff_config_t;
+
+/*! @brief PXP Porter Duff blend mode. Note: don't change the enum item value */
+typedef enum _pxp_porter_duff_blend_mode
+{
+ kPXP_PorterDuffSrc = 0, /*!< Source Only */
+ kPXP_PorterDuffAtop, /*!< Source Atop */
+ kPXP_PorterDuffOver, /*!< Source Over */
+ kPXP_PorterDuffIn, /*!< Source In. */
+ kPXP_PorterDuffOut, /*!< Source Out. */
+ kPXP_PorterDuffDst, /*!< Destination Only. */
+ kPXP_PorterDuffDstAtop, /*!< Destination Atop. */
+ kPXP_PorterDuffDstOver, /*!< Destination Over. */
+ kPXP_PorterDuffDstIn, /*!< Destination In. */
+ kPXP_PorterDuffDstOut, /*!< Destination Out. */
+ kPXP_PorterDuffXor, /*!< XOR. */
+ kPXP_PorterDuffClear, /*!< Clear. */
+ kPXP_PorterDuffMax,
+} pxp_porter_duff_blend_mode_t;
+
+/*! @brief PXP Porter Duff blend mode. Note: don't change the enum item value */
+typedef struct _pxp_pic_copy_config
+{
+ uint32_t srcPicBaseAddr; /*!< Source picture base address. */
+ uint16_t srcPitchBytes; /*!< Pitch of the source buffer. */
+ uint16_t srcOffsetX; /*!< Copy position in source picture. */
+ uint16_t srcOffsetY; /*!< Copy position in source picture. */
+ uint32_t destPicBaseAddr; /*!< Destination picture base address. */
+ uint16_t destPitchBytes; /*!< Pitch of the destination buffer. */
+ uint16_t destOffsetX; /*!< Copy position in destination picture. */
+ uint16_t destOffsetY; /*!< Copy position in destination picture. */
+ uint16_t width; /*!< Pixel number each line to copy. */
+ uint16_t height; /*!< Lines to copy. */
+ pxp_as_pixel_format_t pixelFormat; /*!< Buffer pixel format. */
+} pxp_pic_copy_config_t;
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+
+/*!
+ * @brief PXP process engine enumeration
+ */
+typedef enum _pxp_process_engine_name
+{
+ kPXP_PsAsOutEngine = PXP_CTRL_ENABLE_PS_AS_OUT_MASK,
+ kPXP_DitherEngine = PXP_CTRL_ENABLE_DITHER_MASK,
+ kPXP_WfeaEngine = PXP_CTRL_ENABLE_WFE_A_MASK,
+ kPXP_WfebEngine = PXP_CTRL_ENABLE_WFE_B_MASK,
+ kPXP_InputFetchStoreEngine = PXP_CTRL_ENABLE_INPUT_FETCH_STORE_MASK,
+ kPXP_Alpha1Engine = PXP_CTRL_ENABLE_ALPHA_B_MASK,
+ kPXP_Csc2Engine = PXP_CTRL_ENABLE_CSC2_MASK,
+ kPXP_LutEngine = PXP_CTRL_ENABLE_LUT_MASK,
+ kPXP_Rotate0Engine = PXP_CTRL_ENABLE_ROTATE0_MASK,
+ kPXP_Rotate1Engine = PXP_CTRL_ENABLE_ROTATE1_MASK,
+} pxp_process_engine_name_t;
+
+/* Fetch engine configuration. */
+/*!
+ * @brief PXP fetch engine enumeration
+ *
+ * There are actually 4 fetch engine implemented, the others are WFE-A fetch engine and WFE-B fetch engine,
+ * whose registers are reserved from developer.
+ */
+typedef enum _pxp_fetch_engine_name
+{
+ kPXP_FetchInput,
+ kPXP_FetchDither,
+} pxp_fetch_engine_name_t;
+
+/*! @brief PXP fetch engine interface mode with the upstream store engine. */
+typedef enum _pxp_fetch_interface_mode
+{
+ kPXP_FetchModeNormal = 0U,
+ kPXP_FetchModeHandshake = 0x1U,
+ kPXP_FetchModeBypass = 0x2U,
+} pxp_fetch_interface_mode_t;
+
+/*! @brief PXP fetch/store engine burst length for scanline mode. */
+typedef enum _pxp_scanline_burst
+{
+ kPXP_Scanline8bytes,
+ kPXP_Scanline16bytes,
+ kPXP_Scanline32bytes,
+ kPXP_Scanline64bytes,
+} pxp_scanline_burst_t;
+
+/*! @brief PXP fetch engine block configuration. */
+typedef struct _pxp_block_format_config
+{
+ bool
+ enableblock; /*!< Enable to use block mode instead of scanline mode. Note: 1.Make sure to enable if rotate or
+ flip mode is enabled. 2.Block mode cannot work on 64bpp data stream where activeBits = 64. 3. If
+ LUT processing is in the path between the fetch and store engind, block mode must be enabled. */
+ bool blockSize16; /*!< Enable to use 16*16 block, otherwise it will be 8*8 block. */
+ pxp_scanline_burst_t burstLength; /*!< When using scanline mode, configure this for burst length. */
+} pxp_block_config_t;
+
+/*!
+ * @brief PXP fetch/store engine input/output active bits configuration.
+ *
+ * Since fetch engine is 64-bit input and 32-bit output per channel, need to configure both channels to use 64-bit input
+ * mode. And expand configuration will have no effect.
+ */
+typedef enum _pxp_activeBits
+{
+ kPXP_Active8Bits = 0x0,
+ kPXP_Active16Bits = 0x1,
+ kPXP_Active32Bits = 0x2,
+ kPXP_Active64Bits = 0x3,
+} pxp_active_bits_t;
+
+/*! @brief PXP fetch engine output word order when using 2 channels for 64-bit mode. */
+typedef enum _pxp_fetch_output_word_order
+{
+ kPXP_FetchOutputChannel1channel0 = 0x0, /*!< In 64bit mode, channel 1 output high byte. */
+ kPXP_FetchOutputChannel0channel1 = 0x1, /*!< In 64bit mode, channel 0 output high byte. */
+} pxp_fetch_output_word_order_t;
+
+/*!
+ * @brief PXP fetch engine shift component configuration.
+ *
+ * Fetch engine can divded each word into 4 components and shift them.
+ */
+typedef struct _pxp_fetch_shift_component
+{
+ uint8_t offset;
+ uint8_t width;
+} pxp_fetch_shift_component_t;
+
+/*!
+ * @brief PXP fetch engine shift configuration.
+ *
+ * Fetch engine can divded each word into 4 components and shift them.
+ * For example, to change YUV444 to YVU444, U and V positions need to be shifted: OFFSET0=8, OFFSET1=0, OFFSET2=16,
+ * OFFSET3=24, WIDTH0/1/2/3=8
+ */
+typedef struct _pxp_fetch_shift_config
+{
+ bool shiftBypass; /* Bypass the shift */
+ pxp_fetch_shift_component_t component0;
+ pxp_fetch_shift_component_t component1;
+ pxp_fetch_shift_component_t component2;
+ pxp_fetch_shift_component_t component3;
+} pxp_fetch_shift_config_t;
+
+/*! @brief PXP fetch engine input pixel format. */
+typedef enum _pxp_fetch_pixel_format
+{
+ kPXP_FetchFormatRGB565 = 0x0,
+ kPXP_FetchFormatRGB555 = 0x1,
+ kPXP_FetchFormatARGB1555 = 0x2,
+ kPXP_FetchFormatRGB444 = 0x3,
+ kPXP_FetchFormatARGB4444 = 0x4,
+ kPXP_FetchFormatYUYVorYVYU = 0x5,
+ kPXP_FetchFormatUYVYorVYUY = 0x6,
+ kPXP_FetchFormatYUV422_2P = 0x7,
+} pxp_fetch_pixel_format_t;
+
+/*! @brief PXP fetch engine configuration for one of the channel. */
+typedef struct _pxp_fetch_engine_config
+{
+ bool channelEnable; /*!< Enable channel. */
+ /* Address configuration */
+ uint32_t inputBaseAddr0; /*!< The input base address. Used for Y plane input when pixel format is YUV422_2p. */
+ uint32_t inputBaseAddr1; /*!< Must configure this for UV plane when input pixel format is YUV422_2p. */
+ /* Size configuration */
+ uint16_t totalHeight; /*!< Total height for the actual fetch size. */
+ uint16_t totalWidth; /*!< Total width for the actual fetch size. */
+ uint16_t pitchBytes; /*!< Channel input pitch */
+ uint16_t
+ ulcX; /*!< X coordinate of upper left coordinate in pixels of the active surface of the total input memory */
+ uint16_t
+ ulcY; /*!< Y coordinate of upper left coordinate in pixels of the active surface of the total input memory */
+ uint16_t
+ lrcX; /*!< X coordinate of Lower right coordinate in pixels of the active surface of the total input memory */
+ uint16_t
+ lrcY; /*!< Y coordinate of Lower right coordinate in pixels of the active surface of the total input memory */
+ /* Interface configuration */
+ pxp_fetch_interface_mode_t interface; /*!< Interface mode, normal/bypass/handshake */
+ /* Pixel configuration */
+ pxp_active_bits_t activeBits; /*!< Input active bits. */
+ pxp_fetch_pixel_format_t pixelFormat; /*!< Input pixel fetch format */
+ bool expandEnable; /*!< If enabled, input pixel will be expanded to ARGB8888, RGB888 or YUV444 of 32-bit format at
+ the output. */
+ /* Fetch format configuration */
+ pxp_flip_mode_t flipMode; /*!< Flip the fetched input. */
+ pxp_rotate_degree_t rotateDegree; /*!< Rotate the fetched input. */
+ pxp_block_config_t
+ fetchFormat; /*!< Block mode configuration. Make sure to enable block if rotate or flip mode is enabled. */
+ /* Output configuration. */
+ pxp_fetch_shift_config_t shiftConfig; /*!< Shift operation configuration. */
+ pxp_fetch_output_word_order_t wordOrder; /*!< Output word order when using 2 channels for 64-bit mode. */
+} pxp_fetch_engine_config_t;
+
+/* Store engine configuration. */
+
+/*!
+ * @brief PXP store engine enumeration
+ *
+ * There are actually 4 store engine implemented, the others are WFE-A store engine and WFE-B store engine,
+ * whose registers are reserved from developer.
+ */
+typedef enum _pxp_store_engine_name
+{
+ kPXP_StoreInput,
+ kPXP_StoreDither,
+} pxp_store_engine_name_t;
+
+/*! @brief PXP store engine interface mode with the downstream fetch engine. */
+typedef enum _pxp_store_interface_mode
+{
+ kPXP_StoreModeBypass = 0x20U,
+ kPXP_StoreModeNormal = 0x40U,
+ kPXP_StoreModeHandshake = 0x43U,
+ kPXP_StoreModeDual = 0x60U, /*!< Store engine outputs data directly to downstream fetch engine(Bypass) but also
+ storing it to memory at the same time. */
+} pxp_store_interface_mode_t;
+
+/*! @brief PXP store engine YUV output mode. */
+typedef enum _pxp_store_yuv_mode
+{
+ kPXP_StoreYUVDisable = 0U, /*!< Do not output YUV pixel format. */
+ kPXP_StoreYUVPlane1 =
+ 0x1U, /*!< Use channel to output YUV422_1p pixel format, need to use shift operation to make sure each pixel
+ component in its proper position: 64-bits of pixel data format and each 32 bits as {Y0, U0, Y1, V0}. */
+ kPXP_StoreYUVPlane2 =
+ 0x2U, /*!< Use channel to output YUV422_2p pixel format, need to use shift operation to make sure each pixel
+ component in its proper position: channel 0 {Y0,Y1}, channel 1 {U0,V0}. */
+} pxp_store_yuv_mode_t;
+
+/*! @brief Shift configuration for PXP store engine. */
+typedef struct _pxp_store_shift_config
+{
+ /* Data/Flag shift */
+ bool shiftBypass; /*!< Bypass the data shift */
+ uint64_t *pDataShiftMask; /*!< Pointer to mask0~mask7 to mask the 64-bit of output data, data is masked first then
+ shifted according to width. */
+ uint8_t *pDataShiftWidth; /*!< Pointer to width0~width7. Bit 7 is for shifted direction, 0 to right. Bit0~5 is for
+ shift width. */
+ uint8_t *pFlagShiftMask; /*!< Pointer to mask0~mask7 to mask the 8-bit of output flag, flag is masked first then
+ shifted according to width. */
+ uint8_t *pFlagShiftWidth; /*!< Pointer to width0~width7. Bit 6 is for shifted direction, 0 to right. Bit0~5 is for
+ shift width. */
+} pxp_store_shift_config_t;
+
+/*! @brief PXP store engine configuration for one of the channel. */
+typedef struct _pxp_store_engine_config
+{
+ bool channelEnable; /*!< Enable channel. */
+ /* Address configuration */
+ uint32_t outputBaseAddr0; /*!< The channel 0 output address if using 2 channels. If using 1 channel(must be channel
+ 0) and YUV422_2p output format, is for Y plane address. */
+ uint32_t outputBaseAddr1; /*!< The channel 1 output address if using 2 channels. If using 1 channel(must be channel
+ 0) and YUV422_2p output format, is for UV plane address. */
+ /* Size configuration */
+ uint16_t totalHeight; /*!< Total height for the actual store size. */
+ uint16_t totalWidth; /*!< Total width for the actual store size. */
+ uint16_t pitchBytes; /*!< Channel input pitch */
+ /* Interface configuration */
+ pxp_store_interface_mode_t interface; /*!< Interface mode, normal/bypass/handshake/dual. Make sure 2 channels use
+ the same mode if both enabled. */
+ /* pxp_store_handshake_array_t arraySize; !< If interfase mode is handshake, need to configure the array size. When
+ block is disabled, the scanline can only be 1. TODO no need now. */
+ /* Pixel configuration */
+ pxp_active_bits_t activeBits; /*!< Output active bits. */
+ pxp_store_yuv_mode_t yuvMode; /*!< Whether to output YUV pixel format. */
+ /* Fixed data configuration, only apply for channel 0. */
+ bool useFixedData; /*!< Whether to use fixed value for the output data. Can be used to write fixed value to specific
+ memory location for memory initialization. */
+ uint32_t fixedData; /*!< The value of the fixed data. */
+ /* Data packing */
+ bool packInSelect; /*!< When enabled, channel 0 will select low 32 bit shift out data to pack while channel i select
+ high 32 bit, otherwise all 64bit of data will be selected. */
+ /* Data store format */
+ pxp_block_config_t storeFormat; /*!< The format to store data, block or otherwise. */
+ pxp_store_shift_config_t shiftConfig; /*!< Shift operation configuration. */
+} pxp_store_engine_config_t;
+
+/* Pre-dither CFA engine configuration */
+
+/*! @brief PXP pre-dither CFA engine input pixel format. */
+typedef enum _pxp_cfa_input_format
+{
+ kPXP_CfaRGB888,
+ kPXP_CfaRGB444,
+} pxp_cfa_input_format_t;
+
+/*! @brief PXP pre-dither CFA engine configuration. */
+typedef struct _pxp_cfa_config
+{
+ bool bypass; /*!< Bypass the CFA process */
+ pxp_cfa_input_format_t pixelInFormat; /*!< The pixel input format for CFA. */
+ uint8_t arrayWidth; /*!< CFA array vertical size in pixels, min 3 max 15. */
+ uint8_t arrayHeight; /*!< CFA array horizontal size in pixels, min 3 max 15. */
+ uint16_t totalHeight; /*!< Total height for the buffer size, make sure it is aligned with the dither fetch engine
+ and dither engine. */
+ uint16_t totalWidth; /*!< Total width for the buffer size, make sure it is aligned with the dither fetch engine and
+ dither engine. */
+ uint32_t *cfaValue; /*!< Pointer to the value for the CFA array. 2-bit per component: 00-R,01-G,10-B,11-W. For a 4x4
+ array, 32 bits are need. */
+} pxp_cfa_config_t;
+
+/* Histogram configuration and status */
+
+/*! @brief PXP histogram mask condition. */
+typedef enum _pxp_histogram_mask_condition
+{
+ kPXP_HistogramMaskEqual = 0x0U, /*!< Value that equal to value0 will pass the mask operation. */
+ kPXP_HistogramMaskNotequal = 0x1U, /*!< Value that not equal to value0 will pass the mask operation. */
+ kPXP_HistogramMaskIn = 0x2U, /*!< Value that within the range of value0-value1 will pass the mask operation. */
+ kPXP_HistogramMaskOut = 0x3U, /*!< Value that without the range of value0-value1 will pass the mask operation. */
+} pxp_histogram_mask_condition_t;
+
+/*! @brief PXP Histogram configuration. */
+typedef struct _pxp_histogram_config
+{
+ bool enable; /*!< Enable histogram process. */
+ uint8_t *pParamValue; /*!< Pointer to the 62(2+4+8+16+32) byte of param value for 2-level, 4-level.....32-level
+ parameters. Only low 5-bit of each byte is valid. */
+ uint8_t lutValueOffset; /*!< The starting bit position of the LUT value. */
+ uint8_t lutValueWidth; /*!< The bit width of the LUT value, should be no more than 6 bits since only 63 LUTs are
+ supported. */
+ /* Mask configuration */
+ bool enableMask; /*!< Enable mask operation. */
+ uint8_t maskValue0; /*!< Value 0 for the condition judgement. */
+ uint8_t maskValue1; /*!< Value 1 for the condition judgement. */
+ uint8_t maskOffset; /*!< The starting bit position of the field to be checked against mask condition. */
+ uint8_t maskWidth; /*!< The width of the field to be checked against mask condition. */
+ pxp_histogram_mask_condition_t condition; /*!< The mask condition. */
+ /* Size configuration */
+ uint16_t totalHeight; /*!< Total height for the buffer size, make sure it is aligned with the output of legacy flow
+ or the WFE-A/B engine. */
+ uint16_t totalWidth; /*!< Total width for the buffer size, make sure it is aligned with the output of legacy flow or
+ the WFE-A/B engine. */
+} pxp_histogram_config_t;
+
+/*! @brief PXP Histogram mask result. */
+typedef struct _pxp_histogram_mask_result
+{
+ uint32_t pixelCount; /*!< The total count of the pixels that pass the mask(collided pixels). */
+ uint32_t minX; /*!< The x offset of the ULC of the minimal histogram that covers all passed pixels. */
+ uint32_t minY; /*!< The y offset of the ULC of the minimal histogram that covers all passed pixels. */
+ uint32_t maxX; /*!< The x offset of the LRC of the minimal histogram that covers all passed pixels. */
+ uint32_t maxY; /*!< The y offset of the LRC of the minimal histogram that covers all passed pixels. */
+ uint64_t lutlist; /*!< The 64-bit LUT list of collided pixels, if pixel of LUT17 is collided, bit17 in the list is
+ set. */
+} pxp_histogram_mask_result_t;
+
+/*! @brief PXP Histogram operation result flags. */
+enum _pxp_histgram_flags
+{
+ kPXP_Histogram2levelMatch = 1 << 0U, /* Bitmap pixels are fully contained within the HIST2 histogram. */
+ kPXP_Histogram4levelMatch = 1 << 1U, /* Bitmap pixels are fully contained within the HIST4 histogram. */
+ kPXP_Histogram8levelMatch = 1 << 2U, /* Bitmap pixels are fully contained within the HIST8 histogram. */
+ kPXP_Histogram16levelMatch = 1 << 3U, /* Bitmap pixels are fully contained within the HIST16 histogram. */
+ kPXP_Histogram32levelMatch = 1 << 4U, /* Bitmap pixels are fully contained within the HIST32 histogram. */
+};
+
+/*! @brief PXP WFE-A engine configuration. */
+typedef struct _pxp_wfea_engine_config
+{
+ uint32_t y4Addr; /*!< Address for Y4 buffer. */
+ uint32_t y4cAddr; /*!< Address for Y4C buffer, {Y4[3:0],3'b000,collision}, 8bpp. */
+ uint32_t wbAddr; /*!< Address for EPDC working buffer. */
+ uint16_t updateWidth; /*!< Width of the update area. */
+ uint16_t updateHeight; /*!< Height of the update area. */
+ uint16_t updatePitch; /*!< Pitch of the update area. */
+ uint16_t ulcX; /*!< X coordinate of upper left coordinate of the total input memory */
+ uint16_t ulcY; /*!< Y coordinate of upper left coordinate of the total input memory */
+ uint16_t resX; /*!< Horizontal resolution in pixels. */
+ uint8_t lutNum; /*!< The EPDC LUT number for the update. */
+ bool fullUpdateEnable; /*!< Enable full update. */
+ bool alphaEnable; /*!< Enable alpha field, upd is {Y4[3:0],3'b000,alpha} format, otherwise its {Y4[3:0],4'b0000}. */
+ bool detectionOnly; /*!< Detection only, do not write working buffer. */
+} pxp_wfea_engine_config_t;
+
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize the PXP.
+ *
+ * This function enables the PXP peripheral clock, and resets the PXP registers
+ * to default status.
+ *
+ * @param base PXP peripheral base address.
+ */
+void PXP_Init(PXP_Type *base);
+
+/*!
+ * @brief De-initialize the PXP.
+ *
+ * This function disables the PXP peripheral clock.
+ *
+ * @param base PXP peripheral base address.
+ */
+void PXP_Deinit(PXP_Type *base);
+
+/*!
+ * @brief Reset the PXP.
+ *
+ * This function resets the PXP peripheral registers to default status.
+ *
+ * @param base PXP peripheral base address.
+ */
+void PXP_Reset(PXP_Type *base);
+
+/*!
+ * @brief Reset the PXP and the control register to initialized state.
+ *
+ * @param base PXP peripheral base address.
+ */
+void PXP_ResetControl(PXP_Type *base);
+/* @} */
+
+/*!
+ * @name Global operations
+ * @{
+ */
+
+/*!
+ * @brief Start process.
+ *
+ * Start PXP process using current configuration.
+ *
+ * @param base PXP peripheral base address.
+ */
+static inline void PXP_Start(PXP_Type *base)
+{
+ base->CTRL_SET = PXP_CTRL_ENABLE_MASK;
+}
+
+/*!
+ * @brief Enable or disable LCD hand shake.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableLcdHandShake(PXP_Type *base, bool enable)
+{
+#if defined(PXP_CTRL_ENABLE_LCD_HANDSHAKE_MASK)
+ if (enable)
+ {
+ base->CTRL_SET = PXP_CTRL_ENABLE_LCD_HANDSHAKE_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = PXP_CTRL_ENABLE_LCD_HANDSHAKE_MASK;
+ }
+#else
+ if (enable)
+ {
+ base->CTRL_SET = PXP_CTRL_ENABLE_LCD0_HANDSHAKE_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = PXP_CTRL_ENABLE_LCD0_HANDSHAKE_MASK;
+ }
+#endif
+}
+
+#if (defined(FSL_FEATURE_PXP_HAS_EN_REPEAT) && FSL_FEATURE_PXP_HAS_EN_REPEAT)
+/*!
+ * @brief Enable or disable continous run.
+ *
+ * If continous run not enabled, @ref PXP_Start starts the PXP process. When completed,
+ * PXP enters idle mode and flag @ref kPXP_CompleteFlag asserts.
+ *
+ * If continous run enabled, the PXP will repeat based on the current configuration register
+ * settings.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableContinousRun(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_SET = PXP_CTRL_EN_REPEAT_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = PXP_CTRL_EN_REPEAT_MASK;
+ }
+}
+#endif /* FSL_FEATURE_PXP_HAS_EN_REPEAT */
+
+/*!
+ * @brief Set the PXP processing block size
+ *
+ * This function chooses the pixel block size that PXP using during process.
+ * Larger block size means better performace, but be careful that when PXP is
+ * rotating, the output must be divisible by the block size selected.
+ *
+ * @param base PXP peripheral base address.
+ * @param size The pixel block size.
+ */
+static inline void PXP_SetProcessBlockSize(PXP_Type *base, pxp_block_size_t size)
+{
+ base->CTRL = (base->CTRL & ~PXP_CTRL_BLOCK_SIZE_MASK) | PXP_CTRL_BLOCK_SIZE(size);
+}
+
+#if PXP_USE_PATH
+/*!
+ * @brief Sets the path for one of the MUX
+ *
+ * @param base PXP peripheral base address.
+ * @param path the path configuration for one of the mux.
+ */
+void PXP_SetPath(PXP_Type *base, pxp_path_t path);
+#endif /* PXP_USE_PATH */
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief Enables or disables PXP engines in the process flow.
+ *
+ * @param base PXP peripheral base address.
+ * @param mask The engines to enable. Logical OR of @ref pxp_process_engine_name_t.
+ * @param enable true to enable, false to disable.
+ */
+static inline void PXP_EnableProcessEngine(PXP_Type *base, uint32_t mask, bool enable)
+{
+ mask &= 0xF3F0000UL;
+
+ if (enable)
+ {
+ base->CTRL_SET = mask;
+ }
+ else
+ {
+ base->CTRL_CLR = mask;
+ }
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets PXP status flags.
+ *
+ * This function gets all PXP status flags. The flags are returned as the logical
+ * OR value of the enumerators @ref _pxp_flags. To check a specific status,
+ * compare the return value with enumerators in @ref _pxp_flags.
+ * For example, to check whether the PXP has completed process, use like this:
+ * @code
+ if (kPXP_CompleteFlag & PXP_GetStatusFlags(PXP))
+ {
+ ...
+ }
+ @endcode
+ *
+ * @param base PXP peripheral base address.
+ * @return PXP status flags which are OR'ed by the enumerators in the _pxp_flags.
+ */
+static inline uint32_t PXP_GetStatusFlags(PXP_Type *base)
+{
+#if defined(PXP_STAT_AXI_READ_ERROR_1_MASK)
+ uint32_t status = base->STAT & (PXP_STAT_NEXT_IRQ_MASK | PXP_STAT_IRQ0_MASK | PXP_STAT_AXI_READ_ERROR_0_MASK |
+ PXP_STAT_AXI_WRITE_ERROR_0_MASK | PXP_STAT_AXI_READ_ERROR_1_MASK |
+ PXP_STAT_AXI_WRITE_ERROR_1_MASK);
+#else
+ uint32_t status = base->STAT & (PXP_STAT_NEXT_IRQ_MASK | PXP_STAT_IRQ0_MASK | PXP_STAT_AXI_READ_ERROR_0_MASK |
+ PXP_STAT_AXI_WRITE_ERROR_0_MASK);
+#endif
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ status |= (base->IRQ >> 16U | base->IRQ << 16U);
+#endif /* FSL_FEATURE_PXP_V3 */
+ return status;
+}
+
+/*!
+ * @brief Clears status flags with the provided mask.
+ *
+ * This function clears PXP status flags with a provided mask.
+ *
+ * @param base PXP peripheral base address.
+ * @param statusMask The status flags to be cleared; it is logical OR value of @ref _pxp_flags.
+ */
+static inline void PXP_ClearStatusFlags(PXP_Type *base, uint32_t statusMask)
+{
+ base->STAT_CLR = statusMask;
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ statusMask &= 0xFFFF8000UL;
+ base->IRQ_CLR = (statusMask >> 16U | statusMask << 16U);
+#endif /* FSL_FEATURE_PXP_V3 */
+}
+
+/*!
+ * @brief Gets the AXI ID of the failing bus operation.
+ *
+ * @param base PXP peripheral base address.
+ * @param axiIndex Whitch AXI to get
+ * - 0: AXI0
+ * - 1: AXI1
+ * @return The AXI ID of the failing bus operation.
+ */
+static inline uint8_t PXP_GetAxiErrorId(PXP_Type *base, uint8_t axiIndex)
+{
+#if defined(PXP_STAT_AXI_ERROR_ID_1_MASK)
+ if (0U == axiIndex)
+ {
+ return (uint8_t)((base->STAT & PXP_STAT_AXI_ERROR_ID_0_MASK) >> PXP_STAT_AXI_ERROR_ID_0_SHIFT);
+ }
+ else
+ {
+ return (uint8_t)((base->STAT & PXP_STAT_AXI_ERROR_ID_1_MASK) >> PXP_STAT_AXI_ERROR_ID_1_SHIFT);
+ }
+#else
+ return (uint8_t)((base->STAT & PXP_STAT_AXI_ERROR_ID_MASK) >> PXP_STAT_AXI_ERROR_ID_SHIFT);
+#endif
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables PXP interrupts according to the provided mask.
+ *
+ * This function enables the PXP interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members. See @ref _pxp_interrupt_enable.
+ * For example, to enable PXP process complete interrupt and command loaded
+ * interrupt, do the following.
+ * @code
+ PXP_EnableInterrupts(PXP, kPXP_CommandLoadInterruptEnable | kPXP_CompleteInterruptEnable);
+ @endcode
+ *
+ * @param base PXP peripheral base address.
+ * @param mask The interrupts to enable. Logical OR of @ref _pxp_interrupt_enable.
+ */
+static inline void PXP_EnableInterrupts(PXP_Type *base, uint32_t mask)
+{
+ base->CTRL_SET = (mask & 0xEUL);
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ mask &= 0xFFFF8000UL;
+ base->IRQ_MASK_SET = (mask >> 16U | mask << 16U);
+#endif /* FSL_FEATURE_PXP_V3 */
+}
+
+/*!
+ * @brief Disables PXP interrupts according to the provided mask.
+ *
+ * This function disables the PXP interrupts according to the provided mask. The mask
+ * is a logical OR of enumeration members. See @ref _pxp_interrupt_enable.
+ *
+ * @param base PXP peripheral base address.
+ * @param mask The interrupts to disable. Logical OR of @ref _pxp_interrupt_enable.
+ */
+static inline void PXP_DisableInterrupts(PXP_Type *base, uint32_t mask)
+{
+ base->CTRL_CLR = (mask & 0xEUL);
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+ mask &= 0xFFFF8000UL;
+ base->IRQ_MASK_CLR = (mask >> 16U | mask << 16U);
+#endif /* FSL_FEATURE_PXP_V3 */
+}
+
+/* @} */
+
+/*!
+ * @name Alpha surface
+ * @{
+ */
+
+/*!
+ * @brief Set the alpha surface input buffer configuration.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetAlphaSurfaceBufferConfig(PXP_Type *base, const pxp_as_buffer_config_t *config);
+
+/*!
+ * @brief Set the alpha surface blending configuration.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void PXP_SetAlphaSurfaceBlendConfig(PXP_Type *base, const pxp_as_blend_config_t *config);
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief Set the alpha surface blending configuration for the secondary engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration structure.
+ */
+void PXP_SetAlphaSurfaceBlendSecondaryConfig(PXP_Type *base, const pxp_as_blend_secondary_config_t *config);
+
+/*!
+ * @brief Set the alpha surface overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the @p colorKeyLow to @p colorKeyHigh range, it will use the process surface
+ * pixel value for that location. If no PS image is present or if the PS image also
+ * matches its colorkey range, the PS background color is used.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * @param colorKeyLow Color key low range.
+ * @param colorKeyHigh Color key high range.
+ *
+ * @note Colorkey operations are higher priority than alpha or ROP operations
+ */
+void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh);
+
+/*!
+ * @brief Enable or disable the alpha surface color key.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t num, bool enable)
+{
+ switch (num)
+ {
+ case 0:
+ base->AS_CTRL =
+ (base->AS_CTRL & ~PXP_AS_CTRL_ENABLE_COLORKEY_MASK) | PXP_AS_CTRL_ENABLE_COLORKEY((uint32_t)enable);
+ break;
+
+ case 1:
+ base->ALPHA_B_CTRL_1 = (base->ALPHA_B_CTRL_1 & ~PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE_MASK) |
+ PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE((uint32_t)enable);
+ break;
+
+ default:
+ /* Only 2 alpha process engine instances are supported. */
+ assert(false);
+ break;
+ }
+}
+#else
+/*!
+ * @brief Set the alpha surface overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
+ * pixel value for that location. If no PS image is present or if the PS image also
+ * matches its colorkey range, the PS background color is used.
+ *
+ * @param base PXP peripheral base address.
+ * @param colorKeyLow Color key low range.
+ * @param colorKeyHigh Color key high range.
+ *
+ * @note Colorkey operations are higher priority than alpha or ROP operations
+ */
+void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh);
+
+/*!
+ * @brief Enable or disable the alpha surface color key.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableAlphaSurfaceOverlayColorKey(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->AS_CTRL |= PXP_AS_CTRL_ENABLE_COLORKEY_MASK;
+ }
+ else
+ {
+ base->AS_CTRL &= ~PXP_AS_CTRL_ENABLE_COLORKEY_MASK;
+ }
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * @brief Set the alpha surface position in output buffer.
+ *
+ * @param base PXP peripheral base address.
+ * @param upperLeftX X of the upper left corner.
+ * @param upperLeftY Y of the upper left corner.
+ * @param lowerRightX X of the lower right corner.
+ * @param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetAlphaSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY);
+/* @} */
+
+/*!
+ * @name Process surface
+ * @{
+ */
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief Set the back ground color of PS.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * @param backGroundColor Pixel value of the background color.
+ */
+static inline void PXP_SetProcessSurfaceBackGroundColor(PXP_Type *base, uint8_t num, uint32_t backGroundColor)
+{
+ switch (num)
+ {
+ case 0:
+ base->PS_BACKGROUND_0 = backGroundColor;
+ break;
+
+ case 1:
+ base->PS_BACKGROUND_1 = backGroundColor;
+ break;
+
+ default:
+ /* Only 2 alpha process engine instances are supported. */
+ assert(false);
+ break;
+ }
+}
+#else
+/*!
+ * @brief Set the back ground color of PS.
+ *
+ * @param base PXP peripheral base address.
+ * @param backGroundColor Pixel value of the background color.
+ */
+static inline void PXP_SetProcessSurfaceBackGroundColor(PXP_Type *base, uint32_t backGroundColor)
+{
+#if defined(PXP_PS_BACKGROUND_0_COLOR_MASK)
+ base->PS_BACKGROUND_0 = backGroundColor;
+#else
+ base->PS_BACKGROUND = backGroundColor;
+#endif
+}
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * @brief Set the process surface input buffer configuration.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetProcessSurfaceBufferConfig(PXP_Type *base, const pxp_ps_buffer_config_t *config);
+
+/*!
+ * @brief Set the process surface scaler configuration.
+ *
+ * The valid down scale fact is 1/(2^12) ~ 16.
+ *
+ * @param base PXP peripheral base address.
+ * @param inputWidth Input image width.
+ * @param inputHeight Input image height.
+ * @param outputWidth Output image width.
+ * @param outputHeight Output image height.
+ */
+void PXP_SetProcessSurfaceScaler(
+ PXP_Type *base, uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight);
+
+/*!
+ * @brief Set the process surface position in output buffer.
+ *
+ * @param base PXP peripheral base address.
+ * @param upperLeftX X of the upper left corner.
+ * @param upperLeftY Y of the upper left corner.
+ * @param lowerRightX X of the lower right corner.
+ * @param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetProcessSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY);
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief Set the process surface color key.
+ *
+ * If the PS image matches colorkey range, the PS background color is output. Set
+ * @p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number. 0 for alpha engine A, 1 for alpha engine B.
+ * @param colorKeyLow Color key low range.
+ * @param colorKeyHigh Color key high range.
+ */
+void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh);
+#else
+/*!
+ * @brief Set the process surface color key.
+ *
+ * If the PS image matches colorkey range, the PS background color is output. Set
+ * @p colorKeyLow to 0xFFFFFFFF and @p colorKeyHigh to 0 will disable the colorkeying.
+ *
+ * @param base PXP peripheral base address.
+ * @param colorKeyLow Color key low range.
+ * @param colorKeyHigh Color key high range.
+ */
+void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh);
+#endif /* FSL_FEATURE_PXP_V3 */
+
+/*!
+ * @brief Set the process surface input pixel format YUV or YCbCr.
+ *
+ * If process surface input pixel format is YUV and CSC1 is not enabled,
+ * in other words, the process surface output pixel format is also YUV,
+ * then this function should be called to set whether input pixel format
+ * is YUV or YCbCr.
+ *
+ * @param base PXP peripheral base address.
+ * @param format The YUV format.
+ */
+static inline void PXP_SetProcessSurfaceYUVFormat(PXP_Type *base, pxp_ps_yuv_format_t format)
+{
+ if (kPXP_PsYUVFormatYUV == format)
+ {
+ base->CSC1_COEF0 &= ~PXP_CSC1_COEF0_YCBCR_MODE_MASK;
+ }
+ else
+ {
+ base->CSC1_COEF0 |= PXP_CSC1_COEF0_YCBCR_MODE_MASK;
+ }
+}
+/* @} */
+
+/*!
+ * @name Output buffer
+ * @{
+ */
+
+/*!
+ * @brief Set the PXP outpt buffer configuration.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetOutputBufferConfig(PXP_Type *base, const pxp_output_buffer_config_t *config);
+
+/*!
+ * @brief Set the global overwritten alpha value.
+ *
+ * If global overwritten alpha is enabled, the alpha component in output buffer pixels
+ * will be overwritten, otherwise the computed alpha value is used.
+ *
+ * @param base PXP peripheral base address.
+ * @param alpha The alpha value.
+ */
+static inline void PXP_SetOverwrittenAlphaValue(PXP_Type *base, uint8_t alpha)
+{
+ base->OUT_CTRL = (base->OUT_CTRL & ~PXP_OUT_CTRL_ALPHA_MASK) | PXP_OUT_CTRL_ALPHA(alpha);
+}
+
+/*!
+ * @brief Enable or disable the global overwritten alpha value.
+ *
+ * If global overwritten alpha is enabled, the alpha component in output buffer pixels
+ * will be overwritten, otherwise the computed alpha value is used.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableOverWrittenAlpha(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->OUT_CTRL_SET = PXP_OUT_CTRL_ALPHA_OUTPUT_MASK;
+ }
+ else
+ {
+ base->OUT_CTRL_CLR = PXP_OUT_CTRL_ALPHA_OUTPUT_MASK;
+ }
+}
+
+/*!
+ * @brief Set the rotation configuration.
+ *
+ * The PXP could rotate the process surface or the output buffer. There are
+ * two PXP versions:
+ * - Version 1: Only has one rotate sub module, the output buffer and process
+ * surface share the same rotate sub module, which means the process surface
+ * and output buffer could not be rotate at the same time. When pass in
+ * @ref kPXP_RotateOutputBuffer, the process surface could not use the rotate,
+ * Also when pass in @ref kPXP_RotateProcessSurface, output buffer could not
+ * use the rotate.
+ * - Version 2: Has two seperate rotate sub modules, the output buffer and
+ * process surface could configure the rotation independently.
+ *
+ * Upper layer could use the macro PXP_SHARE_ROTATE to check which version is.
+ * PXP_SHARE_ROTATE=1 means version 1.
+ *
+ * @param base PXP peripheral base address.
+ * @param position Rotate process surface or output buffer.
+ * @param degree Rotate degree.
+ * @param flipMode Flip mode.
+ *
+ * @note This function is different depends on the macro PXP_SHARE_ROTATE.
+ */
+static inline void PXP_SetRotateConfig(PXP_Type *base,
+ pxp_rotate_position_t position,
+ pxp_rotate_degree_t degree,
+ pxp_flip_mode_t flipMode)
+{
+#if PXP_SHARE_ROTATE
+ base->CTRL =
+ (base->CTRL & ~(PXP_CTRL_ROTATE_MASK | PXP_CTRL_ROT_POS_MASK | PXP_CTRL_VFLIP_MASK | PXP_CTRL_HFLIP_MASK)) |
+ PXP_CTRL_ROTATE(degree) | PXP_CTRL_ROT_POS(position) | ((uint32_t)flipMode << PXP_CTRL_HFLIP_SHIFT);
+#else
+ uint32_t ctrl = base->CTRL;
+
+ if (kPXP_RotateOutputBuffer == position)
+ {
+ ctrl &= ~(PXP_CTRL_HFLIP0_MASK | PXP_CTRL_VFLIP0_MASK | PXP_CTRL_ROTATE0_MASK);
+ ctrl |= (PXP_CTRL_ROTATE0(degree) | ((uint32_t)flipMode << PXP_CTRL_HFLIP0_SHIFT));
+ }
+ else
+ {
+ ctrl &= ~(PXP_CTRL_HFLIP1_MASK | PXP_CTRL_VFLIP1_MASK | PXP_CTRL_ROTATE1_MASK);
+ ctrl |= (PXP_CTRL_ROTATE1(degree) | ((uint32_t)flipMode << PXP_CTRL_HFLIP1_SHIFT));
+ }
+
+ base->CTRL = ctrl;
+#endif
+}
+
+/*!
+ * @brief Build a solid rectangle of given pixel value.
+ *
+ * @param base PXP peripheral base address.
+ * @param outFormat output pixel format.
+ * @param value The value of the pixel to be filled in the rectangle in ARGB8888 format.
+ * @param width width of the rectangle.
+ * @param height height of the rectangle.
+ * @param pitch output pitch in byte.
+ * @param outAddr address of the memory to store the rectangle.
+ */
+void PXP_BuildRect(PXP_Type *base,
+ pxp_output_pixel_format_t outFormat,
+ uint32_t value,
+ uint16_t width,
+ uint16_t height,
+ uint16_t pitch,
+ uint32_t outAddr);
+/* @} */
+
+/*!
+ * @name Command queue
+ * @{
+ */
+
+/*!
+ * @brief Set the next command.
+ *
+ * The PXP supports a primitive ability to queue up one operation while the current
+ * operation is running. Workflow:
+ *
+ * 1. Prepare the PXP register values except STAT, CSCCOEFn, NEXT in the memory
+ * in the order they appear in the register map.
+ * 2. Call this function sets the new operation to PXP.
+ * 3. There are two methods to check whether the PXP has loaded the new operation.
+ * The first method is using @ref PXP_IsNextCommandPending. If there is new operation
+ * not loaded by the PXP, this function returns true. The second method is checking
+ * the flag @ref kPXP_CommandLoadFlag, if command loaded, this flag asserts. User
+ * could enable interrupt @ref kPXP_CommandLoadInterruptEnable to get the loaded
+ * signal in interrupt way.
+ * 4. When command loaded by PXP, a new command could be set using this function.
+ *
+ * @code
+ uint32_t pxp_command1[48];
+ uint32_t pxp_command2[48];
+
+ pxp_command1[0] = ...;
+ pxp_command1[1] = ...;
+ ...
+ pxp_command2[0] = ...;
+ pxp_command2[1] = ...;
+ ...
+
+ while (PXP_IsNextCommandPending(PXP))
+ {
+ }
+
+ PXP_SetNextCommand(PXP, pxp_command1);
+
+ while (PXP_IsNextCommandPending(PXP))
+ {
+ }
+
+ PXP_SetNextCommand(PXP, pxp_command2);
+ @endcode
+ *
+ * @param base PXP peripheral base address.
+ * @param commandAddr Address of the new command.
+ */
+void PXP_SetNextCommand(PXP_Type *base, void *commandAddr);
+
+/*!
+ * @brief Check whether the next command is pending.
+ *
+ * @param base UART peripheral base address.
+ * @return True is pending, false is not.
+ */
+static inline bool PXP_IsNextCommandPending(PXP_Type *base)
+{
+ return (bool)(base->NEXT & PXP_NEXT_ENABLED_MASK);
+}
+
+/*!
+ * @brief Cancel command set by @ref PXP_SetNextCommand
+ *
+ * @param base UART peripheral base address.
+ */
+static inline void PXP_CancelNextCommand(PXP_Type *base)
+{
+ /* Write PXP_NEXT_ENABLED_MASK to the register NEXT_CLR to canel the command. */
+ uint32_t regAddr = (uint32_t) & (base->NEXT);
+ regAddr += 8U;
+ *(uint32_t *)regAddr = PXP_NEXT_ENABLED_MASK;
+}
+
+/* @} */
+
+/*!
+ * @name Color space conversion
+ * @{
+ */
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+/*!
+ * @brief Set the CSC2 configuration.
+ *
+ * The CSC2 module receives pixels in any color space and can convert the pixels
+ * into any of RGB, YUV, or YCbCr color spaces. The output pixels are passed
+ * onto the LUT and rotation engine for further processing
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetCsc2Config(PXP_Type *base, const pxp_csc2_config_t *config);
+
+/*!
+ * @brief Enable or disable the CSC2.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableCsc2(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CSC2_CTRL &= ~PXP_CSC2_CTRL_BYPASS_MASK;
+ }
+ else
+ {
+ base->CSC2_CTRL |= PXP_CSC2_CTRL_BYPASS_MASK;
+ }
+}
+#endif /* FSL_FEATURE_PXP_HAS_NO_CSC2 */
+
+/*!
+ * @brief Set the CSC1 mode.
+ *
+ * The CSC1 module receives scaled YUV/YCbCr444 pixels from the scale engine and
+ * converts the pixels to the RGB888 color space. It could only be used by process
+ * surface.
+ *
+ * @param base PXP peripheral base address.
+ * @param mode The conversion mode.
+ */
+void PXP_SetCsc1Mode(PXP_Type *base, pxp_csc1_mode_t mode);
+
+/*!
+ * @brief Enable or disable the CSC1.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableCsc1(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CSC1_COEF0 &= ~PXP_CSC1_COEF0_BYPASS_MASK;
+ }
+ else
+ {
+ base->CSC1_COEF0 |= PXP_CSC1_COEF0_BYPASS_MASK;
+ }
+}
+/* @} */
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+/*!
+ * @name LUT operations
+ * @{
+ */
+
+/*!
+ * @brief Set the LUT configuration.
+ *
+ * The lookup table (LUT) is used to modify pixels in a manner that is not linear
+ * and that cannot be achieved by the color space conversion modules. To setup
+ * the LUT, the complete workflow is:
+ * 1. Use @ref PXP_SetLutConfig to set the configuration, such as the lookup mode.
+ * 2. Use @ref PXP_LoadLutTable to load the lookup table to PXP.
+ * 3. Use @ref PXP_EnableLut to enable the function.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetLutConfig(PXP_Type *base, const pxp_lut_config_t *config);
+
+/*!
+ * @brief Set the look up table to PXP.
+ *
+ * If lookup mode is DIRECT mode, this function loads @p bytesNum of values
+ * from the address @p memAddr into PXP LUT address @p lutStartAddr. So this
+ * function allows only update part of the PXP LUT.
+ *
+ * If lookup mode is CACHE mode, this function sets the new address to @p memAddr
+ * and invalid the PXP LUT cache.
+ *
+ * @param base PXP peripheral base address.
+ * @param lookupMode Which lookup mode is used. Note that this parameter is only
+ * used to distinguish DIRECT mode and CACHE mode, it does not change the register
+ * value PXP_LUT_CTRL[LOOKUP_MODE]. To change that value, use function @ref PXP_SetLutConfig.
+ * @param bytesNum How many bytes to set. This value must be divisable by 8.
+ * @param memAddr Address of look up table to set.
+ * @param lutStartAddr The LUT value will be loaded to LUT from index lutAddr. It should
+ * be 8 bytes aligned.
+ *
+ * @retval kStatus_Success Load successfully.
+ * @retval kStatus_InvalidArgument Failed because of invalid argument.
+ */
+status_t PXP_LoadLutTable(
+ PXP_Type *base, pxp_lut_lookup_mode_t lookupMode, uint32_t bytesNum, uint32_t memAddr, uint16_t lutStartAddr);
+
+/*!
+ * @brief Enable or disable the LUT.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void PXP_EnableLut(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LUT_CTRL &= ~PXP_LUT_CTRL_BYPASS_MASK;
+ }
+ else
+ {
+ base->LUT_CTRL |= PXP_LUT_CTRL_BYPASS_MASK;
+ }
+}
+
+/*!
+ * @brief Select the 8kB LUT bank in DIRECT_RGB444 mode.
+ *
+ * @param base PXP peripheral base address.
+ * @param bank The bank to select.
+ */
+static inline void PXP_Select8kLutBank(PXP_Type *base, pxp_lut_8k_bank_t bank)
+{
+ base->LUT_CTRL = (base->LUT_CTRL & ~PXP_LUT_CTRL_SEL_8KB_MASK) | PXP_LUT_CTRL_SEL_8KB(bank);
+}
+/* @} */
+#endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
+
+#if (defined(FSL_FEATURE_PXP_HAS_DITHER) && FSL_FEATURE_PXP_HAS_DITHER)
+/*!
+ * @name Dither
+ * @{
+ */
+
+/*!
+ * @brief Write data to the PXP internal memory.
+ *
+ * @param base PXP peripheral base address.
+ * @param ram Which internal memory to write.
+ * @param bytesNum How many bytes to write.
+ * @param data Pointer to the data to write.
+ * @param memStartAddr The start address in the internal memory to write the data.
+ */
+void PXP_SetInternalRamData(PXP_Type *base, pxp_ram_t ram, uint32_t bytesNum, uint8_t *data, uint16_t memStartAddr);
+
+/*!
+ * @brief Set the dither final LUT data.
+ *
+ * The dither final LUT is only applicble to dither engine 0. It takes the bits[7:4]
+ * of the output pixel and looks up and 8 bit value from the 16 value LUT to generate
+ * the final output pixel to the next process module.
+ *
+ * @param base PXP peripheral base address.
+ * @param data Pointer to the LUT data to set.
+ */
+void PXP_SetDitherFinalLutData(PXP_Type *base, const pxp_dither_final_lut_data_t *data);
+
+/*!
+ * @brief Set the configuration for the dither block.
+ *
+ * If the pre-dither LUT, post-dither LUT or ordered dither is used, please call
+ * @ref PXP_SetInternalRamData to set the LUT data to internal memory.
+ *
+ * If the final LUT is used, please call @ref PXP_SetDitherFinalLutData to set
+ * the LUT data.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ *
+ * @note When using ordered dithering, please set the PXP process block size same
+ * with the ordered dithering matrix size using function @ref PXP_SetProcessBlockSize.
+ */
+static inline void PXP_SetDitherConfig(PXP_Type *base, const pxp_dither_config_t *config)
+{
+ typedef union
+ {
+ pxp_dither_config_t _dither_config;
+ uint32_t _u32;
+ } pxp_reg_convert_t;
+
+ pxp_reg_convert_t pid;
+
+ pid._dither_config = *config;
+ base->DITHER_CTRL = pid._u32 & 0x00FFFFFFU;
+}
+
+/*!
+ * @brief Enable or disable dither engine in the PXP process path.
+ *
+ * After the initialize function @ref PXP_Init, the dither engine is disabled and not
+ * use in the PXP processing path. This function enables the dither engine and
+ * routes the dither engine output to the output buffer. When the dither engine
+ * is enabled using this function, @ref PXP_SetDitherConfig must be called to
+ * configure dither engine correctly, otherwise there is not output to the output
+ * buffer.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable Pass in true to enable, false to disable.
+ */
+void PXP_EnableDither(PXP_Type *base, bool enable);
+
+/* @} */
+
+#endif /* FSL_FEATURE_PXP_HAS_DITHER */
+
+/*!
+ * @name Porter Duff
+ * @{
+ */
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+/*!
+ * @brief Set the Porter Duff configuration for one of the alpha process engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetPorterDuffConfig(PXP_Type *base, uint8_t num, const pxp_porter_duff_config_t *config);
+#endif /* FSL_FEATURE_PXP_V3 */
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)
+/*!
+ * @brief Set the Porter Duff configuration.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the configuration.
+ */
+void PXP_SetPorterDuffConfig(PXP_Type *base, const pxp_porter_duff_config_t *config);
+#endif /* FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
+
+#if (!(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)) || \
+ (defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)
+/*!
+ * @brief Get the Porter Duff configuration by blend mode.
+ *
+ * The FactorMode are selected based on blend mode, the AlphaMode are set to
+ * @ref kPXP_PorterDuffAlphaStraight, the ColorMode are set to
+ * @ref kPXP_PorterDuffColorWithAlpha, the GlobalAlphaMode are set to
+ * @ref kPXP_PorterDuffLocalAlpha. These values could be modified after calling
+ * this function.
+ *
+ * @param mode The blend mode.
+ * @param config Pointer to the configuration.
+ * @retval kStatus_Success Successfully get the configuratoin.
+ * @retval kStatus_InvalidArgument The blend mode not supported.
+ */
+status_t PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode, pxp_porter_duff_config_t *config);
+
+/* @} */
+#endif /* FSL_FEATURE_PXP_V3 || FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
+
+/* @} */
+
+/*!
+ * @name Buffer copy
+ * @{
+ */
+
+/*!
+ * @brief Copy picture from one buffer to another buffer.
+ *
+ * This function copies a rectangle from one buffer to another buffer.
+ *
+ * @verbatim
+ Source buffer:
+ srcPicBaseAddr
+ +-----------------------------------------------------------+
+ | |
+ | (srcOffsetX, srcOffsetY) |
+ | +-------------------+ |
+ | | | |
+ | | | |
+ | | | height |
+ | | | |
+ | | | |
+ | +-------------------+ |
+ | width |
+ | |
+ | srcPicthBytes |
+ +-----------------------------------------------------------+
+
+ Destination buffer:
+ destPicBaseAddr
+ +-------------------------------------------+
+ | |
+ | |
+ | |
+ | (destOffsetX, destOffsetY) |
+ | +-------------------+ |
+ | | | |
+ | | | |
+ | | | height |
+ | | | |
+ | | | |
+ | +-------------------+ |
+ | width |
+ | |
+ | |
+ | |
+ | destPicthBytes |
+ +-------------------------------------------+
+ @endverbatim
+ *
+ * @note This function resets the old PXP settings, which means the settings
+ * like rotate, flip, will be reseted to disabled status.
+ *
+ * @param base PXP peripheral base address.
+ * @param config Pointer to the picture copy configuration structure.
+ * @retval kStatus_Success Successfully started the copy process.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartPictureCopy(PXP_Type *base, const pxp_pic_copy_config_t *config);
+
+/*!
+ * @brief Copy continous memory.
+ *
+ * @note The copy size should be 512 byte aligned.
+ * @note This function resets the old PXP settings, which means the settings
+ * like rotate, flip, will be reseted to disabled status.
+ *
+ * @param base PXP peripheral base address.
+ * @param srcAddr Source memory address.
+ * @param destAddr Destination memory address.
+ * @param size How many bytes to copy, should be 512 byte aligned.
+ * @retval kStatus_Success Successfully started the copy process.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartMemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size);
+
+/*!
+ * @brief Copy continous memory.
+ *
+ * @note This function resets the old PXP settings, which means the settings
+ * like rotate, flip, will be reseted to disabled status.
+ *
+ * @note Compare with @PXP_StartMemCopy, this function supports size not aligned to
+ * 512 bytes. This function returns when copy finished, upper layer doesn't need to
+ * wait @ref kPXP_CompleteFlag.
+ *
+ * @param base PXP peripheral base address.
+ * @param srcAddr Source memory address.
+ * @param destAddr Destination memory address.
+ * @param size How many bytes to copy, should be 512 byte aligned.
+ * @retval kStatus_Success Successfully started the copy process.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_MemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size);
+
+/* @} */
+
+#if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
+
+/*!
+ * @name Fetch engine
+ * @{
+ */
+/*!
+ * @brief Configures one channel of some block's fetch engine.
+ *
+ * Fetch engine is 64-bit input and 32-bit output per channel
+ *
+ * @param base PXP peripheral base address.
+ * @param name which block the fetch engine belongs to.
+ * @param channel channel number.
+ * @param config pointer to the configuration structure.
+ * @retval kStatus_Success Successfully configured the engine.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetFetchEngineConfig(PXP_Type *base,
+ pxp_fetch_engine_name_t name,
+ uint8_t channel,
+ const pxp_fetch_engine_config_t *config);
+
+/*!
+ * @brief Enables/disables the fetch engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param name which block the fetch engine belongs to.
+ * @param channel channel number.
+ * @param enable true to enable, false to disable.
+ */
+static inline void PXP_EnableFetchEngine(PXP_Type *base, pxp_fetch_engine_name_t name, uint8_t channel, bool enable)
+{
+ if (enable)
+ {
+ if (name == kPXP_FetchInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_FETCH_CTRL_CH0_SET = PXP_INPUT_FETCH_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->INPUT_FETCH_CTRL_CH1_SET = PXP_INPUT_FETCH_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_FETCH_CTRL_CH0_SET = PXP_DITHER_FETCH_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->DITHER_FETCH_CTRL_CH1_SET = PXP_DITHER_FETCH_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (name == kPXP_FetchInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_FETCH_CTRL_CH0_CLR = PXP_INPUT_FETCH_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->INPUT_FETCH_CTRL_CH1_CLR = PXP_INPUT_FETCH_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_FETCH_CTRL_CH0_CLR = PXP_DITHER_FETCH_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->DITHER_FETCH_CTRL_CH1_CLR = PXP_DITHER_FETCH_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ }
+}
+/* @} */
+
+/*!
+ * @name Store engine
+ * @{
+ */
+
+/*!
+ * @brief Configures one channel of some block's store engine.
+ *
+ * Store engine is 32-bit input and 64-bit output per channel.
+ * @note: If there is only one channel used for data input, channel 0 must be used rather than channel 1.
+ *
+ * @param base PXP peripheral base address.
+ * @param name the store engine belongs to which block.
+ * @param channel channel number.
+ * @param config pointer to the configuration structure.
+ * @retval kStatus_Success Successfully configured the engine.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetStoreEngineConfig(PXP_Type *base,
+ pxp_store_engine_name_t name,
+ uint8_t channel,
+ const pxp_store_engine_config_t *config);
+
+/*!
+ * @brief Enables/disables the store engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param name which block the store engine belongs to.
+ * @param channel channel number.
+ * @param enable true to enable, false to disable.
+ */
+static inline void PXP_EnableStoreEngine(PXP_Type *base, pxp_store_engine_name_t name, uint8_t channel, bool enable)
+{
+ if (enable)
+ {
+ if (name == kPXP_StoreInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_STORE_CTRL_CH0_SET = PXP_INPUT_STORE_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->INPUT_STORE_CTRL_CH1_SET = PXP_INPUT_STORE_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_STORE_CTRL_CH0_SET = PXP_DITHER_STORE_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->DITHER_STORE_CTRL_CH1_SET = PXP_DITHER_STORE_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (name == kPXP_StoreInput)
+ {
+ switch (channel)
+ {
+ case 0:
+ base->INPUT_STORE_CTRL_CH0_CLR = PXP_INPUT_STORE_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->INPUT_STORE_CTRL_CH1_CLR = PXP_INPUT_STORE_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ switch (channel)
+ {
+ case 0:
+ base->DITHER_STORE_CTRL_CH0_CLR = PXP_DITHER_STORE_CTRL_CH0_CH_EN_MASK;
+ break;
+
+ case 1:
+ base->DITHER_STORE_CTRL_CH1_CLR = PXP_DITHER_STORE_CTRL_CH1_CH_EN_MASK;
+ break;
+
+ default:
+ /* Only 2 channels are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+ }
+ }
+}
+
+/*!
+ * @brief Combines the 2 channels of some store engine.
+ *
+ * Store engine is 32-bit input and 64-bit output per channel. If both channels of store engine's
+ * input and 8 bits flag contain valid data, then need set combine to true to support total 64-bit input.
+ *
+ * @param base PXP peripheral base address.
+ * @param name the store engine belongs to which block.
+ * @param combine true to combine the 2 channels.
+ */
+static inline void PXP_CombineStoreEngineChannel(PXP_Type *base, pxp_store_engine_name_t name, bool combine)
+{
+ if (name == kPXP_StoreInput)
+ {
+ if (combine)
+ {
+ base->INPUT_STORE_CTRL_CH0_SET = PXP_INPUT_STORE_CTRL_CH0_SET_COMBINE_2CHANNEL_MASK;
+ }
+ else
+ {
+ base->INPUT_STORE_CTRL_CH0_CLR = PXP_INPUT_STORE_CTRL_CH0_SET_COMBINE_2CHANNEL_MASK;
+ }
+ }
+ else
+ {
+ if (combine)
+ {
+ base->DITHER_STORE_CTRL_CH0_SET = PXP_DITHER_STORE_CTRL_CH0_SET_COMBINE_2CHANNEL_MASK;
+ }
+ else
+ {
+ base->DITHER_STORE_CTRL_CH0_CLR = PXP_DITHER_STORE_CTRL_CH0_SET_COMBINE_2CHANNEL_MASK;
+ }
+ }
+}
+/* @} */
+
+/*!
+ * @name Pre-dither CFA engine
+ * @{
+ */
+/*!
+ * @brief Configures the pre-dither CFA engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param config pointer to the configuration structure.
+ * @retval kStatus_Success Successfully configured the engine.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetCfaConfig(PXP_Type *base, const pxp_cfa_config_t *config);
+
+/*!
+ * @brief Enables/disables the CFA block.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable true to enable, false to disable.
+ */
+static inline void PXP_EnableCfa(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CFA_CTRL_CLR = PXP_CFA_CTRL_CFA_BYPASS_MASK;
+ }
+ else
+ {
+ base->CFA_CTRL_SET = PXP_CFA_CTRL_CFA_BYPASS_MASK;
+ }
+}
+/* @} */
+
+/*!
+ * @name Histogram engine
+ * @{
+ */
+/*!
+ * @brief Configures histogram engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @param config pointer to the configuration structure.
+ * @retval kStatus_Success Successfully configured the engine.
+ * @retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_SetHistogramConfig(PXP_Type *base, uint8_t num, const pxp_histogram_config_t *config);
+
+/*!
+ * @brief Enables/disables the histogram engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @param enable true to enable, false to disable.
+ */
+static inline void PXP_EnableHistogram(PXP_Type *base, uint8_t num, bool enable)
+{
+ switch (num)
+ {
+ case 0:
+ base->HIST_A_CTRL =
+ (base->HIST_A_CTRL & ~PXP_HIST_A_CTRL_ENABLE_MASK) | PXP_HIST_A_CTRL_ENABLE((uint32_t)enable);
+ break;
+
+ case 1:
+ base->HIST_B_CTRL =
+ (base->HIST_B_CTRL & ~PXP_HIST_B_CTRL_ENABLE_MASK) | PXP_HIST_B_CTRL_ENABLE((uint32_t)enable);
+ break;
+
+ default:
+ /* Only 2 instances are supported per fetch engine. */
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Gets the results of histogram mask operation.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @param result pointer to the result structure.
+ */
+void PXP_GetHistogramMaskResult(PXP_Type *base, uint8_t num, pxp_histogram_mask_result_t *result);
+
+/*!
+ * @brief Gets the PXP Histogram operation result
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @return bit map of the match result in @ref _pxp_histgram_flags ORed together
+ */
+static inline uint8_t PXP_GetHistogramMatchResult(PXP_Type *base, uint8_t num)
+{
+ uint8_t result = 0U;
+ switch (num)
+ {
+ case 0:
+ result = (uint8_t)((base->HIST_A_CTRL & PXP_HIST_A_CTRL_STATUS_MASK) >> PXP_HIST_A_CTRL_STATUS_SHIFT);
+ break;
+
+ case 1:
+ result = (uint8_t)((base->HIST_B_CTRL & PXP_HIST_B_CTRL_STATUS_MASK) >> PXP_HIST_B_CTRL_STATUS_SHIFT);
+ break;
+
+ default:
+ /* Only 2 histogram instances are supported. */
+ assert(false);
+ break;
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Clears the current histogram operation result.
+ *
+ * Clears the current histogram operation result, including mask operation result and from 2-level to 32-level match
+ * result.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ */
+static inline void PXP_ClearHistogramResult(PXP_Type *base, uint8_t num)
+{
+ switch (num)
+ {
+ case 0:
+ base->HIST_A_CTRL |= PXP_HIST_A_CTRL_CLEAR_MASK;
+ break;
+
+ case 1:
+ base->HIST_B_CTRL |= PXP_HIST_B_CTRL_CLEAR_MASK;
+ break;
+
+ default:
+ /* Only 2 histogram instances are supported. */
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Gets the results of histogram mask operation.
+ *
+ * @param base PXP peripheral base address.
+ * @param num instance number.
+ * @param width the width of the updated block
+ * @param height the height of the updated block
+ */
+static inline void PXP_SetHistogramSize(PXP_Type *base, uint8_t num, uint16_t width, uint16_t height)
+{
+ switch (num)
+ {
+ case 0:
+ base->HIST_A_BUF_SIZE = ((uint32_t)height << 16U) | (uint32_t)width;
+ break;
+
+ case 1:
+ base->HIST_B_BUF_SIZE = ((uint32_t)height << 16U) | (uint32_t)width;
+ break;
+
+ default:
+ /* Only 2 histogram instances are supported. */
+ assert(false);
+ break;
+ }
+}
+/* @} */
+
+/*!
+ * @name WFE engine
+ * @{
+ */
+
+/*!
+ * @brief Initializes the WFE-A engine for waveform process.
+ *
+ * @param base PXP peripheral base address.
+ * @param ditherHandshake true to enable handshake mode with upstream dither store engine.
+ */
+void PXP_WfeaInit(PXP_Type *base, bool ditherHandshake);
+
+/*!
+ * @brief Enables/disables hanshake mode with upstream dither engine.
+ *
+ * @param base PXP peripheral base address.
+ * @param enable true to enable handshake mode with upstream dither store engine.
+ */
+static inline void PXP_WfeaEnableDitherHandshake(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->WFA_FETCH_CTRL |= PXP_WFA_FETCH_CTRL_BF1_HSK_MODE_MASK;
+ }
+ else
+ {
+ base->WFA_FETCH_CTRL &= ~PXP_WFA_FETCH_CTRL_BF1_HSK_MODE_MASK;
+ }
+}
+
+/*!
+ * @brief Configure the WFE-A engine
+ *
+ * @param base PXP peripheral base address.
+ * @param config pointer to the configuration structure.
+ */
+void PXP_SetWfeaConfig(PXP_Type *base, const pxp_wfea_engine_config_t *config);
+
+/*!
+ * @brief Sets the LUT usage status for waveform engine.
+ *
+ * If any EPDC LUT(s) has been occupied, use this API to set its usage for PXP WFE-A.
+ *
+ * @param base PXP base pointer
+ * @param lutStatus the status mask of the LUT(s) to be set, can be a single flag or several flags up to all 64 LUTs.
+ * If user wants to set LUT17 usage, set bit 17 in the lutStatus.
+ */
+static inline void PXP_SetLutUsage(PXP_Type *base, uint64_t lutStatus)
+{
+ base->WFE_A_STG1_8X1_OUT0_0 |= (uint32_t)lutStatus;
+ base->WFE_A_STG1_8X1_OUT0_1 |= (uint32_t)(lutStatus >> 32U);
+}
+
+/*!
+ * @brief Clears the LUT usage status for waveform engine.
+ *
+ * If any EPDC LUT(s) has finished processing and is(are) free, use this API to clear its usage for PXP WFE-A.
+ *
+ * @param base PXP base pointer
+ * @param lutStatus the status mask of the LUT(s) to be cleared, can be a single flag or several flags up to all 64
+ * LUTs. If user wants to clear LUT17, set bit 17.
+ */
+static inline void PXP_ClearLutUsage(PXP_Type *base, uint64_t lutStatus)
+{
+ base->WFE_A_STG1_8X1_OUT0_0 &= ~(uint32_t)lutStatus;
+ base->WFE_A_STG1_8X1_OUT0_1 &= ~(uint32_t)(lutStatus >> 32U);
+}
+
+/*!
+ * @brief Gets the occupied LUT list.
+ *
+ * @param base PXP base pointer
+ * @return lutStatus the status mask of the LUT(s) that is(are) occupied
+ */
+static inline uint64_t PXP_GetLutUsage(PXP_Type *base)
+{
+ return ((uint64_t)base->WFE_A_STG1_8X1_OUT0_0 | (uint64_t)base->WFE_A_STG1_8X1_OUT0_1 << 32U);
+}
+
+/* @} */
+
+#endif /* FSL_FEATURE_PXP_V3 */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PXP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.c b/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.c
new file mode 100644
index 0000000000..33271d6e9a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.c
@@ -0,0 +1,777 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_qtmr.h"
+#ifdef __rtems__
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <libfdt.h>
+#endif /* __rtems__ */
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.qtmr"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base Quad Timer peripheral base address
+ *
+ * @return The Quad Timer instance
+ */
+static uint32_t QTMR_GetInstance(TMR_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to Quad Timer bases for each instance. */
+static TMR_Type *const s_qtmrBases[] = TMR_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to Quad Timer clocks for each instance. */
+static const clock_ip_name_t s_qtmrClocks[] = TMR_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+static uint8_t s_qtmrGetPwmDutyCycle[FSL_FEATURE_SOC_TMR_COUNT] = {0U};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t QTMR_GetInstance(TMR_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_qtmrBases); instance++)
+ {
+ if (s_qtmrBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_qtmrBases));
+
+ return instance;
+}
+
+#ifdef __rtems__
+TMR_Type *QTMR_get_regs_from_fdt(const void *fdt, int node)
+{
+ int rv;
+ TMR_Type *regs;
+
+ rv = fdt_node_check_compatible(fdt, node, "nxp,imxrt-qtimer");
+ if (rv != 0) {
+ return NULL;
+ }
+ regs = imx_get_reg_of_node(fdt, node);
+ return regs;
+}
+
+rtems_vector_number QTMR_get_IRQ_from_fdt(const void *fdt, int node)
+{
+ int rv;
+ rtems_vector_number irq;
+
+ rv = fdt_node_check_compatible(fdt, node, "nxp,imxrt-qtimer");
+ if (rv != 0) {
+ return BSP_INTERRUPT_VECTOR_INVALID;
+ }
+ irq = imx_get_irq_of_node(fdt, node, 0);
+ return irq;
+}
+
+uint32_t QTMR_get_src_clk(TMR_Type *base)
+{
+#if IMXRT_IS_MIMXRT10xx
+ (void) base;
+
+ return CLOCK_GetFreq(kCLOCK_IpgClk);
+#elif IMXRT_IS_MIMXRT11xx
+ (void) base;
+
+ return CLOCK_GetRootClockFreq(kCLOCK_Root_Bus);
+#else
+ #error Getting Timer clock frequency is not implemented for this chip
+#endif
+}
+
+#endif /* __rtems__ */
+/*!
+ * brief Ungates the Quad Timer clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the Quad Timer driver.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param config Pointer to user's Quad Timer config structure
+ */
+void QTMR_Init(TMR_Type *base, qtmr_channel_selection_t channel, const qtmr_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the module clock */
+ CLOCK_EnableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Setup the counter sources */
+ base->CHANNEL[channel].CTRL = (TMR_CTRL_PCS(config->primarySource) | TMR_CTRL_SCS(config->secondarySource));
+
+ /* Setup the master mode operation */
+ base->CHANNEL[channel].SCTRL =
+ (TMR_SCTRL_EEOF(config->enableExternalForce) | TMR_SCTRL_MSTR(config->enableMasterMode));
+
+ /* Setup debug mode */
+ base->CHANNEL[channel].CSCTRL = TMR_CSCTRL_DBG_EN(config->debugMode);
+
+ base->CHANNEL[channel].FILT &= (uint16_t)(~(TMR_FILT_FILT_CNT_MASK | TMR_FILT_FILT_PER_MASK));
+ /* Setup input filter */
+ base->CHANNEL[channel].FILT =
+ (TMR_FILT_FILT_CNT(config->faultFilterCount) | TMR_FILT_FILT_PER(config->faultFilterPeriod));
+}
+
+/*!
+ * brief Stops the counter and gates the Quad Timer clock
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ */
+void QTMR_Deinit(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ /* Stop the counter */
+ base->CHANNEL[channel].CTRL &= (uint16_t)(~TMR_CTRL_CM_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the module clock */
+ CLOCK_DisableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fill in the Quad Timer config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->debugMode = kQTMR_RunNormalInDebug;
+ * config->enableExternalForce = false;
+ * config->enableMasterMode = false;
+ * config->faultFilterCount = 0;
+ * config->faultFilterPeriod = 0;
+ * config->primarySource = kQTMR_ClockDivide_2;
+ * config->secondarySource = kQTMR_Counter0InputPin;
+ * endcode
+ * param config Pointer to user's Quad Timer config structure.
+ */
+void QTMR_GetDefaultConfig(qtmr_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Halt counter during debug mode */
+ config->debugMode = kQTMR_RunNormalInDebug;
+ /* Another counter cannot force state of OFLAG signal */
+ config->enableExternalForce = false;
+ /* Compare function's output from this counter is not broadcast to other counters */
+ config->enableMasterMode = false;
+ /* Fault filter count is set to 0 */
+ config->faultFilterCount = 0;
+ /* Fault filter period is set to 0 which disables the fault filter */
+ config->faultFilterPeriod = 0;
+ /* Primary count source is IP bus clock divide by 2 */
+ config->primarySource = kQTMR_ClockDivide_2;
+ /* Secondary count source is counter 0 input pin */
+ config->secondarySource = kQTMR_Counter0InputPin;
+}
+
+/*!
+ * brief Sets up Quad timer module for PWM signal output.
+ *
+ * The function initializes the timer module according to the parameters passed in by the user. The
+ * function also sets up the value compare registers to match the PWM signal requirements.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param pwmFreqHz PWM signal frequency in Hz
+ * param dutyCyclePercent PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ * param outputPolarity true: invert polarity of the output signal, false: no inversion
+ * param srcClock_Hz Main counter clock in Hz.
+ *
+ * return Returns an error if there was error setting up the signal.
+ */
+status_t QTMR_SetupPwm(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ uint32_t pwmFreqHz,
+ uint8_t dutyCyclePercent,
+ bool outputPolarity,
+ uint32_t srcClock_Hz)
+{
+ uint32_t periodCount, highCount, lowCount;
+ uint16_t reg;
+ status_t status;
+
+ if (dutyCyclePercent <= 100U)
+ {
+ /* Set OFLAG pin for output mode and force out a low on the pin */
+ base->CHANNEL[channel].SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK);
+
+ /* Counter values to generate a PWM signal */
+ periodCount = srcClock_Hz / pwmFreqHz;
+ highCount = periodCount * dutyCyclePercent / 100U;
+ lowCount = periodCount - highCount;
+
+ if (highCount > 0U)
+ {
+ highCount -= 1U;
+ }
+ if (lowCount > 0U)
+ {
+ lowCount -= 1U;
+ }
+
+ if ((highCount > 0xFFFFU) || (lowCount > 0xFFFFU))
+ {
+ /* This should not be a 16-bit overflow value. If it is, change to a larger divider for clock source. */
+ return kStatus_Fail;
+ }
+
+ /* Setup the compare registers for PWM output */
+ base->CHANNEL[channel].COMP1 = (uint16_t)lowCount;
+ base->CHANNEL[channel].COMP2 = (uint16_t)highCount;
+
+ /* Setup the pre-load registers for PWM output */
+ base->CHANNEL[channel].CMPLD1 = (uint16_t)lowCount;
+ base->CHANNEL[channel].CMPLD2 = (uint16_t)highCount;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Setup the compare load control for COMP1 and COMP2.
+ * Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted
+ */
+ reg &= (uint16_t)(~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK));
+ reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
+ base->CHANNEL[channel].CSCTRL = reg;
+
+ if (outputPolarity)
+ {
+ /* Invert the polarity */
+ base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK;
+ }
+ else
+ {
+ /* True polarity, no inversion */
+ base->CHANNEL[channel].SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK;
+ }
+
+ reg = base->CHANNEL[channel].CTRL;
+ reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK;
+ if (dutyCyclePercent == 100U)
+ {
+ /* Set OFLAG output on compare */
+ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_SetOnCompare));
+ }
+ else if (dutyCyclePercent == 0U)
+ {
+ /* Clear OFLAG output on compare */
+ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ClearOnCompare));
+ }
+ else
+ {
+ /* Toggle OFLAG output using alternating compare register */
+ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg));
+ }
+
+ base->CHANNEL[channel].CTRL = reg;
+
+ /* Get pwm duty cycle */
+ s_qtmrGetPwmDutyCycle[channel] = dutyCyclePercent;
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Invalid dutycycle */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Allows the user to count the source clock cycles until a capture event arrives.
+ *
+ * The count is stored in the capture register.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param capturePin Pin through which we receive the input signal to trigger the capture
+ * param inputPolarity true: invert polarity of the input signal, false: no inversion
+ * param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload
+ * param captureMode Specifies which edge of the input signal triggers a capture
+ */
+void QTMR_SetupInputCapture(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ qtmr_input_source_t capturePin,
+ bool inputPolarity,
+ bool reloadOnCapture,
+ qtmr_input_capture_edge_t captureMode)
+{
+ uint16_t reg;
+
+ /* Clear the prior value for the input source for capture */
+ reg = base->CHANNEL[channel].CTRL & (uint16_t)(~TMR_CTRL_SCS_MASK);
+
+ /* Set the new input source */
+ reg |= TMR_CTRL_SCS(capturePin);
+ base->CHANNEL[channel].CTRL = reg;
+
+ /* Clear the prior values for input polarity, capture mode. Set the external pin as input */
+ reg = base->CHANNEL[channel].SCTRL &
+ (uint16_t)(~(TMR_SCTRL_IPS_MASK | TMR_SCTRL_CAPTURE_MODE_MASK | TMR_SCTRL_OEN_MASK));
+ /* Set the new values */
+ reg |= (TMR_SCTRL_IPS(inputPolarity) | TMR_SCTRL_CAPTURE_MODE(captureMode));
+ base->CHANNEL[channel].SCTRL = reg;
+
+ /* Setup if counter should reload when a capture occurs */
+ if (reloadOnCapture)
+ {
+ base->CHANNEL[channel].CSCTRL |= TMR_CSCTRL_ROC_MASK;
+ }
+ else
+ {
+ base->CHANNEL[channel].CSCTRL &= (uint16_t)(~TMR_CSCTRL_ROC_MASK);
+ }
+}
+
+/*!
+ * brief Enables the selected Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_EnableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL)
+ {
+ reg |= TMR_SCTRL_TCFIE_MASK;
+ }
+ /* Overflow interrupt */
+ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL)
+ {
+ reg |= TMR_SCTRL_TOFIE_MASK;
+ }
+ /* Input edge interrupt */
+ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL)
+ {
+ /* Restriction: Do not set both SCTRL[IEFIE] and DMA[IEFDE] */
+ base->CHANNEL[channel].DMA &= ~(uint16_t)TMR_DMA_IEFDE_MASK;
+ reg |= TMR_SCTRL_IEFIE_MASK;
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL)
+ {
+ reg |= TMR_CSCTRL_TCF1EN_MASK;
+ }
+ /* Compare 2 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL)
+ {
+ reg |= TMR_CSCTRL_TCF2EN_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Disables the selected Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base addres
+ * param channel Quad Timer channel number
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_DisableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TCFIE_MASK);
+ }
+ /* Overflow interrupt */
+ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TOFIE_MASK);
+ }
+ /* Input edge interrupt */
+ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK);
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF1EN_MASK;
+ }
+ /* Compare 2 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF2EN_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Gets the enabled Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ uint32_t enabledInterrupts = 0;
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((reg & TMR_SCTRL_TCFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_CompareFlag;
+ }
+ /* Overflow interrupt */
+ if ((reg & TMR_SCTRL_TOFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_OverflowInterruptEnable;
+ }
+ /* Input edge interrupt */
+ if ((reg & TMR_SCTRL_IEFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_EdgeInterruptEnable;
+ }
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((reg & TMR_CSCTRL_TCF1EN_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_Compare1InterruptEnable;
+ }
+ /* Compare 2 interrupt */
+ if ((reg & TMR_CSCTRL_TCF2EN_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_Compare2InterruptEnable;
+ }
+
+ return enabledInterrupts;
+}
+
+/*!
+ * brief Gets the Quad Timer status flags
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+uint32_t QTMR_GetStatus(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ uint32_t statusFlags = 0;
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Timer compare flag */
+ if ((reg & TMR_SCTRL_TCF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_CompareFlag;
+ }
+ /* Timer overflow flag */
+ if ((reg & TMR_SCTRL_TOF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_OverflowFlag;
+ }
+ /* Input edge flag */
+ if ((reg & TMR_SCTRL_IEF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_EdgeFlag;
+ }
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 flag */
+ if ((reg & TMR_CSCTRL_TCF1_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_Compare1Flag;
+ }
+ /* Compare 2 flag */
+ if ((reg & TMR_CSCTRL_TCF2_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_Compare2Flag;
+ }
+
+ return statusFlags;
+}
+
+/*!
+ * brief Clears the Quad Timer status flags.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+void QTMR_ClearStatusFlags(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Timer compare flag */
+ if ((mask & (uint32_t)kQTMR_CompareFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TCF_MASK);
+ }
+ /* Timer overflow flag */
+ if ((mask & (uint32_t)kQTMR_OverflowFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TOF_MASK);
+ }
+ /* Input edge flag */
+ if ((mask & (uint32_t)kQTMR_EdgeFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_IEF_MASK);
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 flag */
+ if ((mask & (uint32_t)kQTMR_Compare1Flag) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF1_MASK;
+ }
+ /* Compare 2 flag */
+ if ((mask & (uint32_t)kQTMR_Compare2Flag) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF2_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Sets the timer period in ticks.
+ *
+ * Timers counts from initial value till it equals the count value set here. The counter
+ * will then reinitialize to the value specified in the Load register.
+ *
+ * note
+ * 1. This function will write the time period in ticks to COMP1 or COMP2 register
+ * depending on the count direction
+ * 2. User can call the utility macros provided in fsl_common.h to convert to ticks
+ * 3. This function supports cases, providing only primary source clock without secondary source clock.
+ * 4. The load register is reset before the counter is reinitialized to the value
+ specified in the load register.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param ticks Timer period in units of ticks
+ */
+void QTMR_SetTimerPeriod(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks)
+{
+ /* Set the length bit to reinitialize the counters on a match */
+ base->CHANNEL[channel].CTRL |= TMR_CTRL_LENGTH_MASK;
+
+ /* Reset LOAD register to reinitialize the counters */
+ base->CHANNEL[channel].LOAD &= (uint16_t)(~TMR_LOAD_LOAD_MASK);
+
+ if ((base->CHANNEL[channel].CTRL & TMR_CTRL_DIR_MASK) != 0U)
+ {
+ /* Counting down */
+ base->CHANNEL[channel].COMP2 = ticks - 1U;
+ }
+ else
+ {
+ /* Counting up */
+ base->CHANNEL[channel].COMP1 = ticks - 1U;
+ }
+}
+
+/*!
+ * brief Set compare value.
+ *
+ * This function sets the value used for comparison with the counter value.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param ticks Timer period in units of ticks.
+ */
+void QTMR_SetCompareValue(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks)
+{
+ base->CHANNEL[channel].CTRL |= TMR_CTRL_LENGTH_MASK;
+
+ if ((base->CHANNEL[channel].CTRL & TMR_CTRL_DIR_MASK) != 0U)
+ {
+ /* Counting down */
+ base->CHANNEL[channel].COMP2 = ticks;
+ }
+ else
+ {
+ /* Counting up */
+ base->CHANNEL[channel].COMP1 = ticks;
+ }
+}
+
+/*!
+ * brief Enable the Quad Timer DMA.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_EnableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].DMA;
+ /* Input Edge Flag DMA Enable */
+ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U)
+ {
+ /* Restriction: Do not set both DMA[IEFDE] and SCTRL[IEFIE] */
+ base->CHANNEL[channel].SCTRL &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK);
+ reg |= TMR_DMA_IEFDE_MASK;
+ }
+ /* Comparator Preload Register 1 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U)
+ {
+ reg |= TMR_DMA_CMPLD1DE_MASK;
+ }
+ /* Comparator Preload Register 2 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U)
+ {
+ reg |= TMR_DMA_CMPLD2DE_MASK;
+ }
+ base->CHANNEL[channel].DMA = reg;
+}
+
+/*!
+ * brief Disable the Quad Timer DMA.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_DisableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].DMA;
+ /* Input Edge Flag DMA Enable */
+ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_IEFDE_MASK;
+ }
+ /* Comparator Preload Register 1 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_CMPLD1DE_MASK;
+ }
+ /* Comparator Preload Register 2 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_CMPLD2DE_MASK;
+ }
+ base->CHANNEL[channel].DMA = reg;
+}
+
+/*!
+ * brief Set PWM output in idle status (high or low).
+ *
+ * Note: When the PWM is set again, the counting needs to be restarted.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param idleStatus True: PWM output is high in idle status; false: PWM output is low in idle status.
+ */
+void QTMR_SetPwmOutputToIdle(TMR_Type *base, qtmr_channel_selection_t channel, bool idleStatus)
+{
+ uint16_t reg = base->CHANNEL[channel].SCTRL;
+
+ /* Stop qtimer channel counter first */
+ base->CHANNEL[channel].CTRL &= (uint16_t)(~TMR_CTRL_CM_MASK);
+ /* Clear count value */
+ base->CHANNEL[channel].CNTR = 0U;
+
+ if (0U != (reg & ((uint16_t)TMR_SCTRL_OPS_MASK)))
+ {
+ /* Inverted polarity. */
+ reg |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_VAL(!idleStatus));
+ }
+ else
+ {
+ /* True polarity. */
+ reg |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_VAL(idleStatus));
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ s_qtmrGetPwmDutyCycle[channel] = 0x0;
+}
+
+/*!
+ * brief Get the PWM channel dutycycle value.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ *
+ * return Current channel dutycycle value.
+ */
+uint8_t QTMR_GetPwmChannelStatus(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ return s_qtmrGetPwmDutyCycle[channel];
+}
+
+/*!
+ * brief This function set the value of the prescaler on QTimer channels.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param prescaler Set prescaler value
+ */
+void QTMR_SetPwmClockMode(TMR_Type *base, qtmr_channel_selection_t channel, qtmr_primary_count_source_t prescaler)
+{
+ assert((uint32_t)prescaler > 7U);
+
+ uint16_t reg = base->CHANNEL[channel].CTRL;
+
+ /* Clear qtimer channel counter mode */
+ base->CHANNEL[channel].CTRL = reg & (uint16_t)(~TMR_CTRL_CM_MASK);
+
+ /* Set the new clock prescaler value and restore qtimer channel counter mode*/
+ reg &= (uint16_t)(~(TMR_CTRL_PCS_MASK));
+ reg |= TMR_CTRL_PCS(prescaler);
+ base->CHANNEL[channel].CTRL = reg;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.h b/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.h
new file mode 100644
index 0000000000..0b45dace35
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/qtmr_1/fsl_qtmr.h
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_QTMR_H_
+#define _FSL_QTMR_H_
+
+#include "fsl_common.h"
+#ifdef __rtems__
+#include <rtems.h>
+#endif /* __rtems__ */
+
+/*!
+ * @addtogroup qtmr
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#ifndef TMR_CSCTRL_OFLAG_MASK
+#define TMR_CSCTRL_OFLAG_MASK (0x100UL)
+#endif
+
+#ifndef TMR_CSCTRL_OFLAG_SHIFT
+#define TMR_CSCTRL_OFLAG_SHIFT (8UL)
+#endif
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_QTMR_DRIVER_VERSION (MAKE_VERSION(2, 2, 1)) /*!< Version */
+/*@}*/
+
+/*! @brief Quad Timer primary clock source selection*/
+typedef enum _qtmr_primary_count_source
+{
+ kQTMR_ClockCounter0InputPin = 0, /*!< Use counter 0 input pin */
+ kQTMR_ClockCounter1InputPin, /*!< Use counter 1 input pin */
+ kQTMR_ClockCounter2InputPin, /*!< Use counter 2 input pin */
+ kQTMR_ClockCounter3InputPin, /*!< Use counter 3 input pin */
+ kQTMR_ClockCounter0Output, /*!< Use counter 0 output */
+ kQTMR_ClockCounter1Output, /*!< Use counter 1 output */
+ kQTMR_ClockCounter2Output, /*!< Use counter 2 output */
+ kQTMR_ClockCounter3Output, /*!< Use counter 3 output */
+ kQTMR_ClockDivide_1, /*!< IP bus clock divide by 1 prescaler */
+ kQTMR_ClockDivide_2, /*!< IP bus clock divide by 2 prescaler */
+ kQTMR_ClockDivide_4, /*!< IP bus clock divide by 4 prescaler */
+ kQTMR_ClockDivide_8, /*!< IP bus clock divide by 8 prescaler */
+ kQTMR_ClockDivide_16, /*!< IP bus clock divide by 16 prescaler */
+ kQTMR_ClockDivide_32, /*!< IP bus clock divide by 32 prescaler */
+ kQTMR_ClockDivide_64, /*!< IP bus clock divide by 64 prescaler */
+ kQTMR_ClockDivide_128 /*!< IP bus clock divide by 128 prescaler */
+} qtmr_primary_count_source_t;
+
+/*! @brief Quad Timer input sources selection*/
+typedef enum _qtmr_input_source
+{
+ kQTMR_Counter0InputPin = 0, /*!< Use counter 0 input pin */
+ kQTMR_Counter1InputPin, /*!< Use counter 1 input pin */
+ kQTMR_Counter2InputPin, /*!< Use counter 2 input pin */
+ kQTMR_Counter3InputPin /*!< Use counter 3 input pin */
+} qtmr_input_source_t;
+
+/*! @brief Quad Timer counting mode selection */
+typedef enum _qtmr_counting_mode
+{
+ kQTMR_NoOperation = 0, /*!< No operation */
+ kQTMR_PriSrcRiseEdge, /*!< Count rising edges of primary source */
+ kQTMR_PriSrcRiseAndFallEdge, /*!< Count rising and falling edges of primary source */
+ kQTMR_PriSrcRiseEdgeSecInpHigh, /*!< Count rise edges of pri SRC while sec inp high active */
+ kQTMR_QuadCountMode, /*!< Quadrature count mode, uses pri and sec sources */
+ kQTMR_PriSrcRiseEdgeSecDir, /*!< Count rising edges of pri SRC; sec SRC specifies dir */
+ kQTMR_SecSrcTrigPriCnt, /*!< Edge of sec SRC trigger primary count until compare*/
+ kQTMR_CascadeCount /*!< Cascaded count mode (up/down) */
+} qtmr_counting_mode_t;
+
+/*! @brief Quad Timer PWM output state */
+typedef enum _qtmr_pwm_out_state
+{
+ kQTMR_PwmLow = 0, /*!< The output state of PWM channel is low */
+ kQTMR_PwmHigh, /*!< The output state of PWM channel is low */
+} qtmr_pwm_out_state_t;
+
+/*! @brief Quad Timer output mode selection*/
+typedef enum _qtmr_output_mode
+{
+ kQTMR_AssertWhenCountActive = 0, /*!< Assert OFLAG while counter is active*/
+ kQTMR_ClearOnCompare, /*!< Clear OFLAG on successful compare */
+ kQTMR_SetOnCompare, /*!< Set OFLAG on successful compare */
+ kQTMR_ToggleOnCompare, /*!< Toggle OFLAG on successful compare */
+ kQTMR_ToggleOnAltCompareReg, /*!< Toggle OFLAG using alternating compare registers */
+ kQTMR_SetOnCompareClearOnSecSrcInp, /*!< Set OFLAG on compare, clear on sec SRC input edge */
+ kQTMR_SetOnCompareClearOnCountRoll, /*!< Set OFLAG on compare, clear on counter rollover */
+ kQTMR_EnableGateClock /*!< Enable gated clock output while count is active */
+} qtmr_output_mode_t;
+
+/*! @brief Quad Timer input capture edge mode, rising edge, or falling edge */
+typedef enum _qtmr_input_capture_edge
+{
+ kQTMR_NoCapture = 0, /*!< Capture is disabled */
+ kQTMR_RisingEdge, /*!< Capture on rising edge (IPS=0) or falling edge (IPS=1)*/
+ kQTMR_FallingEdge, /*!< Capture on falling edge (IPS=0) or rising edge (IPS=1)*/
+ kQTMR_RisingAndFallingEdge /*!< Capture on both edges */
+} qtmr_input_capture_edge_t;
+
+/*! @brief Quad Timer input capture edge mode, rising edge, or falling edge */
+typedef enum _qtmr_preload_control
+{
+ kQTMR_NoPreload = 0, /*!< Never preload */
+ kQTMR_LoadOnComp1, /*!< Load upon successful compare with value in COMP1 */
+ kQTMR_LoadOnComp2 /*!< Load upon successful compare with value in COMP2*/
+} qtmr_preload_control_t;
+
+/*! @brief List of Quad Timer run options when in Debug mode */
+typedef enum _qtmr_debug_action
+{
+ kQTMR_RunNormalInDebug = 0U, /*!< Continue with normal operation */
+ kQTMR_HaltCounter, /*!< Halt counter */
+ kQTMR_ForceOutToZero, /*!< Force output to logic 0 */
+ kQTMR_HaltCountForceOutZero /*!< Halt counter and force output to logic 0 */
+} qtmr_debug_action_t;
+
+/*! @brief List of Quad Timer interrupts */
+// typedef enum _qtmr_interrupt_enable
+typedef enum _qtmr_interrupt_enable
+{
+ kQTMR_CompareInterruptEnable = (1U << 0), /*!< Compare interrupt.*/
+ kQTMR_Compare1InterruptEnable = (1U << 1), /*!< Compare 1 interrupt.*/
+ kQTMR_Compare2InterruptEnable = (1U << 2), /*!< Compare 2 interrupt.*/
+ kQTMR_OverflowInterruptEnable = (1U << 3), /*!< Timer overflow interrupt.*/
+ kQTMR_EdgeInterruptEnable = (1U << 4) /*!< Input edge interrupt.*/
+} qtmr_interrupt_enable_t;
+
+/*! @brief List of Quad Timer flags */
+typedef enum _qtmr_status_flags
+{
+ kQTMR_CompareFlag = (1U << 0), /*!< Compare flag */
+ kQTMR_Compare1Flag = (1U << 1), /*!< Compare 1 flag */
+ kQTMR_Compare2Flag = (1U << 2), /*!< Compare 2 flag */
+ kQTMR_OverflowFlag = (1U << 3), /*!< Timer overflow flag */
+ kQTMR_EdgeFlag = (1U << 4) /*!< Input edge flag */
+} qtmr_status_flags_t;
+
+/*! @brief List of channel selection */
+typedef enum _qtmr_channel_selection
+{
+ kQTMR_Channel_0 = 0U, /*!< TMR Channel 0 */
+ kQTMR_Channel_1, /*!< TMR Channel 1 */
+ kQTMR_Channel_2, /*!< TMR Channel 2 */
+ kQTMR_Channel_3, /*!< TMR Channel 3 */
+} qtmr_channel_selection_t;
+
+/*! @brief List of Quad Timer DMA enable */
+typedef enum _qtmr_dma_enable
+{
+ kQTMR_InputEdgeFlagDmaEnable = (1U << 0), /*!< Input Edge Flag DMA Enable.*/
+ kQTMR_ComparatorPreload1DmaEnable = (1U << 1), /*!< Comparator Preload Register 1 DMA Enable.*/
+ kQTMR_ComparatorPreload2DmaEnable = (1U << 2), /*!< Comparator Preload Register 2 DMA Enable.*/
+} qtmr_dma_enable_t;
+
+/*!
+ * @brief Quad Timer config structure
+ *
+ * This structure holds the configuration settings for the Quad Timer peripheral. To initialize this
+ * structure to reasonable defaults, call the QTMR_GetDefaultConfig() function and pass a
+ * pointer to your config structure instance.
+ *
+ * The config struct can be made const so it resides in flash
+ */
+typedef struct _qtmr_config
+{
+ qtmr_primary_count_source_t primarySource; /*!< Specify the primary count source */
+ qtmr_input_source_t secondarySource; /*!< Specify the secondary count source */
+ bool enableMasterMode; /*!< true: Broadcast compare function output to other counters;
+ false no broadcast */
+ bool enableExternalForce; /*!< true: Compare from another counter force state of OFLAG signal
+ false: OFLAG controlled by local counter */
+ uint8_t faultFilterCount; /*!< Fault filter count */
+ uint8_t faultFilterPeriod; /*!< Fault filter period;value of 0 will bypass the filter */
+ qtmr_debug_action_t debugMode; /*!< Operation in Debug mode */
+} qtmr_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+#ifdef __rtems__
+/*!
+ * @brief Return the timer base based on a FDT node.
+ *
+ * @param fdt Pointer to the fdt
+ * @param node The FDT node
+ *
+ * @return Pointer to the timer. NULL on error (for example if node isn't
+ * compatible).
+ */
+TMR_Type *QTMR_get_regs_from_fdt(const void *fdt, int node);
+
+/*!
+ * @brief Return the timer IRQ vector based on a FDT node.
+ *
+ * @param fdt Pointer to the fdt
+ * @param node The FDT node
+ *
+ * @return IRQ vector number. BSP_INTERRUPT_VECTOR_INVALID on error.
+ */
+rtems_vector_number QTMR_get_IRQ_from_fdt(const void *fdt, int node);
+
+/*!
+ * @brief Return the clock source frequency of the quad timer.
+ *
+ * @param base Quad Timer peripheral base address.
+ *
+ * @return Clock frequency value in hertz.
+ */
+uint32_t QTMR_get_src_clk(TMR_Type *base);
+#endif /* __rtems__ */
+
+/*!
+ * @brief Ungates the Quad Timer clock and configures the peripheral for basic operation.
+ *
+ * @note This API should be called at the beginning of the application using the Quad Timer driver.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param config Pointer to user's Quad Timer config structure
+ */
+void QTMR_Init(TMR_Type *base, qtmr_channel_selection_t channel, const qtmr_config_t *config);
+
+/*!
+ * @brief Stops the counter and gates the Quad Timer clock
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ */
+void QTMR_Deinit(TMR_Type *base, qtmr_channel_selection_t channel);
+
+/*!
+ * @brief Fill in the Quad Timer config struct with the default settings
+ *
+ * The default values are:
+ * @code
+ * config->debugMode = kQTMR_RunNormalInDebug;
+ * config->enableExternalForce = false;
+ * config->enableMasterMode = false;
+ * config->faultFilterCount = 0;
+ * config->faultFilterPeriod = 0;
+ * config->primarySource = kQTMR_ClockDivide_2;
+ * config->secondarySource = kQTMR_Counter0InputPin;
+ * @endcode
+ * @param config Pointer to user's Quad Timer config structure.
+ */
+void QTMR_GetDefaultConfig(qtmr_config_t *config);
+
+/*! @}*/
+
+/*!
+ * @brief Sets up Quad timer module for PWM signal output.
+ *
+ * The function initializes the timer module according to the parameters passed in by the user. The
+ * function also sets up the value compare registers to match the PWM signal requirements.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param pwmFreqHz PWM signal frequency in Hz
+ * @param dutyCyclePercent PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ * @param outputPolarity true: invert polarity of the output signal, false: no inversion
+ * @param srcClock_Hz Main counter clock in Hz.
+ *
+ * @return Returns an error if there was error setting up the signal.
+ */
+status_t QTMR_SetupPwm(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ uint32_t pwmFreqHz,
+ uint8_t dutyCyclePercent,
+ bool outputPolarity,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Allows the user to count the source clock cycles until a capture event arrives.
+ *
+ * The count is stored in the capture register.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param capturePin Pin through which we receive the input signal to trigger the capture
+ * @param inputPolarity true: invert polarity of the input signal, false: no inversion
+ * @param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload
+ * @param captureMode Specifies which edge of the input signal triggers a capture
+ */
+void QTMR_SetupInputCapture(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ qtmr_input_source_t capturePin,
+ bool inputPolarity,
+ bool reloadOnCapture,
+ qtmr_input_capture_edge_t captureMode);
+
+/*!
+ * @name Interrupt Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected Quad Timer interrupts
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_EnableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask);
+
+/*!
+ * @brief Disables the selected Quad Timer interrupts
+ *
+ * @param base Quad Timer peripheral base addres
+ * @param channel Quad Timer channel number
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_DisableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask);
+
+/*!
+ * @brief Gets the enabled Quad Timer interrupts
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base, qtmr_channel_selection_t channel);
+
+/*! @}*/
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Gets the Quad Timer status flags
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+uint32_t QTMR_GetStatus(TMR_Type *base, qtmr_channel_selection_t channel);
+
+/*!
+ * @brief Clears the Quad Timer status flags.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+void QTMR_ClearStatusFlags(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask);
+
+/*! @}*/
+
+/*!
+ * @name Read and Write the timer period
+ * @{
+ */
+
+/*!
+ * @brief Sets the timer period in ticks.
+ *
+ * Timers counts from initial value till it equals the count value set here. The counter
+ * will then reinitialize to the value specified in the Load register.
+ *
+ * @note
+ * 1. This function will write the time period in ticks to COMP1 or COMP2 register
+ * depending on the count direction
+ * 2. User can call the utility macros provided in fsl_common.h to convert to ticks
+ * 3. This function supports cases, providing only primary source clock without secondary source clock.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param ticks Timer period in units of ticks
+ */
+void QTMR_SetTimerPeriod(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks);
+
+/*!
+ * @brief Set compare value.
+ *
+ * This function sets the value used for comparison with the counter value.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param ticks Timer period in units of ticks.
+ */
+void QTMR_SetCompareValue(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks);
+
+/*!
+ * @brief Set load value.
+ *
+ * This function sets the value used to initialize the counter after a counter comparison.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param value Load register initialization value.
+ */
+static inline void QTMR_SetLoadValue(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t value)
+{
+ base->CHANNEL[channel].LOAD &= (uint16_t)(~TMR_LOAD_LOAD_MASK);
+ base->CHANNEL[channel].LOAD = value;
+}
+
+/*!
+ * @brief Reads the current timer counting value.
+ *
+ * This function returns the real-time timer counting value, in a range from 0 to a
+ * timer period.
+ *
+ * @note User can call the utility macros provided in fsl_common.h to convert ticks to usec or msec
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ *
+ * @return Current counter value in ticks
+ */
+static inline uint16_t QTMR_GetCurrentTimerCount(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ return base->CHANNEL[channel].CNTR;
+}
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+
+/*!
+ * @brief Starts the Quad Timer counter.
+ *
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param clockSource Quad Timer clock source
+ */
+static inline void QTMR_StartTimer(TMR_Type *base, qtmr_channel_selection_t channel, qtmr_counting_mode_t clockSource)
+{
+ uint16_t reg = base->CHANNEL[channel].CTRL;
+
+ reg &= (uint16_t)(~(TMR_CTRL_CM_MASK));
+ reg |= TMR_CTRL_CM(clockSource);
+ base->CHANNEL[channel].CTRL = reg;
+}
+
+/*!
+ * @brief Stops the Quad Timer counter.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ */
+static inline void QTMR_StopTimer(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ base->CHANNEL[channel].CTRL &= (uint16_t)(~TMR_CTRL_CM_MASK);
+}
+
+/*! @}*/
+
+/*!
+ * @name Enable and Disable the Quad Timer DMA
+ * @{
+ */
+
+/*!
+ * @brief Enable the Quad Timer DMA.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_EnableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask);
+
+/*!
+ * @brief Disable the Quad Timer DMA.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_DisableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask);
+
+/*!
+ * @brief Set PWM output in idle status (high or low).
+ *
+ * @note When the PWM is set again, the counting needs to be restarted.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param idleStatus True: PWM output is high in idle status; false: PWM output is low in idle status.
+ */
+void QTMR_SetPwmOutputToIdle(TMR_Type *base, qtmr_channel_selection_t channel, bool idleStatus);
+
+/*!
+ * @brief Get the channel output status
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ *
+ * @return Current channel output status.
+ */
+static inline qtmr_pwm_out_state_t QTMR_GetPwmOutputStatus(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ if (0U != ((base->CHANNEL[channel].CSCTRL) & TMR_CSCTRL_OFLAG_MASK))
+ {
+ return kQTMR_PwmHigh;
+ }
+ else
+ {
+ return kQTMR_PwmLow;
+ }
+}
+
+/*!
+ * @brief Get the PWM channel dutycycle value.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ *
+ * @return Current channel dutycycle value.
+ */
+uint8_t QTMR_GetPwmChannelStatus(TMR_Type *base, qtmr_channel_selection_t channel);
+
+/*!
+ * @brief This function set the value of the prescaler on QTimer channels.
+ *
+ * @param base Quad Timer peripheral base address
+ * @param channel Quad Timer channel number
+ * @param prescaler Set prescaler value
+ */
+void QTMR_SetPwmClockMode(TMR_Type *base, qtmr_channel_selection_t channel, qtmr_primary_count_source_t prescaler);
+
+/*! @}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_QTMR_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.c b/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.c
new file mode 100644
index 0000000000..816770dbd7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_rdc.h"
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.rdc"
+#endif
+
+typedef union
+{
+ rdc_domain_assignment_t _mda;
+ uint32_t _u32;
+} rdc_mda_reg_t;
+
+typedef union
+{
+ rdc_hardware_config_t _vir;
+ uint32_t _u32;
+} rdc_vir_reg_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for RDC module.
+ *
+ * @param base RDC peripheral base address.
+ */
+uint32_t RDC_GetInstance(RDC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to rdc bases for each instance. */
+static RDC_Type *const s_rdcBases[] = RDC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to rdc clocks for each instance. */
+static const clock_ip_name_t s_rdcClocks[] = RDC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/******************************************************************************
+ * CODE
+ *****************************************************************************/
+
+uint32_t RDC_GetInstance(RDC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_rdcBases); instance++)
+ {
+ if (s_rdcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_rdcBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the RDC module.
+ *
+ * This function enables the RDC clock.
+ *
+ * param base RDC peripheral base address.
+ */
+void RDC_Init(RDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_rdcClocks[RDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief De-initializes the RDC module.
+ *
+ * This function disables the RDC clock.
+ *
+ * param base RDC peripheral base address.
+ */
+void RDC_Deinit(RDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_rdcClocks[RDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the RDC hardware configuration.
+ *
+ * This function gets the RDC hardware configurations, including number of bus
+ * masters, number of domains, number of memory regions and number of peripherals.
+ *
+ * param base RDC peripheral base address.
+ * param config Pointer to the structure to get the configuration.
+ */
+void RDC_GetHardwareConfig(RDC_Type *base, rdc_hardware_config_t *config)
+{
+ assert(NULL != config);
+
+ rdc_vir_reg_t vir;
+ vir._u32 = base->VIR;
+
+ *config = vir._vir;
+}
+
+/*!
+ * brief Set master domain assignment
+ *
+ * param base RDC peripheral base address.
+ * param master Which master to set.
+ * param domainAssignment Pointer to the assignment.
+ */
+void RDC_SetMasterDomainAssignment(RDC_Type *base, rdc_master_t master, const rdc_domain_assignment_t *domainAssignment)
+{
+ assert((uint32_t)master < RDC_MDA_COUNT);
+
+ rdc_mda_reg_t mda;
+
+ mda._mda = *domainAssignment;
+
+ base->MDA[master] = mda._u32;
+}
+
+/*!
+ * brief Get default master domain assignment
+ *
+ * The default configuration is:
+ * code
+ assignment->domainId = 0U;
+ assignment->lock = 0U;
+ endcode
+ *
+ * param domainAssignment Pointer to the assignment.
+ */
+void RDC_GetDefaultMasterDomainAssignment(rdc_domain_assignment_t *domainAssignment)
+{
+ assert(NULL != domainAssignment);
+
+ rdc_mda_reg_t mda;
+ mda._u32 = 0U;
+
+ *domainAssignment = mda._mda;
+}
+
+/*!
+ * brief Set peripheral access policy.
+ *
+ * param base RDC peripheral base address.
+ * param config Pointer to the policy configuration.
+ */
+void RDC_SetPeriphAccessConfig(RDC_Type *base, const rdc_periph_access_config_t *config)
+{
+ assert((uint32_t)config->periph < RDC_PDAP_COUNT);
+
+ uint32_t periph = (uint32_t)config->periph;
+ uint32_t regPDAP = config->policy;
+
+ if (config->lock)
+ {
+ regPDAP |= RDC_PDAP_LCK_MASK;
+ }
+
+ if (config->enableSema)
+ {
+ regPDAP |= RDC_PDAP_SREQ_MASK;
+ }
+
+ base->PDAP[periph] = regPDAP;
+
+ __DSB();
+}
+
+/*!
+ * brief Get default peripheral access policy.
+ *
+ * The default configuration is:
+ * code
+ config->lock = false;
+ config->enableSema = false;
+ config->policy = RDC_ACCESS_POLICY(0, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(1, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(3, kRDC_ReadWrite);
+ endcode
+ *
+ * param config Pointer to the policy configuration.
+ */
+void RDC_GetDefaultPeriphAccessConfig(rdc_periph_access_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->lock = false;
+ config->enableSema = false;
+ config->policy = RDC_ACCESS_POLICY(0U, kRDC_ReadWrite) | RDC_ACCESS_POLICY(1U, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2U, kRDC_ReadWrite) | RDC_ACCESS_POLICY(3U, kRDC_ReadWrite);
+}
+
+/*!
+ * brief Set memory region access policy.
+ *
+ * Note that when setting the baseAddress and endAddress in p config,
+ * should be aligned to the region resolution, see rdc_mem_t
+ * definitions.
+ *
+ * param base RDC peripheral base address.
+ * param config Pointer to the policy configuration.
+ */
+void RDC_SetMemAccessConfig(RDC_Type *base, const rdc_mem_access_config_t *config)
+{
+ assert((uint32_t)config->mem < RDC_MRC_COUNT);
+
+ uint32_t mem = (uint32_t)config->mem;
+ /* The configuration is enabled by default. */
+ uint32_t regMRC = config->policy | RDC_MRC_ENA_MASK;
+
+ if (config->lock)
+ {
+ regMRC |= RDC_MRC_LCK_MASK;
+ }
+
+#if (defined(FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT) && FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT)
+ base->MR[mem].MRSA = (uint32_t)(config->baseAddress >> (uint32_t)FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT);
+ base->MR[mem].MREA = (uint32_t)(config->endAddress >> (uint32_t)FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT);
+#else
+ base->MR[mem].MRSA = (uint32_t)config->baseAddress;
+ base->MR[mem].MREA = (uint32_t)config->endAddress;
+#endif
+ base->MR[mem].MRC = regMRC;
+
+ __DSB();
+}
+
+/*!
+ * brief Get default memory region access policy.
+ *
+ * The default configuration is:
+ * code
+ config->lock = false;
+ config->baseAddress = 0;
+ config->endAddress = 0;
+ config->policy = RDC_ACCESS_POLICY(0, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(1, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(3, kRDC_ReadWrite);
+ endcode
+ *
+ * param config Pointer to the policy configuration.
+ */
+void RDC_GetDefaultMemAccessConfig(rdc_mem_access_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->lock = false;
+ config->baseAddress = 0;
+ config->endAddress = 0;
+ config->policy = RDC_ACCESS_POLICY(0U, kRDC_ReadWrite) | RDC_ACCESS_POLICY(1U, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2U, kRDC_ReadWrite) | RDC_ACCESS_POLICY(3U, kRDC_ReadWrite);
+}
+
+/*!
+ * brief Get the memory region violation status.
+ *
+ * The first access violation is captured. Subsequent violations are ignored
+ * until the status register is cleared. Contents are cleared upon reading the
+ * register. Clearing of contents occurs only when the status is read by the
+ * memory region's associated domain ID(s).
+ *
+ * param base RDC peripheral base address.
+ * param mem Which memory region to get.
+ * param status The returned status.
+ */
+void RDC_GetMemViolationStatus(RDC_Type *base, rdc_mem_t mem, rdc_mem_status_t *status)
+{
+ assert((uint32_t)mem < RDC_MRC_COUNT);
+
+ uint32_t regMRVS = base->MR[mem].MRVS;
+
+ status->hasViolation = ((regMRVS & RDC_MRVS_AD_MASK) != 0U);
+ status->domainID = (uint8_t)((regMRVS & RDC_MRVS_VDID_MASK) >> RDC_MRVS_VDID_SHIFT);
+#if (defined(FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT) && FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT)
+ regMRVS &= RDC_MRVS_VADR_MASK;
+ status->address = ((uint64_t)regMRVS) << (uint32_t)FSL_FEATURE_RDC_MEM_REGION_ADDR_SHIFT;
+#else
+ regMRVS &= RDC_MRVS_VADR_MASK;
+ status->address = (uint64_t)regMRVS;
+#endif
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.h b/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.h
new file mode 100644
index 0000000000..41d3f5aca1
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rdc/fsl_rdc.h
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2017-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_RDC_H_
+#define _FSL_RDC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup rdc
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+#define FSL_RDC_DRIVER_VERSION (MAKE_VERSION(2, 2, 0))
+
+#define RDC_ACCESS_POLICY(domainID, policy) (uint16_t)((uint16_t)(policy) << ((domainID)*2U))
+
+/*!
+ * @brief RDC hardware configuration.
+ */
+typedef struct _rdc_hardware_config
+{
+ uint32_t domainNumber : 4; /*!< Number of domains. */
+ uint32_t masterNumber : 8; /*!< Number of bus masters. */
+ uint32_t periphNumber : 8; /*!< Number of peripherals. */
+ uint32_t memNumber : 8; /*!< Number of memory regions. */
+ uint32_t : 4;
+} rdc_hardware_config_t;
+
+/*!
+ * @brief RDC interrupts
+ */
+enum _rdc_interrupts
+{
+ kRDC_RestoreCompleteInterrupt = RDC_INTCTRL_RCI_EN_MASK,
+ /*!< Interrupt generated when the RDC has completed restoring state to a recently re-powered memory regions. */
+};
+
+/*!
+ * @brief RDC status
+ */
+enum _rdc_flags
+{
+ kRDC_PowerDownDomainOn = RDC_STAT_PDS_MASK, /*!< Power down domain is ON. */
+};
+
+/*!
+ * @brief Master domain assignment.
+ */
+typedef struct _rdc_domain_assignment
+{
+ uint32_t domainId : 2U; /*!< Domain ID. */
+ uint32_t : 29U; /*!< Reserved. */
+ uint32_t lock : 1U; /*!< Lock the domain assignment. */
+} rdc_domain_assignment_t;
+
+/*!
+ * @brief Access permission policy.
+ */
+enum _rdc_access_policy
+{
+ kRDC_NoAccess = 0, /*!< Could not read or write. */
+ kRDC_WriteOnly = 1, /*!< Write only. */
+ kRDC_ReadOnly = 2, /*!< Read only. */
+ kRDC_ReadWrite = 3, /*!< Read and write. */
+};
+
+/*!
+ * @brief Peripheral domain access permission configuration.
+ */
+typedef struct _rdc_periph_access_config
+{
+ rdc_periph_t periph; /*!< Peripheral name. */
+ bool lock; /*!< Lock the permission until reset. */
+ bool enableSema; /*!< Enable semaphore or not, when enabled, master should
+ call @ref RDC_SEMA42_Lock to lock the semaphore gate
+ accordingly before access the peripheral. */
+ uint16_t policy; /*!< Access policy. */
+} rdc_periph_access_config_t;
+
+/*!
+ * @brief Memory region domain access control configuration.
+ *
+ * Note that when setting the @ref baseAddress and @ref endAddress,
+ * should be aligned to the region resolution, see rdc_mem_t
+ * definitions.
+ */
+typedef struct _rdc_mem_access_config
+{
+ rdc_mem_t mem; /*!< Memory region descriptor name. */
+
+ bool lock; /*!< Lock the configuration. */
+ uint64_t baseAddress; /*!< Start address of the memory region. */
+ uint64_t endAddress; /*!< End address of the memory region. */
+ uint16_t policy; /*!< Access policy. */
+} rdc_mem_access_config_t;
+
+/*!
+ * @brief Memory region access violation status.
+ */
+typedef struct _rdc_mem_status
+{
+ bool hasViolation; /*!< Violating happens or not. */
+ uint8_t domainID; /*!< Violating Domain ID. */
+ uint64_t address; /*!< Violating Address. */
+} rdc_mem_status_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the RDC module.
+ *
+ * This function enables the RDC clock.
+ *
+ * @param base RDC peripheral base address.
+ */
+void RDC_Init(RDC_Type *base);
+
+/*!
+ * @brief De-initializes the RDC module.
+ *
+ * This function disables the RDC clock.
+ *
+ * @param base RDC peripheral base address.
+ */
+void RDC_Deinit(RDC_Type *base);
+
+/*!
+ * @brief Gets the RDC hardware configuration.
+ *
+ * This function gets the RDC hardware configurations, including number of bus
+ * masters, number of domains, number of memory regions and number of peripherals.
+ *
+ * @param base RDC peripheral base address.
+ * @param config Pointer to the structure to get the configuration.
+ */
+void RDC_GetHardwareConfig(RDC_Type *base, rdc_hardware_config_t *config);
+
+/*!
+ * @brief Enable interrupts.
+ *
+ * @param base RDC peripheral base address.
+ * @param mask Interrupts to enable, it is OR'ed value of enum @ref _rdc_interrupts.
+ */
+static inline void RDC_EnableInterrupts(RDC_Type *base, uint32_t mask)
+{
+ base->INTCTRL |= mask;
+}
+
+/*!
+ * @brief Disable interrupts.
+ *
+ * @param base RDC peripheral base address.
+ * @param mask Interrupts to disable, it is OR'ed value of enum @ref _rdc_interrupts.
+ */
+static inline void RDC_DisableInterrupts(RDC_Type *base, uint32_t mask)
+{
+ base->INTCTRL &= ~mask;
+}
+
+/*!
+ * @brief Get the interrupt pending status.
+ *
+ * @param base RDC peripheral base address.
+ * @return Interrupts pending status, it is OR'ed value of enum @ref _rdc_interrupts.
+ */
+static inline uint32_t RDC_GetInterruptStatus(RDC_Type *base)
+{
+ return base->INTSTAT;
+}
+
+/*!
+ * @brief Clear interrupt pending status.
+ *
+ * @param base RDC peripheral base address.
+ * @param mask Status to clear, it is OR'ed value of enum @ref _rdc_interrupts.
+ */
+static inline void RDC_ClearInterruptStatus(RDC_Type *base, uint32_t mask)
+{
+ base->INTSTAT = mask;
+}
+
+/*!
+ * @brief Get RDC status.
+ *
+ * @param base RDC peripheral base address.
+ * @return mask RDC status, it is OR'ed value of enum @ref _rdc_flags.
+ */
+static inline uint32_t RDC_GetStatus(RDC_Type *base)
+{
+ return base->STAT;
+}
+
+/*!
+ * @brief Clear RDC status.
+ *
+ * @param base RDC peripheral base address.
+ * @param mask RDC status to clear, it is OR'ed value of enum @ref _rdc_flags.
+ */
+static inline void RDC_ClearStatus(RDC_Type *base, uint32_t mask)
+{
+ base->STAT = mask;
+}
+
+/*!
+ * @brief Set master domain assignment
+ *
+ * @param base RDC peripheral base address.
+ * @param master Which master to set.
+ * @param domainAssignment Pointer to the assignment.
+ */
+void RDC_SetMasterDomainAssignment(RDC_Type *base,
+ rdc_master_t master,
+ const rdc_domain_assignment_t *domainAssignment);
+
+/*!
+ * @brief Get default master domain assignment
+ *
+ * The default configuration is:
+ * @code
+ assignment->domainId = 0U;
+ assignment->lock = 0U;
+ @endcode
+ *
+ * @param domainAssignment Pointer to the assignment.
+ */
+void RDC_GetDefaultMasterDomainAssignment(rdc_domain_assignment_t *domainAssignment);
+
+/*!
+ * @brief Lock master domain assignment
+ *
+ * Once locked, it could not be unlocked until next reset.
+ *
+ * @param base RDC peripheral base address.
+ * @param master Which master to lock.
+ */
+static inline void RDC_LockMasterDomainAssignment(RDC_Type *base, rdc_master_t master)
+{
+ assert((uint32_t)master < RDC_MDA_COUNT);
+
+ base->MDA[master] |= RDC_MDA_LCK_MASK;
+ __DSB();
+}
+
+/*!
+ * @brief Set peripheral access policy.
+ *
+ * @param base RDC peripheral base address.
+ * @param config Pointer to the policy configuration.
+ */
+void RDC_SetPeriphAccessConfig(RDC_Type *base, const rdc_periph_access_config_t *config);
+
+/*!
+ * @brief Get default peripheral access policy.
+ *
+ * The default configuration is:
+ * @code
+ config->lock = false;
+ config->enableSema = false;
+ config->policy = RDC_ACCESS_POLICY(0, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(1, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(3, kRDC_ReadWrite);
+ @endcode
+ *
+ * @param config Pointer to the policy configuration.
+ */
+void RDC_GetDefaultPeriphAccessConfig(rdc_periph_access_config_t *config);
+
+/*!
+ * @brief Lock peripheral access policy configuration.
+ *
+ * Once locked, it could not be unlocked until reset.
+ *
+ * @param base RDC peripheral base address.
+ * @param periph Which peripheral to lock.
+ */
+static inline void RDC_LockPeriphAccessConfig(RDC_Type *base, rdc_periph_t periph)
+{
+ assert((uint32_t)periph < RDC_PDAP_COUNT);
+
+ base->PDAP[periph] |= RDC_PDAP_LCK_MASK;
+ __DSB();
+}
+
+/*!
+ * @brief Get the peripheral access policy for specific domain.
+ *
+ * @param base RDC peripheral base address.
+ * @param periph Which peripheral to get.
+ * @param domainId Get policy for which domain.
+ * @return Access policy, see @ref _rdc_access_policy.
+ */
+static inline uint8_t RDC_GetPeriphAccessPolicy(RDC_Type *base, rdc_periph_t periph, uint8_t domainId)
+{
+ assert((uint32_t)periph < RDC_PDAP_COUNT);
+
+ return (uint8_t)((base->PDAP[periph] >> (domainId * 2U)) & 0x03U);
+}
+
+/*!
+ * @brief Set memory region access policy.
+ *
+ * Note that when setting the baseAddress and endAddress in @p config,
+ * should be aligned to the region resolution, see rdc_mem_t
+ * definitions.
+ *
+ * @param base RDC peripheral base address.
+ * @param config Pointer to the policy configuration.
+ */
+void RDC_SetMemAccessConfig(RDC_Type *base, const rdc_mem_access_config_t *config);
+
+/*!
+ * @brief Get default memory region access policy.
+ *
+ * The default configuration is:
+ * @code
+ config->lock = false;
+ config->baseAddress = 0;
+ config->endAddress = 0;
+ config->policy = RDC_ACCESS_POLICY(0, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(1, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(2, kRDC_ReadWrite) |
+ RDC_ACCESS_POLICY(3, kRDC_ReadWrite);
+ @endcode
+ *
+ * @param config Pointer to the policy configuration.
+ */
+void RDC_GetDefaultMemAccessConfig(rdc_mem_access_config_t *config);
+
+/*!
+ * @brief Lock memory access policy configuration.
+ *
+ * Once locked, it could not be unlocked until reset. After locked, you can
+ * only call @ref RDC_SetMemAccessValid to enable the configuration, but can not
+ * disable it or change other settings.
+ *
+ * @param base RDC peripheral base address.
+ * @param mem Which memory region to lock.
+ */
+static inline void RDC_LockMemAccessConfig(RDC_Type *base, rdc_mem_t mem)
+{
+ assert((uint32_t)mem < RDC_MRC_COUNT);
+
+ base->MR[mem].MRC |= RDC_MRC_LCK_MASK;
+ __DSB();
+}
+
+/*!
+ * @brief Enable or disable memory access policy configuration.
+ *
+ * @param base RDC peripheral base address.
+ * @param mem Which memory region to operate.
+ * @param valid Pass in true to valid, false to invalid.
+ */
+static inline void RDC_SetMemAccessValid(RDC_Type *base, rdc_mem_t mem, bool valid)
+{
+ assert((uint32_t)mem < RDC_MRC_COUNT);
+
+ if (valid)
+ {
+ base->MR[mem].MRC |= RDC_MRC_ENA_MASK;
+ }
+ else
+ {
+ base->MR[mem].MRC &= ~RDC_MRC_ENA_MASK;
+ }
+ __DSB();
+}
+
+/*!
+ * @brief Get the memory region violation status.
+ *
+ * The first access violation is captured. Subsequent violations are ignored
+ * until the status register is cleared. Contents are cleared upon reading the
+ * register. Clearing of contents occurs only when the status is read by the
+ * memory region's associated domain ID(s).
+ *
+ * @param base RDC peripheral base address.
+ * @param mem Which memory region to get.
+ * @param status The returned status.
+ */
+void RDC_GetMemViolationStatus(RDC_Type *base, rdc_mem_t mem, rdc_mem_status_t *status);
+
+/*!
+ * @brief Clear the memory region violation flag.
+ *
+ * @param base RDC peripheral base address.
+ * @param mem Which memory region to clear.
+ */
+static inline void RDC_ClearMemViolationFlag(RDC_Type *base, rdc_mem_t mem)
+{
+ assert((uint32_t)mem < RDC_MRC_COUNT);
+
+ base->MR[mem].MRVS = RDC_MRVS_AD_MASK;
+}
+
+/*!
+ * @brief Get the memory region access policy for specific domain.
+ *
+ * @param base RDC peripheral base address.
+ * @param mem Which memory region to get.
+ * @param domainId Get policy for which domain.
+ * @return Access policy, see @ref _rdc_access_policy.
+ */
+static inline uint8_t RDC_GetMemAccessPolicy(RDC_Type *base, rdc_mem_t mem, uint8_t domainId)
+{
+ assert((uint32_t)mem < RDC_MRC_COUNT);
+
+ return (uint8_t)((base->MR[mem].MRC >> (domainId * 2U)) & 0x03U);
+}
+
+/*!
+ * @brief Gets the domain ID of the current bus master.
+ *
+ * This function returns the domain ID of the current bus master.
+ *
+ * @param base RDC peripheral base address.
+ * @return Domain ID of current bus master.
+ */
+static inline uint8_t RDC_GetCurrentMasterDomainId(RDC_Type *base)
+{
+ return (uint8_t)((base->STAT & RDC_STAT_DID_MASK) >> RDC_STAT_DID_SHIFT);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_RDC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.c b/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.c
new file mode 100644
index 0000000000..00189e49a8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2017-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_rdc_sema42.h"
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.rdc_sema42"
+#endif
+
+/* The first number write to RSTGDP when reset RDC_SEMA42 gate. */
+#define RDC_SEMA42_GATE_RESET_PATTERN_1 (0xE2U)
+/* The second number write to RSTGDP when reset RDC_SEMA42 gate. */
+#define RDC_SEMA42_GATE_RESET_PATTERN_2 (0x1DU)
+
+#if !defined(RDC_SEMAPHORE_GATE_COUNT)
+/* Compatible remap. */
+#define RDC_SEMAPHORE_GATE_LDOM(x) RDC_SEMAPHORE_GATE0_LDOM(x)
+#define RDC_SEMAPHORE_GATE_GTFSM(x) RDC_SEMAPHORE_GATE0_GTFSM(x)
+#define RDC_SEMAPHORE_GATE_LDOM_MASK RDC_SEMAPHORE_GATE0_LDOM_MASK
+#define RDC_SEMAPHORE_GATE_LDOM_SHIFT RDC_SEMAPHORE_GATE0_LDOM_SHIFT
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for RDC_SEMA42 module.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ */
+uint32_t RDC_SEMA42_GetInstance(RDC_SEMAPHORE_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to sema42 bases for each instance. */
+static RDC_SEMAPHORE_Type *const s_sema42Bases[] = RDC_SEMAPHORE_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(RDC_SEMA42_CLOCKS)
+/*! @brief Pointers to sema42 clocks for each instance. */
+static const clock_ip_name_t s_sema42Clocks[] = RDC_SEMA42_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/******************************************************************************
+ * CODE
+ *****************************************************************************/
+
+uint32_t RDC_SEMA42_GetInstance(RDC_SEMAPHORE_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_sema42Bases); instance++)
+ {
+ if (s_sema42Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_sema42Bases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the RDC_SEMA42 module.
+ *
+ * This function initializes the RDC_SEMA42 module. It only enables the clock but does
+ * not reset the gates because the module might be used by other processors
+ * at the same time. To reset the gates, call either RDC_SEMA42_ResetGate or
+ * RDC_SEMA42_ResetAllGates function.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ */
+void RDC_SEMA42_Init(RDC_SEMAPHORE_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(RDC_SEMA42_CLOCKS)
+ CLOCK_EnableClock(s_sema42Clocks[RDC_SEMA42_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief De-initializes the RDC_SEMA42 module.
+ *
+ * This function de-initializes the RDC_SEMA42 module. It only disables the clock.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ */
+void RDC_SEMA42_Deinit(RDC_SEMAPHORE_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(RDC_SEMA42_CLOCKS)
+ CLOCK_DisableClock(s_sema42Clocks[RDC_SEMA42_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Tries to lock the RDC_SEMA42 gate.
+ *
+ * This function tries to lock the specific RDC_SEMA42 gate. If the gate has been
+ * locked by another processor, this function returns an error code.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ * param gateNum Gate number to lock.
+ * param masterIndex Current processor master index.
+ * param domainId Current processor domain ID.
+ *
+ * retval kStatus_Success Lock the sema42 gate successfully.
+ * retval kStatus_Failed Sema42 gate has been locked by another processor.
+ */
+status_t RDC_SEMA42_TryLock(RDC_SEMAPHORE_Type *base, uint8_t gateNum, uint8_t masterIndex, uint8_t domainId)
+{
+ assert(gateNum < RDC_SEMA42_GATE_COUNT);
+
+ status_t status = kStatus_Success;
+ uint8_t regGate;
+
+ ++masterIndex;
+
+ regGate = (uint8_t)(RDC_SEMAPHORE_GATE_LDOM(domainId) | RDC_SEMAPHORE_GATE_GTFSM(masterIndex));
+
+ /* Try to lock. */
+ RDC_SEMA42_GATEn(base, gateNum) = masterIndex;
+
+ /* Check locked or not. */
+ if (regGate != RDC_SEMA42_GATEn(base, gateNum))
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Locks the RDC_SEMA42 gate.
+ *
+ * This function locks the specific RDC_SEMA42 gate. If the gate has been
+ * locked by other processors, this function waits until it is unlocked and then
+ * lock it.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ * param gateNum Gate number to lock.
+ * param masterIndex Current processor master index.
+ * param domainId Current processor domain ID.
+ */
+void RDC_SEMA42_Lock(RDC_SEMAPHORE_Type *base, uint8_t gateNum, uint8_t masterIndex, uint8_t domainId)
+{
+ while (kStatus_Success != RDC_SEMA42_TryLock(base, gateNum, masterIndex, domainId))
+ {
+ }
+}
+
+/*!
+ * brief Gets which domain has currently locked the gate.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ * param gateNum Gate number.
+ *
+ * return Return -1 if the gate is not locked by any domain, otherwise return the
+ * domain ID.
+ */
+int32_t RDC_SEMA42_GetLockDomainID(RDC_SEMAPHORE_Type *base, uint8_t gateNum)
+{
+ assert(gateNum < RDC_SEMA42_GATE_COUNT);
+
+ int32_t ret;
+ uint8_t regGate = RDC_SEMA42_GATEn(base, gateNum);
+
+ /* Current gate is not locked. */
+ if (0U == (regGate & RDC_SEMAPHORE_GATE_GTFSM_MASK))
+ {
+ ret = -1;
+ }
+ else
+ {
+ ret = (int32_t)((uint8_t)((regGate & RDC_SEMAPHORE_GATE_LDOM_MASK) >> RDC_SEMAPHORE_GATE_LDOM_SHIFT));
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Resets the RDC_SEMA42 gate to an unlocked status.
+ *
+ * This function resets a RDC_SEMA42 gate to an unlocked status.
+ *
+ * param base RDC_SEMA42 peripheral base address.
+ * param gateNum Gate number.
+ *
+ * retval kStatus_Success RDC_SEMA42 gate is reset successfully.
+ * retval kStatus_Failed Some other reset process is ongoing.
+ */
+status_t RDC_SEMA42_ResetGate(RDC_SEMAPHORE_Type *base, uint8_t gateNum)
+{
+ status_t status;
+
+ /*
+ * Reset all gates if gateNum >= RDC_SEMA42_GATE_NUM_RESET_ALL
+ * Reset specific gate if gateNum < RDC_SEMA42_GATE_COUNT
+ */
+
+ /* Check whether some reset is ongoing. */
+ if (0U != (base->RSTGT_R & RDC_SEMAPHORE_RSTGT_R_RSTGSM_MASK))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ /* First step. */
+ base->RSTGT_W = RDC_SEMAPHORE_RSTGT_W_RSTGDP(RDC_SEMA42_GATE_RESET_PATTERN_1);
+ /* Second step. */
+ base->RSTGT_W =
+ RDC_SEMAPHORE_RSTGT_W_RSTGDP(RDC_SEMA42_GATE_RESET_PATTERN_2) | RDC_SEMAPHORE_RSTGT_W_RSTGTN(gateNum);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.h b/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.h
new file mode 100644
index 0000000000..ddd9e4bbc2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rdc_sema42/fsl_rdc_sema42.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2017-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_RDC_SEMA42_H_
+#define _FSL_RDC_SEMA42_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup rdc_sema42
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief RDC_SEMA42 driver version */
+#define FSL_RDC_SEMA42_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
+/*@}*/
+
+/*! @brief The number to reset all RDC_SEMA42 gates. */
+#define RDC_SEMA42_GATE_NUM_RESET_ALL (64U)
+
+#if defined(RDC_SEMAPHORE_GATE_COUNT)
+
+/*! @brief RDC_SEMA42 gate n register address. */
+#define RDC_SEMA42_GATEn(base, n) ((base)->GATE[(n)])
+
+/*! @brief RDC_SEMA42 gate count. */
+#define RDC_SEMA42_GATE_COUNT (RDC_SEMAPHORE_GATE_COUNT)
+
+#else /* RDC_SEMAPHORE_GATE_COUNT */
+
+/*! @brief RDC_SEMA42 gate n register address. */
+#define RDC_SEMA42_GATEn(base, n) (((volatile uint8_t *)(&((base)->GATE0)))[(n)])
+
+/*! @brief RDC_SEMA42 gate count. */
+#define RDC_SEMA42_GATE_COUNT (64U)
+
+/* Compatible remap. */
+#define RDC_SEMAPHORE_GATE_GTFSM_MASK RDC_SEMAPHORE_GATE0_GTFSM_MASK
+
+#endif /* RDC_SEMAPHORE_GATE_COUNT */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the RDC_SEMA42 module.
+ *
+ * This function initializes the RDC_SEMA42 module. It only enables the clock but does
+ * not reset the gates because the module might be used by other processors
+ * at the same time. To reset the gates, call either RDC_SEMA42_ResetGate or
+ * RDC_SEMA42_ResetAllGates function.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ */
+void RDC_SEMA42_Init(RDC_SEMAPHORE_Type *base);
+
+/*!
+ * @brief De-initializes the RDC_SEMA42 module.
+ *
+ * This function de-initializes the RDC_SEMA42 module. It only disables the clock.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ */
+void RDC_SEMA42_Deinit(RDC_SEMAPHORE_Type *base);
+
+/*!
+ * @brief Tries to lock the RDC_SEMA42 gate.
+ *
+ * This function tries to lock the specific RDC_SEMA42 gate. If the gate has been
+ * locked by another processor, this function returns an error code.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number to lock.
+ * @param masterIndex Current processor master index.
+ * @param domainId Current processor domain ID.
+ *
+ * @retval kStatus_Success Lock the sema42 gate successfully.
+ * @retval kStatus_Failed Sema42 gate has been locked by another processor.
+ */
+status_t RDC_SEMA42_TryLock(RDC_SEMAPHORE_Type *base, uint8_t gateNum, uint8_t masterIndex, uint8_t domainId);
+
+/*!
+ * @brief Locks the RDC_SEMA42 gate.
+ *
+ * This function locks the specific RDC_SEMA42 gate. If the gate has been
+ * locked by other processors, this function waits until it is unlocked and then
+ * lock it.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number to lock.
+ * @param masterIndex Current processor master index.
+ * @param domainId Current processor domain ID.
+ */
+void RDC_SEMA42_Lock(RDC_SEMAPHORE_Type *base, uint8_t gateNum, uint8_t masterIndex, uint8_t domainId);
+
+/*!
+ * @brief Unlocks the RDC_SEMA42 gate.
+ *
+ * This function unlocks the specific RDC_SEMA42 gate. It only writes unlock value
+ * to the RDC_SEMA42 gate register. However, it does not check whether the RDC_SEMA42 gate is locked
+ * by the current processor or not. As a result, if the RDC_SEMA42 gate is not locked by the current
+ * processor, this function has no effect.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number to unlock.
+ */
+static inline void RDC_SEMA42_Unlock(RDC_SEMAPHORE_Type *base, uint8_t gateNum)
+{
+ assert(gateNum < RDC_SEMA42_GATE_COUNT);
+
+ RDC_SEMA42_GATEn(base, gateNum) = 0U;
+}
+
+/*!
+ * @brief Gets which master has currently locked the gate.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @return Return -1 if the gate is not locked by any master, otherwise return the
+ * master index.
+ */
+static inline int32_t RDC_SEMA42_GetLockMasterIndex(RDC_SEMAPHORE_Type *base, uint8_t gateNum)
+{
+ assert(gateNum < RDC_SEMA42_GATE_COUNT);
+
+ uint8_t regGate = RDC_SEMA42_GATEn(base, gateNum);
+
+ return (int32_t)((uint8_t)(regGate & RDC_SEMAPHORE_GATE_GTFSM_MASK)) - 1;
+}
+
+/*!
+ * @brief Gets which domain has currently locked the gate.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @return Return -1 if the gate is not locked by any domain, otherwise return the
+ * domain ID.
+ */
+int32_t RDC_SEMA42_GetLockDomainID(RDC_SEMAPHORE_Type *base, uint8_t gateNum);
+
+/*!
+ * @brief Resets the RDC_SEMA42 gate to an unlocked status.
+ *
+ * This function resets a RDC_SEMA42 gate to an unlocked status.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @retval kStatus_Success RDC_SEMA42 gate is reset successfully.
+ * @retval kStatus_Failed Some other reset process is ongoing.
+ */
+status_t RDC_SEMA42_ResetGate(RDC_SEMAPHORE_Type *base, uint8_t gateNum);
+
+/*!
+ * @brief Resets all RDC_SEMA42 gates to an unlocked status.
+ *
+ * This function resets all RDC_SEMA42 gate to an unlocked status.
+ *
+ * @param base RDC_SEMA42 peripheral base address.
+ *
+ * @retval kStatus_Success RDC_SEMA42 is reset successfully.
+ * @retval kStatus_RDC_SEMA42_Reseting Some other reset process is ongoing.
+ */
+static inline status_t RDC_SEMA42_ResetAllGates(RDC_SEMAPHORE_Type *base)
+{
+ return RDC_SEMA42_ResetGate(base, RDC_SEMA42_GATE_NUM_RESET_ALL);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_RDC_SEMA42_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.c b/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.c
new file mode 100644
index 0000000000..4b49280bf8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_rtwdog.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.rtwdog"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Clears the RTWDOG flag.
+ *
+ * This function clears the RTWDOG status flag.
+ *
+ * Example to clear an interrupt flag:
+ * code
+ * RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag);
+ * endcode
+ * param base RTWDOG peripheral base address.
+ * param mask The status flags to clear.
+ * The parameter can be any combination of the following values:
+ * arg kRTWDOG_InterruptFlag
+ */
+void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kRTWDOG_InterruptFlag) != 0U)
+ {
+ base->CS |= RTWDOG_CS_FLG_MASK;
+ }
+}
+
+/*!
+ * brief Initializes the RTWDOG configuration structure.
+ *
+ * This function initializes the RTWDOG configuration structure to default values. The default
+ * values are:
+ * code
+ * rtwdogConfig->enableRtwdog = true;
+ * rtwdogConfig->clockSource = kRTWDOG_ClockSource1;
+ * rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1;
+ * rtwdogConfig->workMode.enableWait = true;
+ * rtwdogConfig->workMode.enableStop = false;
+ * rtwdogConfig->workMode.enableDebug = false;
+ * rtwdogConfig->testMode = kRTWDOG_TestModeDisabled;
+ * rtwdogConfig->enableUpdate = true;
+ * rtwdogConfig->enableInterrupt = false;
+ * rtwdogConfig->enableWindowMode = false;
+ * rtwdogConfig->windowValue = 0U;
+ * rtwdogConfig->timeoutValue = 0xFFFFU;
+ * endcode
+ *
+ * param config Pointer to the RTWDOG configuration structure.
+ * see rtwdog_config_t
+ */
+void RTWDOG_GetDefaultConfig(rtwdog_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableRtwdog = true;
+ config->clockSource = kRTWDOG_ClockSource1;
+ config->prescaler = kRTWDOG_ClockPrescalerDivide1;
+ config->workMode.enableWait = true;
+ config->workMode.enableStop = false;
+ config->workMode.enableDebug = false;
+ config->testMode = kRTWDOG_TestModeDisabled;
+ config->enableUpdate = true;
+ config->enableInterrupt = false;
+ config->enableWindowMode = false;
+ config->windowValue = 0U;
+ config->timeoutValue = 0xFFFFU;
+}
+
+/*!
+ * brief Initializes the RTWDOG module.
+ *
+ * This function initializes the RTWDOG.
+ * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true
+ * in the configuration.
+ *
+ * Example:
+ * code
+ * rtwdog_config_t config;
+ * RTWDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0x7ffU;
+ * config.enableUpdate = true;
+ * RTWDOG_Init(wdog_base,&config);
+ * endcode
+ *
+ * param base RTWDOG peripheral base address.
+ * param config The configuration of the RTWDOG.
+ */
+void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t value = 0U;
+ uint32_t primaskValue = 0U;
+
+ value = RTWDOG_CS_EN(config->enableRtwdog) | RTWDOG_CS_CLK(config->clockSource) |
+ RTWDOG_CS_INT(config->enableInterrupt) | RTWDOG_CS_WIN(config->enableWindowMode) |
+ RTWDOG_CS_UPDATE(config->enableUpdate) | RTWDOG_CS_DBG(config->workMode.enableDebug) |
+ RTWDOG_CS_STOP(config->workMode.enableStop) | RTWDOG_CS_WAIT(config->workMode.enableWait) |
+ RTWDOG_CS_PRES(config->prescaler) | RTWDOG_CS_CMD32EN(1U) | RTWDOG_CS_TST(config->testMode);
+
+ /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence
+ * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */
+ primaskValue = DisableGlobalIRQ();
+ RTWDOG_Unlock(base);
+ base->WIN = config->windowValue;
+ base->TOVAL = config->timeoutValue;
+ base->CS = value;
+ while ((base->CS & RTWDOG_CS_RCS_MASK) == 0U)
+ {
+ }
+ EnableGlobalIRQ(primaskValue);
+}
+
+/*!
+ * brief De-initializes the RTWDOG module.
+ *
+ * This function shuts down the RTWDOG.
+ * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled.
+ *
+ * param base RTWDOG peripheral base address.
+ */
+void RTWDOG_Deinit(RTWDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupts */
+ primaskValue = DisableGlobalIRQ();
+ RTWDOG_Unlock(base);
+ RTWDOG_Disable(base);
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.h b/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.h
new file mode 100644
index 0000000000..5eecb5a23b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/rtwdog/fsl_rtwdog.h
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_RTWDOG_H_
+#define _FSL_RTWDOG_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup rtwdog
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+/*! @name Unlock sequence */
+/*@{*/
+#define WDOG_FIRST_WORD_OF_UNLOCK (RTWDOG_UPDATE_KEY & 0xFFFFU) /*!< First word of unlock sequence */
+#define WDOG_SECOND_WORD_OF_UNLOCK ((RTWDOG_UPDATE_KEY >> 16U) & 0xFFFFU) /*!< Second word of unlock sequence */
+/*@}*/
+
+/*! @name Refresh sequence */
+/*@{*/
+#define WDOG_FIRST_WORD_OF_REFRESH (RTWDOG_REFRESH_KEY & 0xFFFFU) /*!< First word of refresh sequence */
+#define WDOG_SECOND_WORD_OF_REFRESH ((RTWDOG_REFRESH_KEY >> 16U) & 0xFFFFU) /*!< Second word of refresh sequence */
+/*@}*/
+/*! @name Driver version */
+/*@{*/
+/*! @brief RTWDOG driver version 2.1.2. */
+#define FSL_RTWDOG_DRIVER_VERSION (MAKE_VERSION(2, 1, 2))
+/*@}*/
+
+/*! @brief Describes RTWDOG clock source. */
+typedef enum _rtwdog_clock_source
+{
+ kRTWDOG_ClockSource0 = 0U, /*!< Clock source 0 */
+ kRTWDOG_ClockSource1 = 1U, /*!< Clock source 1 */
+ kRTWDOG_ClockSource2 = 2U, /*!< Clock source 2 */
+ kRTWDOG_ClockSource3 = 3U, /*!< Clock source 3 */
+} rtwdog_clock_source_t;
+
+/*! @brief Describes the selection of the clock prescaler. */
+typedef enum _rtwdog_clock_prescaler
+{
+ kRTWDOG_ClockPrescalerDivide1 = 0x0U, /*!< Divided by 1 */
+ kRTWDOG_ClockPrescalerDivide256 = 0x1U, /*!< Divided by 256 */
+} rtwdog_clock_prescaler_t;
+
+/*! @brief Defines RTWDOG work mode. */
+typedef struct _rtwdog_work_mode
+{
+ bool enableWait; /*!< Enables or disables RTWDOG in wait mode */
+ bool enableStop; /*!< Enables or disables RTWDOG in stop mode */
+ bool enableDebug; /*!< Enables or disables RTWDOG in debug mode */
+} rtwdog_work_mode_t;
+
+/*! @brief Describes RTWDOG test mode. */
+typedef enum _rtwdog_test_mode
+{
+ kRTWDOG_TestModeDisabled = 0U, /*!< Test Mode disabled */
+ kRTWDOG_UserModeEnabled = 1U, /*!< User Mode enabled */
+ kRTWDOG_LowByteTest = 2U, /*!< Test Mode enabled, only low byte is used */
+ kRTWDOG_HighByteTest = 3U, /*!< Test Mode enabled, only high byte is used */
+} rtwdog_test_mode_t;
+
+/*! @brief Describes RTWDOG configuration structure. */
+typedef struct _rtwdog_config
+{
+ bool enableRtwdog; /*!< Enables or disables RTWDOG */
+ rtwdog_clock_source_t clockSource; /*!< Clock source select */
+ rtwdog_clock_prescaler_t prescaler; /*!< Clock prescaler value */
+ rtwdog_work_mode_t workMode; /*!< Configures RTWDOG work mode in debug stop and wait mode */
+ rtwdog_test_mode_t testMode; /*!< Configures RTWDOG test mode */
+ bool enableUpdate; /*!< Update write-once register enable */
+ bool enableInterrupt; /*!< Enables or disables RTWDOG interrupt */
+ bool enableWindowMode; /*!< Enables or disables RTWDOG window mode */
+ uint16_t windowValue; /*!< Window value */
+ uint16_t timeoutValue; /*!< Timeout value */
+} rtwdog_config_t;
+
+/*!
+ * @brief RTWDOG interrupt configuration structure.
+ *
+ * This structure contains the settings for all of the RTWDOG interrupt configurations.
+ */
+enum _rtwdog_interrupt_enable_t
+{
+ kRTWDOG_InterruptEnable = RTWDOG_CS_INT_MASK, /*!< Interrupt is generated before forcing a reset */
+};
+
+/*!
+ * @brief RTWDOG status flags.
+ *
+ * This structure contains the RTWDOG status flags for use in the RTWDOG functions.
+ */
+enum _rtwdog_status_flags_t
+{
+ kRTWDOG_RunningFlag = RTWDOG_CS_EN_MASK, /*!< Running flag, set when RTWDOG is enabled */
+ kRTWDOG_InterruptFlag = RTWDOG_CS_FLG_MASK, /*!< Interrupt flag, set when interrupt occurs */
+};
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name RTWDOG Initialization and De-initialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the RTWDOG configuration structure.
+ *
+ * This function initializes the RTWDOG configuration structure to default values. The default
+ * values are:
+ * @code
+ * rtwdogConfig->enableRtwdog = true;
+ * rtwdogConfig->clockSource = kRTWDOG_ClockSource1;
+ * rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1;
+ * rtwdogConfig->workMode.enableWait = true;
+ * rtwdogConfig->workMode.enableStop = false;
+ * rtwdogConfig->workMode.enableDebug = false;
+ * rtwdogConfig->testMode = kRTWDOG_TestModeDisabled;
+ * rtwdogConfig->enableUpdate = true;
+ * rtwdogConfig->enableInterrupt = false;
+ * rtwdogConfig->enableWindowMode = false;
+ * rtwdogConfig->windowValue = 0U;
+ * rtwdogConfig->timeoutValue = 0xFFFFU;
+ * @endcode
+ *
+ * @param config Pointer to the RTWDOG configuration structure.
+ * @see rtwdog_config_t
+ */
+void RTWDOG_GetDefaultConfig(rtwdog_config_t *config);
+
+/*!
+ * @brief Initializes the RTWDOG module.
+ *
+ * This function initializes the RTWDOG.
+ * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true
+ * in the configuration.
+ *
+ * Example:
+ * @code
+ * rtwdog_config_t config;
+ * RTWDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0x7ffU;
+ * config.enableUpdate = true;
+ * RTWDOG_Init(wdog_base,&config);
+ * @endcode
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param config The configuration of the RTWDOG.
+ */
+
+#if defined(DOXYGEN_OUTPUT) && DOXYGEN_OUTPUT
+void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config);
+#else
+AT_QUICKACCESS_SECTION_CODE(void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config));
+#endif
+
+/*!
+ * @brief De-initializes the RTWDOG module.
+ *
+ * This function shuts down the RTWDOG.
+ * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled.
+ *
+ * @param base RTWDOG peripheral base address.
+ */
+void RTWDOG_Deinit(RTWDOG_Type *base);
+
+/* @} */
+
+/*!
+ * @name RTWDOG functional Operation
+ * @{
+ */
+
+/*!
+ * @brief Enables the RTWDOG module.
+ *
+ * This function writes a value into the WDOG_CS register to enable the RTWDOG.
+ * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address.
+ */
+static inline void RTWDOG_Enable(RTWDOG_Type *base)
+{
+ base->CS |= RTWDOG_CS_EN_MASK;
+}
+
+/*!
+ * @brief Disables the RTWDOG module.
+ *
+ * This function writes a value into the WDOG_CS register to disable the RTWDOG.
+ * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address
+ */
+static inline void RTWDOG_Disable(RTWDOG_Type *base)
+{
+ base->CS &= ~RTWDOG_CS_EN_MASK;
+}
+
+/*!
+ * @brief Enables the RTWDOG interrupt.
+ *
+ * This function writes a value into the WDOG_CS register to enable the RTWDOG interrupt.
+ * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param mask The interrupts to enable.
+ * The parameter can be a combination of the following source if defined:
+ * @arg kRTWDOG_InterruptEnable
+ */
+static inline void RTWDOG_EnableInterrupts(RTWDOG_Type *base, uint32_t mask)
+{
+ base->CS |= mask;
+}
+
+/*!
+ * @brief Disables the RTWDOG interrupt.
+ *
+ * This function writes a value into the WDOG_CS register to disable the RTWDOG interrupt.
+ * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param mask The interrupts to disabled.
+ * The parameter can be a combination of the following source if defined:
+ * @arg kRTWDOG_InterruptEnable
+ */
+static inline void RTWDOG_DisableInterrupts(RTWDOG_Type *base, uint32_t mask)
+{
+ base->CS &= ~mask;
+}
+
+/*!
+ * @brief Gets the RTWDOG all status flags.
+ *
+ * This function gets all status flags.
+ *
+ * Example to get the running flag:
+ * @code
+ * uint32_t status;
+ * status = RTWDOG_GetStatusFlags(wdog_base) & kRTWDOG_RunningFlag;
+ * @endcode
+ * @param base RTWDOG peripheral base address
+ * @return State of the status flag: asserted (true) or not-asserted (false). @see _rtwdog_status_flags_t
+ * - true: related status flag has been set.
+ * - false: related status flag is not set.
+ */
+static inline uint32_t RTWDOG_GetStatusFlags(RTWDOG_Type *base)
+{
+ return (base->CS & (RTWDOG_CS_EN_MASK | RTWDOG_CS_FLG_MASK));
+}
+
+/*!
+ * @brief Enables/disables the window mode.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param enable Enables(true) or disables(false) the feature.
+ */
+static inline void RTWDOG_EnableWindowMode(RTWDOG_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CS |= RTWDOG_CS_WIN_MASK;
+ }
+ else
+ {
+ base->CS &= ~RTWDOG_CS_WIN_MASK;
+ }
+}
+
+/*!
+ * @brief Converts raw count value to millisecond.
+ *
+ * Note that if the clock frequency is too high the timeout period can be less than 1 ms.
+ * In this case this api will return 0 value.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param count Raw count value.
+ * @param clockFreqInHz The frequency of the clock source RTWDOG uses.
+ */
+static inline uint32_t RTWDOG_CountToMesec(RTWDOG_Type *base, uint32_t count, uint32_t clockFreqInHz)
+{
+ if ((base->CS & RTWDOG_CS_PRES_MASK) != 0U)
+ {
+ clockFreqInHz /= 256U;
+ }
+ return count * 1000U / clockFreqInHz;
+}
+
+/*!
+ * @brief Clears the RTWDOG flag.
+ *
+ * This function clears the RTWDOG status flag.
+ *
+ * Example to clear an interrupt flag:
+ * @code
+ * RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag);
+ * @endcode
+ * @param base RTWDOG peripheral base address.
+ * @param mask The status flags to clear.
+ * The parameter can be any combination of the following values:
+ * @arg kRTWDOG_InterruptFlag
+ */
+void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask);
+
+/*!
+ * @brief Sets the RTWDOG timeout value.
+ *
+ * This function writes a timeout value into the WDOG_TOVAL register.
+ * The WDOG_TOVAL register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address
+ * @param timeoutCount RTWDOG timeout value, count of RTWDOG clock ticks.
+ */
+static inline void RTWDOG_SetTimeoutValue(RTWDOG_Type *base, uint16_t timeoutCount)
+{
+ base->TOVAL = timeoutCount;
+}
+
+/*!
+ * @brief Sets the RTWDOG window value.
+ *
+ * This function writes a window value into the WDOG_WIN register.
+ * The WDOG_WIN register is a write-once register. Ensure that the WCT window is still open and
+ * this register has not been written in this WCT while the function is called.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @param windowValue RTWDOG window value.
+ */
+static inline void RTWDOG_SetWindowValue(RTWDOG_Type *base, uint16_t windowValue)
+{
+ base->WIN = windowValue;
+}
+
+/*!
+ * @brief Unlocks the RTWDOG register written.
+ *
+ * This function unlocks the RTWDOG register written.
+ *
+ * Before starting the unlock sequence and following the configuration, disable the global interrupts.
+ * Otherwise, an interrupt could effectively invalidate the unlock sequence and the WCT may expire.
+ * After the configuration finishes, re-enable the global interrupts.
+ *
+ * @param base RTWDOG peripheral base address
+ */
+__STATIC_FORCEINLINE void RTWDOG_Unlock(RTWDOG_Type *base)
+{
+ if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U)
+ {
+ base->CNT = RTWDOG_UPDATE_KEY;
+ }
+ else
+ {
+ base->CNT = WDOG_FIRST_WORD_OF_UNLOCK;
+ base->CNT = WDOG_SECOND_WORD_OF_UNLOCK;
+ }
+ while ((base->CS & RTWDOG_CS_ULK_MASK) == 0U)
+ {
+ }
+}
+
+/*!
+ * @brief Refreshes the RTWDOG timer.
+ *
+ * This function feeds the RTWDOG.
+ * This function should be called before the Watchdog timer is in timeout. Otherwise, a reset is asserted.
+ *
+ * @param base RTWDOG peripheral base address
+ */
+static inline void RTWDOG_Refresh(RTWDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+ primaskValue = DisableGlobalIRQ();
+ if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U)
+ {
+ base->CNT = RTWDOG_REFRESH_KEY;
+ }
+ else
+ {
+ base->CNT = WDOG_FIRST_WORD_OF_REFRESH;
+ base->CNT = WDOG_SECOND_WORD_OF_REFRESH;
+ }
+ EnableGlobalIRQ(primaskValue);
+}
+
+/*!
+ * @brief Gets the RTWDOG counter value.
+ *
+ * This function gets the RTWDOG counter value.
+ *
+ * @param base RTWDOG peripheral base address.
+ * @return Current RTWDOG counter value.
+ */
+static inline uint16_t RTWDOG_GetCounterValue(RTWDOG_Type *base)
+{
+ return (uint16_t)base->CNT;
+}
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/
+
+#endif /* _FSL_RTWDOG_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.c b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.c
new file mode 100644
index 0000000000..1e37b4cd8f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.c
@@ -0,0 +1,3831 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_sai.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.sai"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief _sai_transfer_state sai transfer state.*/
+enum
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_Idle, /*!< Transfer is done. */
+ kSAI_Error /*!< Transfer error occurred. */
+};
+
+/*! @brief Typedef for sai tx interrupt handler. */
+typedef void (*sai_tx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*! @brief Typedef for sai rx interrupt handler. */
+typedef void (*sai_rx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*! @brief check flag avalibility */
+#define IS_SAI_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief sai get rx enabled interrupt status.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param enableFlag enable flag to check.
+ * @param statusFlag status flag to check.
+ */
+static bool SAI_RxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+/*!
+ * @brief sai get tx enabled interrupt status.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param enableFlag enable flag to check.
+ * @param statusFlag status flag to check.
+ */
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+/*!
+ * @brief Set the master clock divider.
+ *
+ * This API will compute the master clock divider according to master clock frequency and master
+ * clock source clock source frequency.
+ *
+ * @param base SAI base pointer.
+ * @param mclk_Hz Mater clock frequency in Hz.
+ * @param mclkSrcClock_Hz Master clock source frequency in Hz.
+ */
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+
+/*!
+ * @brief Set the master clock divider.
+ *
+ * This API will compute the master clock divider according to master clock frequency and master
+ * clock source clock source frequency.
+ *
+ * @param base SAI base pointer.
+ * @param mclk_Hz Mater clock frequency in Hz.
+ * @param mclkSrcClock_Hz Master clock source frequency in Hz.
+ */
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz);
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+static uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief sends a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel start channel number.
+ * @param channelMask enabled channels mask.
+ * @param endChannel end channel numbers.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+static void SAI_WriteNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size);
+
+/*!
+ * @brief Receive a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel start channel number.
+ * @param channelMask enabled channels mask.
+ * @param endChannel end channel numbers.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+static void SAI_ReadNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size);
+
+/*!
+ * @brief Get classic I2S mode configurations.
+ *
+ * @param config transceiver configurations
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel
+ * @param saiChannelMask channel mask value to enable
+ */
+static void SAI_GetCommonConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
+/*!@brief SAI handle pointer */
+static sai_handle_t *s_saiHandle[ARRAY_SIZE(s_saiBases)][2];
+/* IRQ number array */
+static const IRQn_Type s_saiTxIRQ[] = I2S_TX_IRQS;
+static const IRQn_Type s_saiRxIRQ[] = I2S_RX_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_saiClock[] = SAI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_tx_isr_t s_saiTxIsr;
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_rx_isr_t s_saiRxIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SAI_RxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag)
+{
+ uint32_t rcsr = base->RCSR;
+
+ return IS_SAI_FLAG_SET(rcsr, enableFlag) && IS_SAI_FLAG_SET(rcsr, statusFlag);
+}
+
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag)
+{
+ uint32_t tcsr = base->TCSR;
+
+ return IS_SAI_FLAG_SET(tcsr, enableFlag) && IS_SAI_FLAG_SET(tcsr, statusFlag);
+}
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz)
+{
+ assert(mclk_Hz <= mclkSrcClock_Hz);
+
+ uint32_t sourceFreq = mclkSrcClock_Hz / 100U; /*In order to prevent overflow */
+ uint32_t targetFreq = mclk_Hz / 100U; /*In order to prevent overflow */
+
+#if FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV
+ uint32_t postDivider = sourceFreq / targetFreq;
+
+ /* if source equal to target, then disable divider */
+ if (postDivider == 1U)
+ {
+ base->MCR &= ~I2S_MCR_DIVEN_MASK;
+ }
+ else
+ {
+ base->MCR = (base->MCR & (~I2S_MCR_DIV_MASK)) | I2S_MCR_DIV(postDivider / 2U - 1U) | I2S_MCR_DIVEN_MASK;
+ }
+#endif
+#if FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER
+ uint16_t fract, divide;
+ uint32_t remaind = 0;
+ uint32_t current_remainder = 0xFFFFFFFFU;
+ uint16_t current_fract = 0;
+ uint16_t current_divide = 0;
+ uint32_t mul_freq = 0;
+ uint32_t max_fract = 256;
+
+ /* Compute the max fract number */
+ max_fract = targetFreq * 4096U / sourceFreq + 1U;
+ if (max_fract > 256U)
+ {
+ max_fract = 256U;
+ }
+
+ /* Looking for the closet frequency */
+ for (fract = 1; fract < max_fract; fract++)
+ {
+ mul_freq = sourceFreq * fract;
+ remaind = mul_freq % targetFreq;
+ divide = (uint16_t)(mul_freq / targetFreq);
+
+ /* Find the exactly frequency */
+ if (remaind == 0U)
+ {
+ current_fract = fract;
+ current_divide = (uint16_t)(mul_freq / targetFreq);
+ break;
+ }
+
+ /* Closer to next one, set the closest to next data */
+ if (remaind > mclk_Hz / 2U)
+ {
+ remaind = targetFreq - remaind;
+ divide += 1U;
+ }
+
+ /* Update the closest div and fract */
+ if (remaind < current_remainder)
+ {
+ current_fract = fract;
+ current_divide = divide;
+ current_remainder = remaind;
+ }
+ }
+
+ /* Fill the computed fract and divider to registers */
+ base->MDR = I2S_MDR_DIVIDE(current_divide - 1UL) | I2S_MDR_FRACT(current_fract - 1UL);
+
+ /* Waiting for the divider updated */
+ while ((base->MCR & I2S_MCR_DUF_MASK) != 0UL)
+ {
+ }
+#endif
+}
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+static uint32_t SAI_GetInstance(I2S_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_saiBases); instance++)
+ {
+ if (s_saiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_saiBases));
+
+ return instance;
+}
+
+static void SAI_WriteNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size)
+{
+ uint32_t i = 0, j = 0U;
+ uint8_t m = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+ uint32_t temp = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = channel; j <= endChannel; j++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << j), channelMask))
+ {
+ for (m = 0; m < bytesPerWord; m++)
+ {
+ temp = (uint32_t)(*buffer);
+ data |= (temp << (8U * m));
+ buffer++;
+ }
+ base->TDR[j] = data;
+ data = 0;
+ }
+ }
+ }
+}
+
+static void SAI_ReadNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size)
+{
+ uint32_t i = 0, j = 0;
+ uint8_t m = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = channel; j <= endChannel; j++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << j), channelMask))
+ {
+ data = base->RDR[j];
+ for (m = 0; m < bytesPerWord; m++)
+ {
+ *buffer = (uint8_t)(data >> (8U * m)) & 0xFFU;
+ buffer++;
+ }
+ }
+ }
+ }
+}
+
+static void SAI_GetCommonConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ (void)memset(config, 0, sizeof(sai_transceiver_t));
+
+ config->channelMask = (uint8_t)saiChannelMask;
+ /* sync mode default configurations */
+ config->syncMode = kSAI_ModeAsync;
+
+ /* master mode default */
+ config->masterSlave = kSAI_Master;
+
+ /* bit default configurations */
+ config->bitClock.bclkSrcSwap = false;
+ config->bitClock.bclkInputDelay = false;
+ config->bitClock.bclkPolarity = kSAI_SampleOnRisingEdge;
+ config->bitClock.bclkSource = kSAI_BclkSourceMclkDiv;
+
+ /* frame sync default configurations */
+ config->frameSync.frameSyncWidth = (uint8_t)bitWidth;
+ config->frameSync.frameSyncEarly = true;
+#if defined(FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE) && FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE
+ config->frameSync.frameSyncGenerateOnDemand = false;
+#endif
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveLow;
+
+ /* serial data default configurations */
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+ config->serialData.dataMode = kSAI_DataPinStateOutputZero;
+#endif
+ config->serialData.dataOrder = kSAI_DataMSB;
+ config->serialData.dataWord0Length = (uint8_t)bitWidth;
+ config->serialData.dataWordLength = (uint8_t)bitWidth;
+ config->serialData.dataWordNLength = (uint8_t)bitWidth;
+ config->serialData.dataFirstBitShifted = (uint8_t)bitWidth;
+ config->serialData.dataWordNum = 2U;
+ config->serialData.dataMaskedWord = (uint32_t)mode;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ config->fifo.fifoContinueOneError = true;
+#endif
+}
+
+/*!
+ * brief Initializes the SAI Tx peripheral.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures SAI Tx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_TxGetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAIM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SAI base pointer
+ * param config SAI configuration structure.
+ */
+void SAI_TxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SAI clock */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ SAI_TxReset(base);
+
+ /* Configure audio protocol */
+ if (config->protocol == kSAI_BusLeftJustified)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusRightJustified)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusI2S)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(1U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusPCMA)
+ {
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->TCR2 |= I2S_TCR2_BCD_MASK;
+ base->TCR4 |= I2S_TCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->TCR2 & (~I2S_TCR2_MSEL_MASK);
+ base->TCR2 = (val | I2S_TCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCD_MASK;
+ base->TCR4 &= ~I2S_TCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(1U));
+ /* If sync with Rx, should set Rx to async mode */
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ SAI_TxSetFIFOErrorContinue(base, true);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR */
+}
+
+/*!
+ * brief Initializes the SAI Rx peripheral.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures the SAI Rx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_RxGetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAI module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SAI base pointer
+ * param config SAI configuration structure.
+ */
+void SAI_RxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable SAI clock first. */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ SAI_RxReset(base);
+
+ /* Configure audio protocol */
+ if (config->protocol == kSAI_BusLeftJustified)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusRightJustified)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusI2S)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(1U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusPCMA)
+ {
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->RCR2 |= I2S_RCR2_BCD_MASK;
+ base->RCR4 |= I2S_RCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->RCR2 & (~I2S_RCR2_MSEL_MASK);
+ base->RCR2 = (val | I2S_RCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCD_MASK;
+ base->RCR4 &= ~I2S_RCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(1U));
+ /* If sync with Tx, should set Tx to async mode */
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ SAI_RxSetFIFOErrorContinue(base, true);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR */
+}
+
+/*!
+ * brief Initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_Init is called to enable the clock.
+ *
+ * param base SAI base pointer
+ */
+void SAI_Init(I2S_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SAI clock */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* disable interrupt and DMA request*/
+ base->TCSR &=
+ ~(I2S_TCSR_FRIE_MASK | I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK | I2S_TCSR_FRDE_MASK | I2S_TCSR_FWDE_MASK);
+ base->RCSR &=
+ ~(I2S_RCSR_FRIE_MASK | I2S_RCSR_FWIE_MASK | I2S_RCSR_FEIE_MASK | I2S_RCSR_FRDE_MASK | I2S_RCSR_FWDE_MASK);
+#else
+ /* disable interrupt and DMA request*/
+ base->TCSR &= ~(I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK | I2S_TCSR_FWDE_MASK);
+ base->RCSR &= ~(I2S_RCSR_FWIE_MASK | I2S_RCSR_FEIE_MASK | I2S_RCSR_FWDE_MASK);
+#endif
+}
+
+/*!
+ * brief De-initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_TxInit
+ * or SAI_RxInit is called to enable the clock.
+ *
+ * param base SAI base pointer
+ */
+void SAI_Deinit(I2S_Type *base)
+{
+ SAI_TxEnable(base, false);
+ SAI_RxEnable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ (void)CLOCK_DisableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the SAI Tx configuration structure to default values.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref
+ * SAI_GetClassicI2SConfig, SAI_GetLeftJustifiedConfig,SAI_GetRightJustifiedConfig, SAI_GetDSPConfig,SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_TxConfig().
+ * The initialized structure can remain unchanged in SAI_TxConfig(), or it can be modified
+ * before calling SAI_TxConfig().
+ * This is an example.
+ code
+ sai_config_t config;
+ SAI_TxGetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SAI_TxGetDefaultConfig(sai_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ config->mclkSource = kSAI_MclkSourceSysclk;
+#endif
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+ config->protocol = kSAI_BusI2S;
+ config->syncMode = kSAI_ModeAsync;
+}
+
+/*!
+ * brief Sets the SAI Rx configuration structure to default values.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref
+ * SAI_GetClassicI2SConfig,SAI_GetLeftJustifiedConfig,SAI_GetRightJustifiedConfig,SAI_GetDSPConfig,SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_RxConfig().
+ * The initialized structure can remain unchanged in SAI_RxConfig() or it can be modified
+ * before calling SAI_RxConfig().
+ * This is an example.
+ code
+ sai_config_t config;
+ SAI_RxGetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SAI_RxGetDefaultConfig(sai_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ config->mclkSource = kSAI_MclkSourceSysclk;
+#endif
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+ config->protocol = kSAI_BusI2S;
+ config->syncMode = kSAI_ModeSync;
+}
+
+/*!
+ * brief Resets the SAI Tx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Tx. After reset, clear the reset bit.
+ *
+ * param base SAI base pointer
+ */
+void SAI_TxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->TCSR = I2S_TCSR_SR_MASK | I2S_TCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+
+ /* Reset all Tx register values */
+ base->TCR2 = 0;
+ base->TCR3 = 0;
+ base->TCR4 = 0;
+ base->TCR5 = 0;
+ base->TMR = 0;
+}
+
+/*!
+ * brief Resets the SAI Rx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Rx. After reset, clear the reset bit.
+ *
+ * param base SAI base pointer
+ */
+void SAI_RxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->RCSR = I2S_RCSR_SR_MASK | I2S_RCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+
+ /* Reset all Rx register values */
+ base->RCR2 = 0;
+ base->RCR3 = 0;
+ base->RCR4 = 0;
+ base->RCR5 = 0;
+ base->RMR = 0;
+}
+
+/*!
+ * brief Enables/disables the SAI Tx.
+ *
+ * param base SAI base pointer
+ * param enable True means enable SAI Tx, false means disable.
+ */
+void SAI_TxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Rx, should enable RE bit. */
+ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ }
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ /* Also need to clear the FIFO error flag before start */
+ SAI_TxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+ }
+ else
+ {
+ /* If Rx not in sync with Tx, then disable Tx, otherwise, shall not disable Tx */
+ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) != 0x1U)
+ {
+ /* Disable TE bit */
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
+ }
+ }
+}
+
+/*!
+ * brief Enables/disables the SAI Rx.
+ *
+ * param base SAI base pointer
+ * param enable True means enable SAI Rx, false means disable.
+ */
+void SAI_RxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Tx, should enable TE bit. */
+ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ }
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ /* Also need to clear the FIFO error flag before start */
+ SAI_RxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+ }
+ else
+ {
+ /* If Tx not in sync with Rx, then disable Rx, otherwise, shall not disable Rx */
+ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) != 0x1U)
+ {
+ /* Disable RE bit */
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
+ }
+ }
+}
+
+/*!
+ * brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Tx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like TCR1~TCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * param base SAI base pointer
+ * param resetType Reset type, FIFO reset or software reset
+ */
+void SAI_TxSoftwareReset(I2S_Type *base, sai_reset_type_t resetType)
+{
+ base->TCSR |= (uint32_t)resetType;
+
+ /* Clear the software reset */
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+}
+
+/*!
+ * brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Rx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like RCR1~RCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * param base SAI base pointer
+ * param resetType Reset type, FIFO reset or software reset
+ */
+void SAI_RxSoftwareReset(I2S_Type *base, sai_reset_type_t resetType)
+{
+ base->RCSR |= (uint32_t)resetType;
+
+ /* Clear the software reset */
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+}
+
+/*!
+ * brief Set the Tx channel FIFO enable mask.
+ *
+ * param base SAI base pointer
+ * param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_TxSetChannelFIFOMask(I2S_Type *base, uint8_t mask)
+{
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(mask);
+}
+
+/*!
+ * brief Set the Rx channel FIFO enable mask.
+ *
+ * param base SAI base pointer
+ * param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_RxSetChannelFIFOMask(I2S_Type *base, uint8_t mask)
+{
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ base->RCR3 |= I2S_RCR3_RCE(mask);
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetDataOrder(I2S_Type *base, sai_data_order_t order)
+{
+ uint32_t val = (base->TCR4) & (~I2S_TCR4_MF_MASK);
+
+ val |= I2S_TCR4_MF(order);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetDataOrder(I2S_Type *base, sai_data_order_t order)
+{
+ uint32_t val = (base->RCR4) & (~I2S_RCR4_MF_MASK);
+
+ val |= I2S_RCR4_MF(order);
+ base->RCR4 = val;
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->TCR2) & (~I2S_TCR2_BCP_MASK);
+
+ val |= I2S_TCR2_BCP(polarity);
+ base->TCR2 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->RCR2) & (~I2S_RCR2_BCP_MASK);
+
+ val |= I2S_RCR2_BCP(polarity);
+ base->RCR2 = val;
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->TCR4) & (~I2S_TCR4_FSP_MASK);
+
+ val |= I2S_TCR4_FSP(polarity);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->RCR4) & (~I2S_RCR4_FSP_MASK);
+
+ val |= I2S_RCR4_FSP(polarity);
+ base->RCR4 = val;
+}
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+/*!
+ * brief Set Tx FIFO packing feature.
+ *
+ * param base SAI base pointer.
+ * param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_TxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack)
+{
+ uint32_t val = base->TCR4;
+
+ val &= ~I2S_TCR4_FPACK_MASK;
+ val |= I2S_TCR4_FPACK(pack);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set Rx FIFO packing feature.
+ *
+ * param base SAI base pointer.
+ * param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_RxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack)
+{
+ uint32_t val = base->RCR4;
+
+ val &= ~I2S_RCR4_FPACK_MASK;
+ val |= I2S_RCR4_FPACK(pack);
+ base->RCR4 = val;
+}
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_PACKING */
+
+/*!
+ * brief Transmitter bit clock rate configurations.
+ *
+ * param base SAI base pointer.
+ * param sourceClockHz, bit clock source frequency.
+ * param sampleRate audio data sample rate.
+ * param bitWidth, audio data bitWidth.
+ * param channelNumbers, audio channel numbers.
+ */
+void SAI_TxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers)
+{
+ uint32_t tcr2 = base->TCR2;
+ uint32_t bitClockDiv = 0;
+ uint32_t bitClockFreq = sampleRate * bitWidth * channelNumbers;
+
+ assert(sourceClockHz >= bitClockFreq);
+
+ tcr2 &= ~I2S_TCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ bitClockDiv = sourceClockHz / bitClockFreq;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (bitClockDiv == 0U)
+ {
+ bitClockDiv++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((sourceClockHz / bitClockDiv) > bitClockFreq)
+ {
+ bitClockDiv++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (bitClockDiv == 1U)
+ {
+ tcr2 |= I2S_TCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ tcr2 |= I2S_TCR2_DIV(bitClockDiv / 2U - 1UL);
+ }
+
+ base->TCR2 = tcr2;
+}
+
+/*!
+ * brief Receiver bit clock rate configurations.
+ *
+ * param base SAI base pointer.
+ * param sourceClockHz, bit clock source frequency.
+ * param sampleRate audio data sample rate.
+ * param bitWidth, audio data bitWidth.
+ * param channelNumbers, audio channel numbers.
+ */
+void SAI_RxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers)
+{
+ uint32_t rcr2 = base->RCR2;
+ uint32_t bitClockDiv = 0;
+ uint32_t bitClockFreq = sampleRate * bitWidth * channelNumbers;
+
+ assert(sourceClockHz >= bitClockFreq);
+
+ rcr2 &= ~I2S_RCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ bitClockDiv = sourceClockHz / bitClockFreq;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (bitClockDiv == 0U)
+ {
+ bitClockDiv++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((sourceClockHz / bitClockDiv) > bitClockFreq)
+ {
+ bitClockDiv++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (bitClockDiv == 1U)
+ {
+ rcr2 |= I2S_RCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ rcr2 |= I2S_RCR2_DIV(bitClockDiv / 2U - 1UL);
+ }
+
+ base->RCR2 = rcr2;
+}
+
+/*!
+ * brief Transmitter Bit clock configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config)
+{
+ uint32_t tcr2 = base->TCR2;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Master_FrameSync_Slave))
+ {
+ assert(config != NULL);
+
+ tcr2 &= ~(I2S_TCR2_BCD_MASK | I2S_TCR2_BCP_MASK | I2S_TCR2_BCI_MASK | I2S_TCR2_BCS_MASK | I2S_TCR2_MSEL_MASK);
+ tcr2 |= I2S_TCR2_BCD(1U) | I2S_TCR2_BCP(config->bclkPolarity) | I2S_TCR2_BCI(config->bclkInputDelay) |
+ I2S_TCR2_BCS(config->bclkSrcSwap) | I2S_TCR2_MSEL(config->bclkSource);
+ }
+ else
+ {
+ tcr2 &= ~(I2S_TCR2_BCD_MASK);
+ tcr2 |= I2S_TCR2_BCP(config->bclkPolarity);
+ }
+
+ base->TCR2 = tcr2;
+}
+
+/*!
+ * brief Receiver Bit clock configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config)
+{
+ uint32_t rcr2 = base->RCR2;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Master_FrameSync_Slave))
+ {
+ assert(config != NULL);
+
+ rcr2 &= ~(I2S_RCR2_BCD_MASK | I2S_RCR2_BCP_MASK | I2S_RCR2_BCI_MASK | I2S_RCR2_BCS_MASK | I2S_RCR2_MSEL_MASK);
+ rcr2 |= I2S_RCR2_BCD(1U) | I2S_RCR2_BCP(config->bclkPolarity) | I2S_RCR2_BCI(config->bclkInputDelay) |
+ I2S_RCR2_BCS(config->bclkSrcSwap) | I2S_RCR2_MSEL(config->bclkSource);
+ }
+ else
+ {
+ rcr2 &= ~(I2S_RCR2_BCD_MASK);
+ rcr2 |= I2S_RCR2_BCP(config->bclkPolarity);
+ }
+
+ base->RCR2 = rcr2;
+}
+
+#if (defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER))
+/*!
+ * brief Master clock configurations.
+ *
+ * param base SAI base pointer.
+ * param config master clock configurations.
+ */
+void SAI_SetMasterClockConfig(I2S_Type *base, sai_master_clock_t *config)
+{
+ assert(config != NULL);
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ uint32_t val = 0;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+ /* Check if master clock divider enabled, then set master clock divider */
+ if (config->mclkOutputEnable)
+ {
+ SAI_SetMasterClockDivider(base, config->mclkHz, config->mclkSourceClkHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+}
+#endif
+
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+/*!
+ * brief SAI transmitter fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param config fifo configurations.
+ */
+void SAI_TxSetFifoConfig(I2S_Type *base, sai_fifo_t *config)
+{
+ assert(config != NULL);
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((config->fifoWatermark == 0U) ||
+ (config->fifoWatermark > (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base))))
+ {
+ config->fifoWatermark = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) / 2U);
+ }
+#endif
+
+ uint32_t tcr4 = base->TCR4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+ tcr4 &= ~I2S_TCR4_FCOMB_MASK;
+ tcr4 |= I2S_TCR4_FCOMB(config->fifoCombine);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ tcr4 &= ~I2S_TCR4_FCONT_MASK;
+ /* ERR05144: not set FCONT = 1 when TMR > 0, the transmit shift register may not load correctly that will cause TX
+ * not work */
+ if (base->TMR == 0U)
+ {
+ tcr4 |= I2S_TCR4_FCONT(config->fifoContinueOneError);
+ }
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+ tcr4 &= ~I2S_TCR4_FPACK_MASK;
+ tcr4 |= I2S_TCR4_FPACK(config->fifoPacking);
+#endif
+
+ base->TCR4 = tcr4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ base->TCR1 = (base->TCR1 & (~I2S_TCR1_TFW_MASK)) | I2S_TCR1_TFW(config->fifoWatermark);
+#endif
+}
+
+/*!
+ * brief SAI receiver fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param config fifo configurations.
+ */
+void SAI_RxSetFifoConfig(I2S_Type *base, sai_fifo_t *config)
+{
+ assert(config != NULL);
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((config->fifoWatermark == 0U) ||
+ (config->fifoWatermark > (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base))))
+ {
+ config->fifoWatermark = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) / 2U);
+ }
+#endif
+ uint32_t rcr4 = base->RCR4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+ rcr4 &= ~I2S_RCR4_FCOMB_MASK;
+ rcr4 |= I2S_RCR4_FCOMB(config->fifoCombine);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ rcr4 &= ~I2S_RCR4_FCONT_MASK;
+ rcr4 |= I2S_RCR4_FCONT(config->fifoContinueOneError);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+ rcr4 &= ~I2S_RCR4_FPACK_MASK;
+ rcr4 |= I2S_RCR4_FPACK(config->fifoPacking);
+#endif
+
+ base->RCR4 = rcr4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ base->RCR1 = (base->RCR1 & (~I2S_RCR1_RFW_MASK)) | I2S_RCR1_RFW(config->fifoWatermark);
+#endif
+}
+#endif
+
+/*!
+ * brief SAI transmitter Frame sync configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config)
+{
+ assert(config != NULL);
+ assert((config->frameSyncWidth - 1UL) <= (I2S_TCR4_SYWD_MASK >> I2S_TCR4_SYWD_SHIFT));
+
+ uint32_t tcr4 = base->TCR4;
+
+ tcr4 &= ~(I2S_TCR4_FSE_MASK | I2S_TCR4_FSP_MASK | I2S_TCR4_FSD_MASK | I2S_TCR4_SYWD_MASK);
+
+#if defined(FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE) && FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE
+ tcr4 &= ~I2S_TCR4_ONDEM_MASK;
+ tcr4 |= I2S_TCR4_ONDEM(config->frameSyncGenerateOnDemand);
+#endif
+
+ tcr4 |=
+ I2S_TCR4_FSE(config->frameSyncEarly) | I2S_TCR4_FSP(config->frameSyncPolarity) |
+ I2S_TCR4_FSD(((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Slave_FrameSync_Master)) ? 1UL : 0U) |
+ I2S_TCR4_SYWD(config->frameSyncWidth - 1UL);
+
+ base->TCR4 = tcr4;
+}
+
+/*!
+ * brief SAI receiver Frame sync configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config)
+{
+ assert(config != NULL);
+ assert((config->frameSyncWidth - 1UL) <= (I2S_RCR4_SYWD_MASK >> I2S_RCR4_SYWD_SHIFT));
+
+ uint32_t rcr4 = base->RCR4;
+
+ rcr4 &= ~(I2S_RCR4_FSE_MASK | I2S_RCR4_FSP_MASK | I2S_RCR4_FSD_MASK | I2S_RCR4_SYWD_MASK);
+
+#if defined(FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE) && FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE
+ rcr4 &= ~I2S_RCR4_ONDEM_MASK;
+ rcr4 |= I2S_RCR4_ONDEM(config->frameSyncGenerateOnDemand);
+#endif
+
+ rcr4 |=
+ I2S_RCR4_FSE(config->frameSyncEarly) | I2S_RCR4_FSP(config->frameSyncPolarity) |
+ I2S_RCR4_FSD(((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Slave_FrameSync_Master)) ? 1UL : 0U) |
+ I2S_RCR4_SYWD(config->frameSyncWidth - 1UL);
+
+ base->RCR4 = rcr4;
+}
+
+/*!
+ * brief SAI transmitter Serial data configurations.
+ *
+ * param base SAI base pointer.
+ * param config serial data configurations.
+ */
+void SAI_TxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t tcr4 = base->TCR4;
+
+ base->TCR5 = I2S_TCR5_WNW(config->dataWordNLength - 1UL) | I2S_TCR5_W0W(config->dataWord0Length - 1UL) |
+ I2S_TCR5_FBT(config->dataFirstBitShifted - 1UL);
+ base->TMR = config->dataMaskedWord;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ /* ERR05144: not set FCONT = 1 when TMR > 0, the transmit shift register may not load correctly that will cause TX
+ * not work */
+ if (config->dataMaskedWord > 0U)
+ {
+ tcr4 &= ~I2S_TCR4_FCONT_MASK;
+ }
+#endif
+ tcr4 &= ~(I2S_TCR4_FRSZ_MASK | I2S_TCR4_MF_MASK);
+ tcr4 |= I2S_TCR4_FRSZ(config->dataWordNum - 1UL) | I2S_TCR4_MF(config->dataOrder);
+
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+ tcr4 &= ~I2S_TCR4_CHMOD_MASK;
+ tcr4 |= I2S_TCR4_CHMOD(config->dataMode);
+#endif
+
+ base->TCR4 = tcr4;
+}
+
+/*!
+ * @brief SAI receiver Serial data configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config serial data configurations.
+ */
+void SAI_RxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t rcr4 = base->RCR4;
+
+ base->RCR5 = I2S_RCR5_WNW(config->dataWordNLength - 1UL) | I2S_RCR5_W0W(config->dataWord0Length - 1UL) |
+ I2S_RCR5_FBT(config->dataFirstBitShifted - 1UL);
+ base->RMR = config->dataMaskedWord;
+
+ rcr4 &= ~(I2S_RCR4_FRSZ_MASK | I2S_RCR4_MF_MASK);
+ rcr4 |= I2S_RCR4_FRSZ(config->dataWordNum - 1uL) | I2S_RCR4_MF(config->dataOrder);
+
+ base->RCR4 = rcr4;
+}
+
+/*!
+ * brief SAI transmitter configurations.
+ *
+ * param base SAI base pointer.
+ * param config transmitter configurations.
+ */
+void SAI_TxSetConfig(I2S_Type *base, sai_transceiver_t *config)
+{
+ assert(config != NULL);
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint8_t i = 0U;
+ uint32_t val = 0U;
+ uint8_t channelNums = 0U;
+
+ /* reset transmitter */
+ SAI_TxReset(base);
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (config->channelMask == 0U)
+ {
+ config->channelMask = 1U << config->startChannel;
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET(1UL << i, config->channelMask))
+ {
+ channelNums++;
+ config->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ config->startChannel = i;
+ break;
+ }
+ }
+
+ config->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (config->channelNums > 1U)
+ {
+ base->TCR4 &= ~I2S_TCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(config->channelMask);
+
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(1U));
+ /* If sync with Rx, should set Rx to async mode */
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+ /* bit clock configurations */
+ SAI_TxSetBitclockConfig(base, config->masterSlave, &config->bitClock);
+ /* serial data configurations */
+ SAI_TxSetSerialDataConfig(base, &config->serialData);
+ /* frame sync configurations */
+ SAI_TxSetFrameSyncConfig(base, config->masterSlave, &config->frameSync);
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+ /* fifo configurations */
+ SAI_TxSetFifoConfig(base, &config->fifo);
+#endif
+}
+
+/*!
+ * brief SAI transmitter transfer configurations.
+ *
+ * This function initializes the TX, include bit clock, frame sync, master clock, serial data and fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param config tranmitter configurations.
+ */
+void SAI_TransferTxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+ assert(config->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ handle->bitWidth = config->frameSync.frameSyncWidth;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((config->fifo.fifoWatermark == 0U) ||
+ (config->fifo.fifoWatermark > (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base))))
+ {
+ config->fifo.fifoWatermark = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) / 2U);
+ }
+ handle->watermark = config->fifo.fifoWatermark;
+#endif
+
+ /* transmitter configurations */
+ SAI_TxSetConfig(base, config);
+
+ handle->channel = config->startChannel;
+ /* used for multi channel */
+ handle->channelMask = config->channelMask;
+ handle->channelNums = config->channelNums;
+ handle->endChannel = config->endChannel;
+}
+
+/*!
+ * brief SAI receiver configurations.
+ *
+ * param base SAI base pointer.
+ * param config transmitter configurations.
+ */
+void SAI_RxSetConfig(I2S_Type *base, sai_transceiver_t *config)
+{
+ assert(config != NULL);
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint8_t i = 0U;
+ uint32_t val = 0U;
+ uint8_t channelNums = 0U;
+
+ /* reset receiver */
+ SAI_RxReset(base);
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (config->channelMask == 0U)
+ {
+ config->channelMask = 1U << config->startChannel;
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ channelNums++;
+ config->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ config->startChannel = i;
+ break;
+ }
+ }
+
+ config->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (config->channelNums > 1U)
+ {
+ base->RCR4 &= ~I2S_RCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ base->RCR3 |= I2S_RCR3_RCE(config->channelMask);
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(1U));
+ /* If sync with Tx, should set Tx to async mode */
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+ /* bit clock configurations */
+ SAI_RxSetBitclockConfig(base, config->masterSlave, &config->bitClock);
+ /* serial data configurations */
+ SAI_RxSetSerialDataConfig(base, &config->serialData);
+ /* frame sync configurations */
+ SAI_RxSetFrameSyncConfig(base, config->masterSlave, &config->frameSync);
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+ /* fifo configurations */
+ SAI_RxSetFifoConfig(base, &config->fifo);
+#endif
+}
+
+/*!
+ * brief SAI receiver transfer configurations.
+ *
+ * This function initializes the TX, include bit clock, frame sync, master clock, serial data and fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param config tranmitter configurations.
+ */
+void SAI_TransferRxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+
+ handle->bitWidth = config->frameSync.frameSyncWidth;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((config->fifo.fifoWatermark == 0U) ||
+ (config->fifo.fifoWatermark > (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base))))
+ {
+ config->fifo.fifoWatermark = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) / 2U);
+ }
+ handle->watermark = config->fifo.fifoWatermark;
+#endif
+
+ /* receiver configurations */
+ SAI_RxSetConfig(base, config);
+
+ handle->channel = config->startChannel;
+ /* used for multi channel */
+ handle->channelMask = config->channelMask;
+ handle->channelNums = config->channelNums;
+ handle->endChannel = config->endChannel;
+}
+
+/*!
+ * brief Get classic I2S mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetClassicI2SConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+}
+
+/*!
+ * brief Get left justified mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetLeftJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get right justified mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetRightJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get DSP mode configurations.
+ *
+ * note DSP mode is also called PCM mode which support MODE A and MODE B,
+ * DSP/PCM MODE A configuration flow. RX is similiar but uses SAI_RxSetConfig instead of SAI_TxSetConfig:
+ * code
+ * SAI_GetDSPConfig(config, kSAI_FrameSyncLenOneBitClk, bitWidth, kSAI_Stereo, channelMask)
+ * config->frameSync.frameSyncEarly = true;
+ * SAI_TxSetConfig(base, config)
+ * endcode
+ *
+ * DSP/PCM MODE B configuration flow for TX. RX is similiar but uses SAI_RxSetConfig instead of SAI_TxSetConfig:
+ * code
+ * SAI_GetDSPConfig(config, kSAI_FrameSyncLenOneBitClk, bitWidth, kSAI_Stereo, channelMask)
+ * SAI_TxSetConfig(base, config)
+ * endcode
+ *
+ * param config transceiver configurations.
+ * param frameSyncWidth length of frame sync.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask mask value of the channel to enable.
+ */
+void SAI_GetDSPConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ /* frame sync default configurations */
+ switch (frameSyncWidth)
+ {
+ case kSAI_FrameSyncLenOneBitClk:
+ config->frameSync.frameSyncWidth = 1U;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get TDM mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetTDMConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ uint32_t dataWordNum,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+ assert(dataWordNum <= 32U);
+
+ SAI_GetCommonConfig(config, bitWidth, kSAI_Stereo, saiChannelMask);
+
+ /* frame sync default configurations */
+ switch (frameSyncWidth)
+ {
+ case kSAI_FrameSyncLenOneBitClk:
+ config->frameSync.frameSyncWidth = 1U;
+ break;
+ case kSAI_FrameSyncLenPerWordWidth:
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+ config->serialData.dataWordNum = (uint8_t)dataWordNum;
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_TxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t bclk = 0;
+ uint32_t val = 0;
+ uint8_t i = 0U, channelNums = 0U;
+ uint32_t divider = 0U;
+
+ if (format->isFrameSyncCompact)
+ {
+ bclk = format->sampleRate_Hz * format->bitWidth * (format->stereo == kSAI_Stereo ? 2U : 1U);
+ val = (base->TCR4 & (~I2S_TCR4_SYWD_MASK));
+ val |= I2S_TCR4_SYWD(format->bitWidth - 1U);
+ base->TCR4 = val;
+ }
+ else
+ {
+ bclk = format->sampleRate_Hz * 32U * 2U;
+ }
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled, then set master clock divider */
+ if (IS_SAI_FLAG_SET(base->MCR, I2S_MCR_MOE_MASK))
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (IS_SAI_FLAG_SET(base->TCR2, I2S_TCR2_BCD_MASK))
+ {
+ base->TCR2 &= ~I2S_TCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ divider = bclkSourceClockHz / bclk;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (divider == 0U)
+ {
+ divider++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((bclkSourceClockHz / divider) > bclk)
+ {
+ divider++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (divider == 1U)
+ {
+ base->TCR2 |= I2S_TCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ base->TCR2 |= I2S_TCR2_DIV(divider / 2U - 1U);
+ }
+ }
+
+ /* Set bitWidth */
+ val = (format->isFrameSyncCompact) ? (format->bitWidth - 1U) : 31U;
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(val);
+ }
+ else
+ {
+ if (IS_SAI_FLAG_SET(base->TCR4, I2S_TCR4_MF_MASK))
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(format->bitWidth - 1UL);
+ }
+ else
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(0);
+ }
+ }
+
+ /* Set mono or stereo */
+ base->TMR = (uint32_t)format->stereo;
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (format->channelMask == 0U)
+ {
+ format->channelMask = 1U << format->channel;
+ }
+
+ /* if channel nums is not set, calculate it here according to channelMask*/
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ channelNums++;
+ format->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ format->channel = i;
+ break;
+ }
+ }
+
+ format->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (format->channelNums > 1U)
+ {
+ base->TCR4 &= ~I2S_TCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(format->channelMask);
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Set watermark */
+ base->TCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_RxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_RxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t bclk = 0;
+ uint32_t val = 0;
+ uint8_t i = 0U, channelNums = 0U;
+ uint32_t divider = 0U;
+
+ if (format->isFrameSyncCompact)
+ {
+ bclk = format->sampleRate_Hz * format->bitWidth * (format->stereo == kSAI_Stereo ? 2U : 1U);
+ val = (base->RCR4 & (~I2S_RCR4_SYWD_MASK));
+ val |= I2S_RCR4_SYWD(format->bitWidth - 1U);
+ base->RCR4 = val;
+ }
+ else
+ {
+ bclk = format->sampleRate_Hz * 32U * 2U;
+ }
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled */
+ if (IS_SAI_FLAG_SET(base->MCR, I2S_MCR_MOE_MASK))
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (IS_SAI_FLAG_SET(base->RCR2, I2S_RCR2_BCD_MASK))
+ {
+ base->RCR2 &= ~I2S_RCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ divider = bclkSourceClockHz / bclk;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (divider == 0U)
+ {
+ divider++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((bclkSourceClockHz / divider) > bclk)
+ {
+ divider++;
+ }
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (divider == 1U)
+ {
+ base->RCR2 |= I2S_RCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ base->RCR2 |= I2S_RCR2_DIV(divider / 2U - 1U);
+ }
+ }
+
+ /* Set bitWidth */
+ val = (format->isFrameSyncCompact) ? (format->bitWidth - 1U) : 31U;
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(val);
+ }
+ else
+ {
+ if (IS_SAI_FLAG_SET(base->RCR4, I2S_RCR4_MF_MASK))
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(format->bitWidth - 1UL);
+ }
+ else
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(0UL);
+ }
+ }
+
+ /* Set mono or stereo */
+ base->RMR = (uint32_t)format->stereo;
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (format->channelMask == 0U)
+ {
+ format->channelMask = 1U << format->channel;
+ }
+
+ /* if channel nums is not set, calculate it here according to channelMask*/
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ channelNums++;
+ format->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ format->channel = i;
+ break;
+ }
+ }
+
+ format->channelNums = channelNums;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (format->channelNums > 1U)
+ {
+ base->RCR4 &= ~I2S_RCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ /* enable all the channel */
+ base->RCR3 |= I2S_RCR3_RCE(format->channelMask);
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Set watermark */
+ base->RCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SAI_WriteBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ bytesPerWord = (((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - base->TCR1) * bytesPerWord);
+#endif
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_WriteNonBlocking(base, channel, 1UL << channel, channel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer = (uint8_t *)((uintptr_t)buffer + bytesPerWord);
+ i += bytesPerWord;
+ }
+
+ /* Wait until the last data is sent */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+}
+
+/*!
+ * brief Sends data to multi channel using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param channelMask channel mask.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SAI_WriteMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t i = 0, j = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+ uint32_t channelNums = 0U, endChannel = 0U;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ bytesPerWord = (((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - base->TCR1) * bytesPerWord);
+#endif
+
+ for (i = 0U; (i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base)); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), channelMask))
+ {
+ channelNums++;
+ endChannel = i;
+ }
+ }
+
+ bytesPerWord *= channelNums;
+
+ while (j < size)
+ {
+ /* Wait until it can write data */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_WriteNonBlocking(base, channel, channelMask, endChannel, (uint8_t)bitWidth, buffer,
+ bytesPerWord * channelNums);
+ buffer = (uint8_t *)((uintptr_t)buffer + bytesPerWord * channelNums);
+ j += bytesPerWord * channelNums;
+ }
+
+ /* Wait until the last data is sent */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+}
+
+/*!
+ * brief Receives multi channel data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param channelMask channel mask.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SAI_ReadMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t i = 0, j = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+ uint32_t channelNums = 0U, endChannel = 0U;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ bytesPerWord = base->RCR1 * bytesPerWord;
+#endif
+ for (i = 0U; (i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base)); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), channelMask))
+ {
+ channelNums++;
+ endChannel = i;
+ }
+ }
+
+ bytesPerWord *= channelNums;
+
+ while (j < size)
+ {
+ /* Wait until data is received */
+ while (!(IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_ReadNonBlocking(base, channel, channelMask, endChannel, (uint8_t)bitWidth, buffer,
+ bytesPerWord * channelNums);
+ buffer = (uint8_t *)((uintptr_t)buffer + bytesPerWord * channelNums);
+ j += bytesPerWord * channelNums;
+ }
+}
+
+/*!
+ * brief Receives data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SAI_ReadBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ bytesPerWord = base->RCR1 * bytesPerWord;
+#endif
+
+ while (i < size)
+ {
+ /* Wait until data is received */
+ while (!(IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_ReadNonBlocking(base, channel, 1UL << channel, channel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer = (uint8_t *)((uintptr_t)buffer + bytesPerWord);
+ i += bytesPerWord;
+ }
+}
+
+/*!
+ * brief Initializes the SAI Tx handle.
+ *
+ * This function initializes the Tx handle for the SAI Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SAI base pointer
+ * param handle SAI handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void SAI_TransferTxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_saiHandle[SAI_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->base = base;
+
+ /* Set the isr pointer */
+ s_saiTxIsr = SAI_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ (void)EnableIRQ(s_saiTxIRQ[SAI_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the SAI Rx handle.
+ *
+ * This function initializes the Rx handle for the SAI Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void SAI_TransferRxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_saiHandle[SAI_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->base = base;
+
+ /* Set the isr pointer */
+ s_saiRxIsr = SAI_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ (void)EnableIRQ(s_saiRxIRQ[SAI_GetInstance(base)]);
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TransferTxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * return Status of this function. Return value is the status_t.
+ */
+status_t SAI_TransferTxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle != NULL);
+
+ if ((bclkSourceClockHz < format->sampleRate_Hz)
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ || (mclkSourceClockHz < format->sampleRate_Hz)
+#endif
+ )
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = (uint8_t)format->bitWidth;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->watermark = format->watermark;
+#endif
+
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ handle->channel = format->channel;
+ /* used for multi channel */
+ handle->channelMask = format->channelMask;
+ handle->channelNums = format->channelNums;
+ handle->endChannel = format->endChannel;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TransferRxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * return Status of this function. Return value is one of status_t.
+ */
+status_t SAI_TransferRxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle != NULL);
+
+ if ((bclkSourceClockHz < format->sampleRate_Hz)
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ || (mclkSourceClockHz < format->sampleRate_Hz)
+#endif
+ )
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = (uint8_t)format->bitWidth;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->watermark = format->watermark;
+#endif
+
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ handle->channel = format->channel;
+ /* used for multi channel */
+ handle->channelMask = format->channelMask;
+ handle->channelNums = format->channelNums;
+ handle->endChannel = format->endChannel;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on SAI.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SAI_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the sai_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SAI_TxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferSendNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(handle->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_TxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_TxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ /* Enable Tx transfer */
+ SAI_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on SAI.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SAI_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * param base SAI base pointer
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the sai_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SAI_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferReceiveNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(handle->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = (uint32_t)kSAI_Busy;
+
+/* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_RxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_RxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ /* Enable Rx transfer */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetSendCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint32_t queueDriverIndex = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriverIndex] - handle->saiQueue[queueDriverIndex].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets a received byte count.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param count Bytes count received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetReceiveCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint32_t queueDriverIndex = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriverIndex] - handle->saiQueue[queueDriverIndex].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortSend(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_TxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_TxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_TxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ handle->state = (uint32_t)kSAI_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * (uint8_t)SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SAI base pointer
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortReceive(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_RxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_RxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_RxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ handle->state = (uint32_t)kSAI_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * (uint8_t)SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSend.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSend(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortSend(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceive.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceive(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortReceive(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferTxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint32_t dataSize = (handle->bitWidth / 8UL) * handle->channelNums;
+
+ /* Handle Error */
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FEF_MASK))
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_TxClearStatusFlags(base, I2S_TCSR_FEF_MASK);
+
+ /* Reset FIFO for safety */
+ SAI_TxSoftwareReset(base, kSAI_ResetTypeFIFO);
+
+ /* Call the callback */
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FRF_MASK))
+ {
+ /* Judge if the data need to transmit is less than space */
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize),
+ (size_t)(((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - handle->watermark) * dataSize));
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_WriteNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uintptr_t)buffer + size);
+ }
+#else
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK))
+ {
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_WriteNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uintptr_t)buffer + size);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ /* If finished a block, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortSend(base, handle);
+ }
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferRxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint32_t dataSize = (handle->bitWidth / 8UL) * handle->channelNums;
+
+ /* Handle Error */
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FEF_MASK))
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_RxClearStatusFlags(base, I2S_TCSR_FEF_MASK);
+
+ /* Reset FIFO for safety */
+ SAI_RxSoftwareReset(base, kSAI_ResetTypeFIFO);
+
+ /* Call the callback */
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FRF_MASK))
+ {
+ /* Judge if the data need to transmit is less than space */
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), handle->watermark * dataSize);
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_ReadNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uintptr_t)buffer + size);
+ }
+#else
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK))
+ {
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_ReadNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update internal state */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uintptr_t)buffer + size);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ /* If finished a block, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortReceive(base, handle);
+ }
+}
+
+#if defined(I2S0)
+void I2S0_DriverIRQHandler(void);
+void I2S0_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S0_Tx_DriverIRQHandler(void);
+void I2S0_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][0] != NULL);
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S0_Rx_DriverIRQHandler(void);
+void I2S0_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][1] != NULL);
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S0*/
+
+#if defined(I2S1)
+void I2S1_DriverIRQHandler(void);
+void I2S1_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S1, s_saiHandle[1][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S1_Tx_DriverIRQHandler(void);
+void I2S1_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][0] != NULL);
+ s_saiTxIsr(I2S1, s_saiHandle[1][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S1_Rx_DriverIRQHandler(void);
+void I2S1_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][1] != NULL);
+ s_saiRxIsr(I2S1, s_saiHandle[1][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S1*/
+
+#if defined(I2S2)
+void I2S2_DriverIRQHandler(void);
+void I2S2_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S2, s_saiHandle[2][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S2_Tx_DriverIRQHandler(void);
+void I2S2_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[2][0] != NULL);
+ s_saiTxIsr(I2S2, s_saiHandle[2][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S2_Rx_DriverIRQHandler(void);
+void I2S2_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[2][1] != NULL);
+ s_saiRxIsr(I2S2, s_saiHandle[2][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S2*/
+
+#if defined(I2S3)
+void I2S3_DriverIRQHandler(void);
+void I2S3_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S3_Tx_DriverIRQHandler(void);
+void I2S3_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][0] != NULL);
+ s_saiTxIsr(I2S3, s_saiHandle[3][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S3_Rx_DriverIRQHandler(void);
+void I2S3_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][1] != NULL);
+ s_saiRxIsr(I2S3, s_saiHandle[3][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S3*/
+
+#if defined(I2S4)
+void I2S4_DriverIRQHandler(void);
+void I2S4_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S4, s_saiHandle[4][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S4, s_saiHandle[4][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S4_Tx_DriverIRQHandler(void);
+void I2S4_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[4][0] != NULL);
+ s_saiTxIsr(I2S4, s_saiHandle[4][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S4_Rx_DriverIRQHandler(void);
+void I2S4_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[4][1] != NULL);
+ s_saiRxIsr(I2S4, s_saiHandle[4][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FSL_FEATURE_SAI_SAI5_SAI6_SHARE_IRQ) && (FSL_FEATURE_SAI_SAI5_SAI6_SHARE_IRQ) && defined(I2S5) && \
+ defined(I2S6)
+void I2S56_DriverIRQHandler(void);
+void I2S56_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ I2S_Type *base = s_saiHandle[5][1]->base;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(base, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(base, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(base, s_saiHandle[5][1]);
+ }
+
+ base = s_saiHandle[5][0]->base;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(base, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(base, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(base, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S56_Tx_DriverIRQHandler(void);
+void I2S56_Tx_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ assert(s_saiHandle[5][0] != NULL);
+ s_saiTxIsr(s_saiHandle[5][0]->base, s_saiHandle[5][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S56_Rx_DriverIRQHandler(void);
+void I2S56_Rx_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ assert(s_saiHandle[5][1] != NULL);
+ s_saiRxIsr(s_saiHandle[5][1]->base, s_saiHandle[5][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+
+#if defined(I2S5)
+void I2S5_DriverIRQHandler(void);
+void I2S5_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S5, s_saiHandle[5][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S5, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S5_Tx_DriverIRQHandler(void);
+void I2S5_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[5][0] != NULL);
+ s_saiTxIsr(I2S5, s_saiHandle[5][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S5_Rx_DriverIRQHandler(void);
+void I2S5_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[5][1] != NULL);
+ s_saiRxIsr(I2S5, s_saiHandle[5][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(I2S6)
+void I2S6_DriverIRQHandler(void);
+void I2S6_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S6_Tx_DriverIRQHandler(void);
+void I2S6_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[6][0] != NULL);
+ s_saiTxIsr(I2S6, s_saiHandle[6][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S6_Rx_DriverIRQHandler(void);
+void I2S6_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[6][1] != NULL);
+ s_saiRxIsr(I2S6, s_saiHandle[6][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(AUDIO__SAI0)
+void AUDIO_SAI0_INT_DriverIRQHandler(void);
+void AUDIO_SAI0_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI0, s_saiHandle[0][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI0 */
+
+#if defined(AUDIO__SAI1)
+void AUDIO_SAI1_INT_DriverIRQHandler(void);
+void AUDIO_SAI1_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI1 */
+
+#if defined(AUDIO__SAI2)
+void AUDIO_SAI2_INT_DriverIRQHandler(void);
+void AUDIO_SAI2_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI2, s_saiHandle[2][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI2 */
+
+#if defined(AUDIO__SAI3)
+void AUDIO_SAI3_INT_DriverIRQHandler(void);
+void AUDIO_SAI3_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(AUDIO__SAI6)
+void AUDIO_SAI6_INT_DriverIRQHandler(void);
+void AUDIO_SAI6_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI6 */
+
+#if defined(AUDIO__SAI7)
+void AUDIO_SAI7_INT_DriverIRQHandler(void);
+void AUDIO_SAI7_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[7][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[7][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI7, s_saiHandle[7][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[7][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[7][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI7, s_saiHandle[7][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI7 */
+
+#if defined(ADMA__SAI0)
+void ADMA_SAI0_INT_DriverIRQHandler(void);
+void ADMA_SAI0_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI0, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI0, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI0 */
+
+#if defined(ADMA__SAI1)
+void ADMA_SAI1_INT_DriverIRQHandler(void);
+void ADMA_SAI1_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI1 */
+
+#if defined(ADMA__SAI2)
+void ADMA_SAI2_INT_DriverIRQHandler(void);
+void ADMA_SAI2_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI2, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI2, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI2 */
+
+#if defined(ADMA__SAI3)
+void ADMA_SAI3_INT_DriverIRQHandler(void);
+void ADMA_SAI3_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI3, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI3, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI3 */
+
+#if defined(ADMA__SAI4)
+void ADMA_SAI4_INT_DriverIRQHandler(void);
+void ADMA_SAI4_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI4, s_saiHandle[1][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI4, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI4 */
+
+#if defined(ADMA__SAI5)
+void ADMA_SAI5_INT_DriverIRQHandler(void);
+void ADMA_SAI5_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI5, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI5, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI5 */
+
+#if defined(SAI0)
+void SAI0_DriverIRQHandler(void);
+void SAI0_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI0, s_saiHandle[0][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI0 */
+
+#if defined(SAI1)
+void SAI1_DriverIRQHandler(void);
+void SAI1_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI1 */
+
+#if defined(SAI2)
+void SAI2_DriverIRQHandler(void);
+void SAI2_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI2, s_saiHandle[2][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI2 */
+
+#if defined(SAI3)
+void SAI3_DriverIRQHandler(void);
+void SAI3_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void SAI3_TX_DriverIRQHandler(void);
+void SAI3_TX_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][0] != NULL);
+ s_saiTxIsr(SAI3, s_saiHandle[3][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void SAI3_RX_DriverIRQHandler(void);
+void SAI3_RX_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][1] != NULL);
+ s_saiRxIsr(SAI3, s_saiHandle[3][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI3 */
+
+#if defined(SAI4)
+void SAI4_DriverIRQHandler(void);
+void SAI4_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI4, s_saiHandle[4][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI4, s_saiHandle[4][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI4 */
+
+#if defined(SAI5)
+void SAI5_DriverIRQHandler(void);
+void SAI5_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI5, s_saiHandle[5][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI5, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI5 */
+
+#if defined(SAI6)
+void SAI6_DriverIRQHandler(void);
+void SAI6_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI6 */ \ No newline at end of file
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.h b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.h
new file mode 100644
index 0000000000..a080aa81b8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai.h
@@ -0,0 +1,1586 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SAI_H_
+#define _FSL_SAI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup sai_driver SAI Driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SAI_DRIVER_VERSION (MAKE_VERSION(2, 3, 8)) /*!< Version 2.3.8 */
+/*@}*/
+
+/*! @brief _sai_status_t, SAI return status.*/
+enum
+{
+ kStatus_SAI_TxBusy = MAKE_STATUS(kStatusGroup_SAI, 0), /*!< SAI Tx is busy. */
+ kStatus_SAI_RxBusy = MAKE_STATUS(kStatusGroup_SAI, 1), /*!< SAI Rx is busy. */
+ kStatus_SAI_TxError = MAKE_STATUS(kStatusGroup_SAI, 2), /*!< SAI Tx FIFO error. */
+ kStatus_SAI_RxError = MAKE_STATUS(kStatusGroup_SAI, 3), /*!< SAI Rx FIFO error. */
+ kStatus_SAI_QueueFull = MAKE_STATUS(kStatusGroup_SAI, 4), /*!< SAI transfer queue is full. */
+ kStatus_SAI_TxIdle = MAKE_STATUS(kStatusGroup_SAI, 5), /*!< SAI Tx is idle */
+ kStatus_SAI_RxIdle = MAKE_STATUS(kStatusGroup_SAI, 6) /*!< SAI Rx is idle */
+};
+
+/*! @brief _sai_channel_mask,.sai channel mask value, actual channel numbers is depend soc specific */
+enum
+{
+ kSAI_Channel0Mask = 1 << 0U, /*!< channel 0 mask value */
+ kSAI_Channel1Mask = 1 << 1U, /*!< channel 1 mask value */
+ kSAI_Channel2Mask = 1 << 2U, /*!< channel 2 mask value */
+ kSAI_Channel3Mask = 1 << 3U, /*!< channel 3 mask value */
+ kSAI_Channel4Mask = 1 << 4U, /*!< channel 4 mask value */
+ kSAI_Channel5Mask = 1 << 5U, /*!< channel 5 mask value */
+ kSAI_Channel6Mask = 1 << 6U, /*!< channel 6 mask value */
+ kSAI_Channel7Mask = 1 << 7U, /*!< channel 7 mask value */
+};
+
+/*! @brief Define the SAI bus type */
+typedef enum _sai_protocol
+{
+ kSAI_BusLeftJustified = 0x0U, /*!< Uses left justified format.*/
+ kSAI_BusRightJustified, /*!< Uses right justified format. */
+ kSAI_BusI2S, /*!< Uses I2S format. */
+ kSAI_BusPCMA, /*!< Uses I2S PCM A format.*/
+ kSAI_BusPCMB /*!< Uses I2S PCM B format. */
+} sai_protocol_t;
+
+/*! @brief Master or slave mode */
+typedef enum _sai_master_slave
+{
+ kSAI_Master = 0x0U, /*!< Master mode include bclk and frame sync */
+ kSAI_Slave = 0x1U, /*!< Slave mode include bclk and frame sync */
+ kSAI_Bclk_Master_FrameSync_Slave = 0x2U, /*!< bclk in master mode, frame sync in slave mode */
+ kSAI_Bclk_Slave_FrameSync_Master = 0x3U, /*!< bclk in slave mode, frame sync in master mode */
+} sai_master_slave_t;
+
+/*! @brief Mono or stereo audio format */
+typedef enum _sai_mono_stereo
+{
+ kSAI_Stereo = 0x0U, /*!< Stereo sound. */
+ kSAI_MonoRight, /*!< Only Right channel have sound. */
+ kSAI_MonoLeft /*!< Only left channel have sound. */
+} sai_mono_stereo_t;
+
+/*! @brief SAI data order, MSB or LSB */
+typedef enum _sai_data_order
+{
+ kSAI_DataLSB = 0x0U, /*!< LSB bit transferred first */
+ kSAI_DataMSB /*!< MSB bit transferred first */
+} sai_data_order_t;
+
+/*! @brief SAI clock polarity, active high or low */
+typedef enum _sai_clock_polarity
+{
+ kSAI_PolarityActiveHigh = 0x0U, /*!< Drive outputs on rising edge */
+ kSAI_PolarityActiveLow = 0x1U, /*!< Drive outputs on falling edge */
+ kSAI_SampleOnFallingEdge = 0x0U, /*!< Sample inputs on falling edge */
+ kSAI_SampleOnRisingEdge = 0x1U, /*!< Sample inputs on rising edge */
+} sai_clock_polarity_t;
+
+/*! @brief Synchronous or asynchronous mode */
+typedef enum _sai_sync_mode
+{
+ kSAI_ModeAsync = 0x0U, /*!< Asynchronous mode */
+ kSAI_ModeSync, /*!< Synchronous mode (with receiver or transmit) */
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ kSAI_ModeSyncWithOtherTx, /*!< Synchronous with another SAI transmit */
+ kSAI_ModeSyncWithOtherRx /*!< Synchronous with another SAI receiver */
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+} sai_sync_mode_t;
+
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+/*! @brief Mater clock source */
+typedef enum _sai_mclk_source
+{
+ kSAI_MclkSourceSysclk = 0x0U, /*!< Master clock from the system clock */
+ kSAI_MclkSourceSelect1, /*!< Master clock from source 1 */
+ kSAI_MclkSourceSelect2, /*!< Master clock from source 2 */
+ kSAI_MclkSourceSelect3 /*!< Master clock from source 3 */
+} sai_mclk_source_t;
+#endif
+
+/*! @brief Bit clock source */
+typedef enum _sai_bclk_source
+{
+ kSAI_BclkSourceBusclk = 0x0U, /*!< Bit clock using bus clock */
+ /* General device bit source definition */
+ kSAI_BclkSourceMclkOption1 = 0x1U, /*!< Bit clock MCLK option 1 */
+ kSAI_BclkSourceMclkOption2 = 0x2U, /*!< Bit clock MCLK option2 */
+ kSAI_BclkSourceMclkOption3 = 0x3U, /*!< Bit clock MCLK option3 */
+ /* Kinetis device bit clock source definition */
+ kSAI_BclkSourceMclkDiv = 0x1U, /*!< Bit clock using master clock divider */
+ kSAI_BclkSourceOtherSai0 = 0x2U, /*!< Bit clock from other SAI device */
+ kSAI_BclkSourceOtherSai1 = 0x3U /*!< Bit clock from other SAI device */
+} sai_bclk_source_t;
+
+/*! @brief _sai_interrupt_enable_t, The SAI interrupt enable flag */
+enum
+{
+ kSAI_WordStartInterruptEnable =
+ I2S_TCSR_WSIE_MASK, /*!< Word start flag, means the first word in a frame detected */
+ kSAI_SyncErrorInterruptEnable = I2S_TCSR_SEIE_MASK, /*!< Sync error flag, means the sync error is detected */
+ kSAI_FIFOWarningInterruptEnable = I2S_TCSR_FWIE_MASK, /*!< FIFO warning flag, means the FIFO is empty */
+ kSAI_FIFOErrorInterruptEnable = I2S_TCSR_FEIE_MASK, /*!< FIFO error flag */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ kSAI_FIFORequestInterruptEnable = I2S_TCSR_FRIE_MASK, /*!< FIFO request, means reached watermark */
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+};
+
+/*! @brief _sai_dma_enable_t, The DMA request sources */
+enum
+{
+ kSAI_FIFOWarningDMAEnable = I2S_TCSR_FWDE_MASK, /*!< FIFO warning caused by the DMA request */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ kSAI_FIFORequestDMAEnable = I2S_TCSR_FRDE_MASK, /*!< FIFO request caused by the DMA request */
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+};
+
+/*! @brief _sai_flags, The SAI status flag */
+enum
+{
+ kSAI_WordStartFlag = I2S_TCSR_WSF_MASK, /*!< Word start flag, means the first word in a frame detected */
+ kSAI_SyncErrorFlag = I2S_TCSR_SEF_MASK, /*!< Sync error flag, means the sync error is detected */
+ kSAI_FIFOErrorFlag = I2S_TCSR_FEF_MASK, /*!< FIFO error flag */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ kSAI_FIFORequestFlag = I2S_TCSR_FRF_MASK, /*!< FIFO request flag. */
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+ kSAI_FIFOWarningFlag = I2S_TCSR_FWF_MASK, /*!< FIFO warning flag */
+};
+
+/*! @brief The reset type */
+typedef enum _sai_reset_type
+{
+ kSAI_ResetTypeSoftware = I2S_TCSR_SR_MASK, /*!< Software reset, reset the logic state */
+ kSAI_ResetTypeFIFO = I2S_TCSR_FR_MASK, /*!< FIFO reset, reset the FIFO read and write pointer */
+ kSAI_ResetAll = I2S_TCSR_SR_MASK | I2S_TCSR_FR_MASK /*!< All reset. */
+} sai_reset_type_t;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+/*!
+ * @brief The SAI packing mode
+ * The mode includes 8 bit and 16 bit packing.
+ */
+typedef enum _sai_fifo_packing
+{
+ kSAI_FifoPackingDisabled = 0x0U, /*!< Packing disabled */
+ kSAI_FifoPacking8bit = 0x2U, /*!< 8 bit packing enabled */
+ kSAI_FifoPacking16bit = 0x3U /*!< 16bit packing enabled */
+} sai_fifo_packing_t;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_PACKING */
+
+/*! @brief SAI user configuration structure */
+typedef struct _sai_config
+{
+ sai_protocol_t protocol; /*!< Audio bus protocol in SAI */
+ sai_sync_mode_t syncMode; /*!< SAI sync mode, control Tx/Rx clock sync */
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ bool mclkOutputEnable; /*!< Master clock output enable, true means master clock divider enabled */
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ sai_mclk_source_t mclkSource; /*!< Master Clock source */
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+#endif
+ sai_bclk_source_t bclkSource; /*!< Bit Clock source */
+ sai_master_slave_t masterSlave; /*!< Master or slave */
+} sai_config_t;
+
+#ifndef SAI_XFER_QUEUE_SIZE
+/*!@brief SAI transfer queue size, user can refine it according to use case. */
+#define SAI_XFER_QUEUE_SIZE (4U)
+#endif
+
+/*! @brief Audio sample rate */
+typedef enum _sai_sample_rate
+{
+ kSAI_SampleRate8KHz = 8000U, /*!< Sample rate 8000 Hz */
+ kSAI_SampleRate11025Hz = 11025U, /*!< Sample rate 11025 Hz */
+ kSAI_SampleRate12KHz = 12000U, /*!< Sample rate 12000 Hz */
+ kSAI_SampleRate16KHz = 16000U, /*!< Sample rate 16000 Hz */
+ kSAI_SampleRate22050Hz = 22050U, /*!< Sample rate 22050 Hz */
+ kSAI_SampleRate24KHz = 24000U, /*!< Sample rate 24000 Hz */
+ kSAI_SampleRate32KHz = 32000U, /*!< Sample rate 32000 Hz */
+ kSAI_SampleRate44100Hz = 44100U, /*!< Sample rate 44100 Hz */
+ kSAI_SampleRate48KHz = 48000U, /*!< Sample rate 48000 Hz */
+ kSAI_SampleRate96KHz = 96000U, /*!< Sample rate 96000 Hz */
+ kSAI_SampleRate192KHz = 192000U, /*!< Sample rate 192000 Hz */
+ kSAI_SampleRate384KHz = 384000U, /*!< Sample rate 384000 Hz */
+} sai_sample_rate_t;
+
+/*! @brief Audio word width */
+typedef enum _sai_word_width
+{
+ kSAI_WordWidth8bits = 8U, /*!< Audio data width 8 bits */
+ kSAI_WordWidth16bits = 16U, /*!< Audio data width 16 bits */
+ kSAI_WordWidth24bits = 24U, /*!< Audio data width 24 bits */
+ kSAI_WordWidth32bits = 32U /*!< Audio data width 32 bits */
+} sai_word_width_t;
+
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+/*! @brief sai data pin state definition */
+typedef enum _sai_data_pin_state
+{
+ kSAI_DataPinStateTriState =
+ 0U, /*!< transmit data pins are tri-stated when slots are masked or channels are disabled */
+ kSAI_DataPinStateOutputZero = 1U, /*!< transmit data pins are never tri-stated and will output zero when slots
+ are masked or channel disabled */
+} sai_data_pin_state_t;
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+/*! @brief sai fifo combine mode definition */
+typedef enum _sai_fifo_combine
+{
+ kSAI_FifoCombineDisabled = 0U, /*!< sai fifo combine mode disabled */
+ kSAI_FifoCombineModeEnabledOnRead, /*!< sai fifo combine mode enabled on FIFO reads */
+ kSAI_FifoCombineModeEnabledOnWrite, /*!< sai fifo combine mode enabled on FIFO write */
+ kSAI_FifoCombineModeEnabledOnReadWrite, /*!< sai fifo combined mode enabled on FIFO read/writes */
+} sai_fifo_combine_t;
+#endif
+
+/*! @brief sai transceiver type */
+typedef enum _sai_transceiver_type
+{
+ kSAI_Transmitter = 0U, /*!< sai transmitter */
+ kSAI_Receiver = 1U, /*!< sai receiver */
+} sai_transceiver_type_t;
+
+/*! @brief sai frame sync len */
+typedef enum _sai_frame_sync_len
+{
+ kSAI_FrameSyncLenOneBitClk = 0U, /*!< 1 bit clock frame sync len for DSP mode */
+ kSAI_FrameSyncLenPerWordWidth = 1U, /*!< Frame sync length decided by word width */
+} sai_frame_sync_len_t;
+
+/*! @brief sai transfer format */
+typedef struct _sai_transfer_format
+{
+ uint32_t sampleRate_Hz; /*!< Sample rate of audio data */
+ uint32_t bitWidth; /*!< Data length of audio data, usually 8/16/24/32 bits */
+ sai_mono_stereo_t stereo; /*!< Mono or stereo */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ uint32_t masterClockHz; /*!< Master clock frequency in Hz */
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ uint8_t watermark; /*!< Watermark value */
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+
+ /* for the multi channel usage, user can provide channelMask Oonly, then sai driver will handle
+ * other parameter carefully, such as
+ * channelMask = kSAI_Channel0Mask | kSAI_Channel1Mask | kSAI_Channel4Mask
+ * then in SAI_RxSetFormat/SAI_TxSetFormat function, channel/endChannel/channelNums will be calculated.
+ * for the single channel usage, user can provide channel or channel mask only, such as,
+ * channel = 0 or channelMask = kSAI_Channel0Mask.
+ */
+ uint8_t channel; /*!< Transfer start channel */
+ uint8_t channelMask; /*!< enabled channel mask value, reference _sai_channel_mask */
+ uint8_t endChannel; /*!< end channel number */
+ uint8_t channelNums; /*!< Total enabled channel numbers */
+
+ sai_protocol_t protocol; /*!< Which audio protocol used */
+ bool isFrameSyncCompact; /*!< True means Frame sync length is configurable according to bitWidth, false means frame
+ sync length is 64 times of bit clock. */
+} sai_transfer_format_t;
+
+#if (defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER))
+/*! @brief master clock configurations */
+typedef struct _sai_master_clock
+{
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ bool mclkOutputEnable; /*!< master clock output enable */
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ sai_mclk_source_t mclkSource; /*!< Master Clock source */
+#endif
+#endif
+
+#if (defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER))
+ uint32_t mclkHz; /*!< target mclk frequency */
+ uint32_t mclkSourceClkHz; /*!< mclk source frequency*/
+#endif
+} sai_master_clock_t;
+#endif
+
+/*! @brief sai fifo feature*/
+#if (defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) || \
+ (defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) || \
+ (defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING) || \
+ (defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO))
+#define FSL_SAI_HAS_FIFO_EXTEND_FEATURE 1
+#else
+#define FSL_SAI_HAS_FIFO_EXTEND_FEATURE 0
+#endif
+
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+/*! @brief sai fifo configurations */
+typedef struct _sai_fifo
+{
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ bool fifoContinueOneError; /*!< fifo continues when error occur */
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+ sai_fifo_combine_t fifoCombine; /*!< fifo combine mode */
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+ sai_fifo_packing_t fifoPacking; /*!< fifo packing mode */
+#endif
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ uint8_t fifoWatermark; /*!< fifo watermark */
+#endif
+} sai_fifo_t;
+#endif
+
+/*! @brief sai bit clock configurations */
+typedef struct _sai_bit_clock
+{
+ bool bclkSrcSwap; /*!< bit clock source swap */
+ bool bclkInputDelay; /*!< bit clock actually used by the transmitter is delayed by the pad output delay,
+ this has effect of decreasing the data input setup time, but increasing the data output valid
+ time .*/
+ sai_clock_polarity_t bclkPolarity; /*!< bit clock polarity */
+ sai_bclk_source_t bclkSource; /*!< bit Clock source */
+} sai_bit_clock_t;
+
+/*! @brief sai frame sync configurations */
+typedef struct _sai_frame_sync
+{
+ uint8_t frameSyncWidth; /*!< frame sync width in number of bit clocks */
+ bool frameSyncEarly; /*!< TRUE is frame sync assert one bit before the first bit of frame
+ FALSE is frame sync assert with the first bit of the frame */
+
+#if defined(FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE) && FSL_FEATURE_SAI_HAS_ON_DEMAND_MODE
+ bool frameSyncGenerateOnDemand; /*!< internal frame sync is generated when FIFO waring flag is clear */
+#endif
+
+ sai_clock_polarity_t frameSyncPolarity; /*!< frame sync polarity */
+
+} sai_frame_sync_t;
+
+/*! @brief sai serial data configurations */
+typedef struct _sai_serial_data
+{
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+ sai_data_pin_state_t dataMode; /*!< sai data pin state when slots masked or channel disabled */
+#endif
+
+ sai_data_order_t dataOrder; /*!< configure whether the LSB or MSB is transmitted first */
+ uint8_t dataWord0Length; /*!< configure the number of bits in the first word in each frame */
+ uint8_t dataWordNLength; /*!< configure the number of bits in the each word in each frame, except the first word */
+ uint8_t dataWordLength; /*!< used to record the data length for dma transfer */
+ uint8_t
+ dataFirstBitShifted; /*!< Configure the bit index for the first bit transmitted for each word in the frame */
+ uint8_t dataWordNum; /*!< configure the number of words in each frame */
+ uint32_t dataMaskedWord; /*!< configure whether the transmit word is masked */
+} sai_serial_data_t;
+
+/*! @brief sai transceiver configurations */
+typedef struct _sai_transceiver
+{
+ sai_serial_data_t serialData; /*!< serial data configurations */
+ sai_frame_sync_t frameSync; /*!< ws configurations */
+ sai_bit_clock_t bitClock; /*!< bit clock configurations */
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+ sai_fifo_t fifo; /*!< fifo configurations */
+#endif
+ sai_master_slave_t masterSlave; /*!< transceiver is master or slave */
+
+ sai_sync_mode_t syncMode; /*!< transceiver sync mode */
+
+ uint8_t startChannel; /*!< Transfer start channel */
+ uint8_t channelMask; /*!< enabled channel mask value, reference _sai_channel_mask */
+ uint8_t endChannel; /*!< end channel number */
+ uint8_t channelNums; /*!< Total enabled channel numbers */
+
+} sai_transceiver_t;
+
+/*! @brief SAI transfer structure */
+typedef struct _sai_transfer
+{
+ uint8_t *data; /*!< Data start address to transfer. */
+ size_t dataSize; /*!< Transfer size. */
+} sai_transfer_t;
+
+typedef struct _sai_handle sai_handle_t;
+
+/*! @brief SAI transfer callback prototype */
+typedef void (*sai_transfer_callback_t)(I2S_Type *base, sai_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SAI handle structure */
+struct _sai_handle
+{
+ I2S_Type *base; /*!< base address */
+
+ uint32_t state; /*!< Transfer status */
+ sai_transfer_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+ uint8_t bitWidth; /*!< Bit width for transfer, 8/16/24/32 bits */
+
+ /* for the multi channel usage, user can provide channelMask Oonly, then sai driver will handle
+ * other parameter carefully, such as
+ * channelMask = kSAI_Channel0Mask | kSAI_Channel1Mask | kSAI_Channel4Mask
+ * then in SAI_RxSetFormat/SAI_TxSetFormat function, channel/endChannel/channelNums will be calculated.
+ * for the single channel usage, user can provide channel or channel mask only, such as,
+ * channel = 0 or channelMask = kSAI_Channel0Mask.
+ */
+ uint8_t channel; /*!< Transfer start channel */
+ uint8_t channelMask; /*!< enabled channel mask value, refernece _sai_channel_mask */
+ uint8_t endChannel; /*!< end channel number */
+ uint8_t channelNums; /*!< Total enabled channel numbers */
+
+ sai_transfer_t saiQueue[SAI_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[SAI_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ uint8_t watermark; /*!< Watermark value */
+#endif
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SAI Tx peripheral.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures SAI Tx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_TxGetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAIM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base SAI base pointer
+ * @param config SAI configuration structure.
+ */
+void SAI_TxInit(I2S_Type *base, const sai_config_t *config);
+
+/*!
+ * @brief Initializes the SAI Rx peripheral.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures the SAI Rx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_RxGetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAI module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base SAI base pointer
+ * @param config SAI configuration structure.
+ */
+void SAI_RxInit(I2S_Type *base, const sai_config_t *config);
+
+/*!
+ * @brief Sets the SAI Tx configuration structure to default values.
+ * @deprecated Do not use this function. It has been superceded by
+ * @ref SAI_GetClassicI2SConfig, @ref SAI_GetLeftJustifiedConfig , @ref SAI_GetRightJustifiedConfig, @ref
+ SAI_GetDSPConfig, @ref SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_TxConfig().
+ * The initialized structure can remain unchanged in SAI_TxConfig(), or it can be modified
+ * before calling SAI_TxConfig().
+ * This is an example.
+ @code
+ sai_config_t config;
+ SAI_TxGetDefaultConfig(&config);
+ @endcode
+ *
+ * @param config pointer to master configuration structure
+ */
+void SAI_TxGetDefaultConfig(sai_config_t *config);
+
+/*!
+ * @brief Sets the SAI Rx configuration structure to default values.
+ * @deprecated Do not use this function. It has been superceded by
+ * @ref SAI_GetClassicI2SConfig, @ref SAI_GetLeftJustifiedConfig , @ref SAI_GetRightJustifiedConfig, @ref
+ SAI_GetDSPConfig, @ref SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_RxConfig().
+ * The initialized structure can remain unchanged in SAI_RxConfig() or it can be modified
+ * before calling SAI_RxConfig().
+ * This is an example.
+ @code
+ sai_config_t config;
+ SAI_RxGetDefaultConfig(&config);
+ @endcode
+ *
+ * @param config pointer to master configuration structure
+ */
+void SAI_RxGetDefaultConfig(sai_config_t *config);
+
+/*!
+ * @brief Initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_Init is called to enable the clock.
+ *
+ * @param base SAI base pointer.
+ */
+void SAI_Init(I2S_Type *base);
+
+/*!
+ * @brief De-initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_TxInit
+ * or SAI_RxInit is called to enable the clock.
+ *
+ * @param base SAI base pointer.
+ */
+void SAI_Deinit(I2S_Type *base);
+
+/*!
+ * @brief Resets the SAI Tx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Tx. After reset, clear the reset bit.
+ *
+ * @param base SAI base pointer
+ */
+void SAI_TxReset(I2S_Type *base);
+
+/*!
+ * @brief Resets the SAI Rx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Rx. After reset, clear the reset bit.
+ *
+ * @param base SAI base pointer
+ */
+void SAI_RxReset(I2S_Type *base);
+
+/*!
+ * @brief Enables/disables the SAI Tx.
+ *
+ * @param base SAI base pointer.
+ * @param enable True means enable SAI Tx, false means disable.
+ */
+void SAI_TxEnable(I2S_Type *base, bool enable);
+
+/*!
+ * @brief Enables/disables the SAI Rx.
+ *
+ * @param base SAI base pointer.
+ * @param enable True means enable SAI Rx, false means disable.
+ */
+void SAI_RxEnable(I2S_Type *base, bool enable);
+
+/*!
+ * @brief Set Rx bit clock direction.
+ *
+ * Select bit clock direction, master or slave.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave reference sai_master_slave_t.
+ */
+static inline void SAI_TxSetBitClockDirection(I2S_Type *base, sai_master_slave_t masterSlave)
+{
+ if (masterSlave == kSAI_Master)
+ {
+ base->TCR2 |= I2S_TCR2_BCD_MASK;
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCD_MASK;
+ }
+}
+
+/*!
+ * @brief Set Rx bit clock direction.
+ *
+ * Select bit clock direction, master or slave.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave reference sai_master_slave_t.
+ */
+static inline void SAI_RxSetBitClockDirection(I2S_Type *base, sai_master_slave_t masterSlave)
+{
+ if (masterSlave == kSAI_Master)
+ {
+ base->RCR2 |= I2S_RCR2_BCD_MASK;
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCD_MASK;
+ }
+}
+
+/*!
+ * @brief Set Rx frame sync direction.
+ *
+ * Select frame sync direction, master or slave.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave reference sai_master_slave_t.
+ */
+static inline void SAI_RxSetFrameSyncDirection(I2S_Type *base, sai_master_slave_t masterSlave)
+{
+ if (masterSlave == kSAI_Master)
+ {
+ base->RCR4 |= I2S_RCR4_FSD_MASK;
+ }
+ else
+ {
+ base->RCR4 &= ~I2S_RCR4_FSD_MASK;
+ }
+}
+
+/*!
+ * @brief Set Tx frame sync direction.
+ *
+ * Select frame sync direction, master or slave.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave reference sai_master_slave_t.
+ */
+static inline void SAI_TxSetFrameSyncDirection(I2S_Type *base, sai_master_slave_t masterSlave)
+{
+ if (masterSlave == kSAI_Master)
+ {
+ base->TCR4 |= I2S_TCR4_FSD_MASK;
+ }
+ else
+ {
+ base->TCR4 &= ~I2S_TCR4_FSD_MASK;
+ }
+}
+
+/*!
+ * @brief Transmitter bit clock rate configurations.
+ *
+ * @param base SAI base pointer.
+ * @param sourceClockHz Bit clock source frequency.
+ * @param sampleRate Audio data sample rate.
+ * @param bitWidth Audio data bitWidth.
+ * @param channelNumbers Audio channel numbers.
+ */
+void SAI_TxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers);
+
+/*!
+ * @brief Receiver bit clock rate configurations.
+ *
+ * @param base SAI base pointer.
+ * @param sourceClockHz Bit clock source frequency.
+ * @param sampleRate Audio data sample rate.
+ * @param bitWidth Audio data bitWidth.
+ * @param channelNumbers Audio channel numbers.
+ */
+void SAI_RxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers);
+
+/*!
+ * @brief Transmitter Bit clock configurations.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave master or slave.
+ * @param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config);
+
+/*!
+ * @brief Receiver Bit clock configurations.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave master or slave.
+ * @param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config);
+
+#if (defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER))
+/*!
+ * @brief Master clock configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config master clock configurations.
+ */
+void SAI_SetMasterClockConfig(I2S_Type *base, sai_master_clock_t *config);
+#endif
+
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+/*!
+ * @brief SAI transmitter fifo configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config fifo configurations.
+ */
+void SAI_TxSetFifoConfig(I2S_Type *base, sai_fifo_t *config);
+
+/*!
+ * @brief SAI receiver fifo configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config fifo configurations.
+ */
+void SAI_RxSetFifoConfig(I2S_Type *base, sai_fifo_t *config);
+#endif
+
+/*!
+ * @brief SAI transmitter Frame sync configurations.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave master or slave.
+ * @param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config);
+
+/*!
+ * @brief SAI receiver Frame sync configurations.
+ *
+ * @param base SAI base pointer.
+ * @param masterSlave master or slave.
+ * @param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config);
+
+/*!
+ * @brief SAI transmitter Serial data configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config serial data configurations.
+ */
+void SAI_TxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config);
+
+/*!
+ * @brief SAI receiver Serial data configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config serial data configurations.
+ */
+void SAI_RxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config);
+
+/*!
+ * @brief SAI transmitter configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config transmitter configurations.
+ */
+void SAI_TxSetConfig(I2S_Type *base, sai_transceiver_t *config);
+
+/*!
+ * @brief SAI receiver configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config receiver configurations.
+ */
+void SAI_RxSetConfig(I2S_Type *base, sai_transceiver_t *config);
+
+/*!
+ * @brief Get classic I2S mode configurations.
+ *
+ * @param config transceiver configurations.
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel.
+ * @param saiChannelMask mask value of the channel to be enable.
+ */
+void SAI_GetClassicI2SConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+
+/*!
+ * @brief Get left justified mode configurations.
+ *
+ * @param config transceiver configurations.
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel.
+ * @param saiChannelMask mask value of the channel to be enable.
+ */
+void SAI_GetLeftJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+
+/*!
+ * @brief Get right justified mode configurations.
+ *
+ * @param config transceiver configurations.
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel.
+ * @param saiChannelMask mask value of the channel to be enable.
+ */
+void SAI_GetRightJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+
+/*!
+ * @brief Get TDM mode configurations.
+ *
+ * @param config transceiver configurations.
+ * @param frameSyncWidth length of frame sync.
+ * @param bitWidth audio data word width.
+ * @param dataWordNum word number in one frame.
+ * @param saiChannelMask mask value of the channel to be enable.
+ */
+void SAI_GetTDMConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ uint32_t dataWordNum,
+ uint32_t saiChannelMask);
+
+/*!
+ * @brief Get DSP mode configurations.
+ *
+ * @note DSP mode is also called PCM mode which support MODE A and MODE B,
+ * DSP/PCM MODE A configuration flow. RX is similiar but uses SAI_RxSetConfig instead of SAI_TxSetConfig:
+ * @code
+ * SAI_GetDSPConfig(config, kSAI_FrameSyncLenOneBitClk, bitWidth, kSAI_Stereo, channelMask)
+ * config->frameSync.frameSyncEarly = true;
+ * SAI_TxSetConfig(base, config)
+ * @endcode
+ *
+ * DSP/PCM MODE B configuration flow for TX. RX is similiar but uses SAI_RxSetConfig instead of SAI_TxSetConfig:
+ * @code
+ * SAI_GetDSPConfig(config, kSAI_FrameSyncLenOneBitClk, bitWidth, kSAI_Stereo, channelMask)
+ * SAI_TxSetConfig(base, config)
+ * @endcode
+ *
+ * @param config transceiver configurations.
+ * @param frameSyncWidth length of frame sync.
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel.
+ * @param saiChannelMask mask value of the channel to enable.
+ */
+void SAI_GetDSPConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the SAI Tx status flag state.
+ *
+ * @param base SAI base pointer
+ * @return SAI Tx status flag value. Use the Status Mask to get the status value needed.
+ */
+static inline uint32_t SAI_TxGetStatusFlag(I2S_Type *base)
+{
+ return base->TCSR;
+}
+
+/*!
+ * @brief Clears the SAI Tx status flag state.
+ *
+ * @param base SAI base pointer
+ * @param mask State mask. It can be a combination of the following source if defined:
+ * @arg kSAI_WordStartFlag
+ * @arg kSAI_SyncErrorFlag
+ * @arg kSAI_FIFOErrorFlag
+ */
+static inline void SAI_TxClearStatusFlags(I2S_Type *base, uint32_t mask)
+{
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | mask);
+}
+
+/*!
+ * @brief Gets the SAI Tx status flag state.
+ *
+ * @param base SAI base pointer
+ * @return SAI Rx status flag value. Use the Status Mask to get the status value needed.
+ */
+static inline uint32_t SAI_RxGetStatusFlag(I2S_Type *base)
+{
+ return base->RCSR;
+}
+
+/*!
+ * @brief Clears the SAI Rx status flag state.
+ *
+ * @param base SAI base pointer
+ * @param mask State mask. It can be a combination of the following sources if defined.
+ * @arg kSAI_WordStartFlag
+ * @arg kSAI_SyncErrorFlag
+ * @arg kSAI_FIFOErrorFlag
+ */
+static inline void SAI_RxClearStatusFlags(I2S_Type *base, uint32_t mask)
+{
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | mask);
+}
+
+/*!
+ * @brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Tx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like TCR1~TCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * @param base SAI base pointer
+ * @param tresetType Reset type, FIFO reset or software reset
+ */
+void SAI_TxSoftwareReset(I2S_Type *base, sai_reset_type_t resetType);
+
+/*!
+ * @brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Rx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like RCR1~RCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * @param base SAI base pointer
+ * @param resetType Reset type, FIFO reset or software reset
+ */
+void SAI_RxSoftwareReset(I2S_Type *base, sai_reset_type_t resetType);
+
+/*!
+ * @brief Set the Tx channel FIFO enable mask.
+ *
+ * @param base SAI base pointer
+ * @param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_TxSetChannelFIFOMask(I2S_Type *base, uint8_t mask);
+
+/*!
+ * @brief Set the Rx channel FIFO enable mask.
+ *
+ * @param base SAI base pointer
+ * @param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_RxSetChannelFIFOMask(I2S_Type *base, uint8_t mask);
+
+/*!
+ * @brief Set the Tx data order.
+ *
+ * @param base SAI base pointer
+ * @param order Data order MSB or LSB
+ */
+void SAI_TxSetDataOrder(I2S_Type *base, sai_data_order_t order);
+
+/*!
+ * @brief Set the Rx data order.
+ *
+ * @param base SAI base pointer
+ * @param order Data order MSB or LSB
+ */
+void SAI_RxSetDataOrder(I2S_Type *base, sai_data_order_t order);
+
+/*!
+ * @brief Set the Tx data order.
+ *
+ * @param base SAI base pointer
+ * @param polarity
+ */
+void SAI_TxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity);
+
+/*!
+ * @brief Set the Rx data order.
+ *
+ * @param base SAI base pointer
+ * @param polarity
+ */
+void SAI_RxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity);
+
+/*!
+ * @brief Set the Tx data order.
+ *
+ * @param base SAI base pointer
+ * @param polarity
+ */
+void SAI_TxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity);
+
+/*!
+ * @brief Set the Rx data order.
+ *
+ * @param base SAI base pointer
+ * @param polarity
+ */
+void SAI_RxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity);
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+/*!
+ * @brief Set Tx FIFO packing feature.
+ *
+ * @param base SAI base pointer.
+ * @param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_TxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack);
+
+/*!
+ * @brief Set Rx FIFO packing feature.
+ *
+ * @param base SAI base pointer.
+ * @param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_RxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_PACKING */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+/*!
+ * @brief Set Tx FIFO error continue.
+ *
+ * FIFO error continue mode means SAI will keep running while FIFO error occurred. If this feature
+ * not enabled, SAI will hang and users need to clear FEF flag in TCSR register.
+ *
+ * @param base SAI base pointer.
+ * @param isEnabled Is FIFO error continue enabled, true means enable, false means disable.
+ */
+static inline void SAI_TxSetFIFOErrorContinue(I2S_Type *base, bool isEnabled)
+{
+ if (isEnabled)
+ {
+ base->TCR4 |= I2S_TCR4_FCONT_MASK;
+ }
+ else
+ {
+ base->TCR4 &= ~I2S_TCR4_FCONT_MASK;
+ }
+}
+
+/*!
+ * @brief Set Rx FIFO error continue.
+ *
+ * FIFO error continue mode means SAI will keep running while FIFO error occurred. If this feature
+ * not enabled, SAI will hang and users need to clear FEF flag in RCSR register.
+ *
+ * @param base SAI base pointer.
+ * @param isEnabled Is FIFO error continue enabled, true means enable, false means disable.
+ */
+static inline void SAI_RxSetFIFOErrorContinue(I2S_Type *base, bool isEnabled)
+{
+ if (isEnabled)
+ {
+ base->RCR4 |= I2S_RCR4_FCONT_MASK;
+ }
+ else
+ {
+ base->RCR4 &= ~I2S_RCR4_FCONT_MASK;
+ }
+}
+#endif
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the SAI Tx interrupt requests.
+ *
+ * @param base SAI base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSAI_WordStartInterruptEnable
+ * @arg kSAI_SyncErrorInterruptEnable
+ * @arg kSAI_FIFOWarningInterruptEnable
+ * @arg kSAI_FIFORequestInterruptEnable
+ * @arg kSAI_FIFOErrorInterruptEnable
+ */
+static inline void SAI_TxEnableInterrupts(I2S_Type *base, uint32_t mask)
+{
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | mask);
+}
+
+/*!
+ * @brief Enables the SAI Rx interrupt requests.
+ *
+ * @param base SAI base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSAI_WordStartInterruptEnable
+ * @arg kSAI_SyncErrorInterruptEnable
+ * @arg kSAI_FIFOWarningInterruptEnable
+ * @arg kSAI_FIFORequestInterruptEnable
+ * @arg kSAI_FIFOErrorInterruptEnable
+ */
+static inline void SAI_RxEnableInterrupts(I2S_Type *base, uint32_t mask)
+{
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | mask);
+}
+
+/*!
+ * @brief Disables the SAI Tx interrupt requests.
+ *
+ * @param base SAI base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSAI_WordStartInterruptEnable
+ * @arg kSAI_SyncErrorInterruptEnable
+ * @arg kSAI_FIFOWarningInterruptEnable
+ * @arg kSAI_FIFORequestInterruptEnable
+ * @arg kSAI_FIFOErrorInterruptEnable
+ */
+static inline void SAI_TxDisableInterrupts(I2S_Type *base, uint32_t mask)
+{
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~mask));
+}
+
+/*!
+ * @brief Disables the SAI Rx interrupt requests.
+ *
+ * @param base SAI base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSAI_WordStartInterruptEnable
+ * @arg kSAI_SyncErrorInterruptEnable
+ * @arg kSAI_FIFOWarningInterruptEnable
+ * @arg kSAI_FIFORequestInterruptEnable
+ * @arg kSAI_FIFOErrorInterruptEnable
+ */
+static inline void SAI_RxDisableInterrupts(I2S_Type *base, uint32_t mask)
+{
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~mask));
+}
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the SAI Tx DMA requests.
+ * @param base SAI base pointer
+ * @param mask DMA source
+ * The parameter can be combination of the following sources if defined.
+ * @arg kSAI_FIFOWarningDMAEnable
+ * @arg kSAI_FIFORequestDMAEnable
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void SAI_TxEnableDMA(I2S_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | mask);
+ }
+ else
+ {
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~mask));
+ }
+}
+
+/*!
+ * @brief Enables/disables the SAI Rx DMA requests.
+ * @param base SAI base pointer
+ * @param mask DMA source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSAI_FIFOWarningDMAEnable
+ * @arg kSAI_FIFORequestDMAEnable
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void SAI_RxEnableDMA(I2S_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | mask);
+ }
+ else
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~mask));
+ }
+}
+
+/*!
+ * @brief Gets the SAI Tx data register address.
+ *
+ * This API is used to provide a transfer address for the SAI DMA transfer configuration.
+ *
+ * @param base SAI base pointer.
+ * @param channel Which data channel used.
+ * @return data register address.
+ */
+static inline uintptr_t SAI_TxGetDataRegisterAddress(I2S_Type *base, uint32_t channel)
+{
+ return (uintptr_t)(&(base->TDR)[channel]);
+}
+
+/*!
+ * @brief Gets the SAI Rx data register address.
+ *
+ * This API is used to provide a transfer address for the SAI DMA transfer configuration.
+ *
+ * @param base SAI base pointer.
+ * @param channel Which data channel used.
+ * @return data register address.
+ */
+static inline uintptr_t SAI_RxGetDataRegisterAddress(I2S_Type *base, uint32_t channel)
+{
+ return (uintptr_t)(&(base->RDR)[channel]);
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Configures the SAI Tx audio format.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_TxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SAI base pointer.
+ * @param format Pointer to the SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_TxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Rx audio format.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_RxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SAI base pointer.
+ * @param format Pointer to the SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_RxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Sends data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+void SAI_WriteBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Sends data to multi channel using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @param channelMask channel mask.
+ * @param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+void SAI_WriteMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Writes data into SAI FIFO.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @param data Data needs to be written.
+ */
+static inline void SAI_WriteData(I2S_Type *base, uint32_t channel, uint32_t data)
+{
+ base->TDR[channel] = data;
+}
+
+/*!
+ * @brief Receives data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+void SAI_ReadBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Receives multi channel data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @param channelMask channel mask.
+ * @param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+void SAI_ReadMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Reads data from the SAI FIFO.
+ *
+ * @param base SAI base pointer.
+ * @param channel Data channel used.
+ * @return Data in SAI FIFO.
+ */
+static inline uint32_t SAI_ReadData(I2S_Type *base, uint32_t channel)
+{
+ return base->RDR[channel];
+}
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SAI Tx handle.
+ *
+ * This function initializes the Tx handle for the SAI Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function
+ */
+void SAI_TransferTxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData);
+
+/*!
+ * @brief Initializes the SAI Rx handle.
+ *
+ * This function initializes the Rx handle for the SAI Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function.
+ */
+void SAI_TransferRxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData);
+
+/*!
+ * @brief SAI transmitter transfer configurations.
+ *
+ * This function initializes the Tx, include bit clock, frame sync, master clock, serial data and fifo
+ * configurations.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI handle pointer.
+ * @param config tranmitter configurations.
+ */
+void SAI_TransferTxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config);
+
+/*!
+ * @brief SAI receiver transfer configurations.
+ *
+ * This function initializes the Rx, include bit clock, frame sync, master clock, serial data and fifo
+ * configurations.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI handle pointer.
+ * @param config receiver configurations.
+ */
+void SAI_TransferRxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config);
+
+/*!
+ * @brief Configures the SAI Tx audio format.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferTxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI handle pointer.
+ * @param format Pointer to the SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * @return Status of this function. Return value is the status_t.
+ */
+status_t SAI_TransferTxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Rx audio format.
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferRxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI handle pointer.
+ * @param format Pointer to the SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * @return Status of this function. Return value is one of status_t.
+ */
+status_t SAI_TransferRxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Performs an interrupt non-blocking send transfer on SAI.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SAI_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the sai_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SAI_TxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferSendNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on SAI.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SAI_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * @param base SAI base pointer
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the sai_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SAI_RxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferReceiveNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Gets a set byte count.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * @param count Bytes count sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetSendCount(I2S_Type *base, sai_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets a received byte count.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * @param count Bytes count received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetReceiveCount(I2S_Type *base, sai_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the current send.
+ *
+ * @note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortSend(I2S_Type *base, sai_handle_t *handle);
+
+/*!
+ * @brief Aborts the current IRQ receive.
+ *
+ * @note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SAI base pointer
+ * @param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortReceive(I2S_Type *base, sai_handle_t *handle);
+
+/*!
+ * @brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSend.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSend(I2S_Type *base, sai_handle_t *handle);
+
+/*!
+ * @brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceive.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceive(I2S_Type *base, sai_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferTxHandleIRQ(I2S_Type *base, sai_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SAI base pointer.
+ * @param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferRxHandleIRQ(I2S_Type *base, sai_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_SAI_H_ */ \ No newline at end of file
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.c
new file mode 100644
index 0000000000..47aa11def9
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.c
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_sai_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.sai_edma"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32UL) & ~0x1FU)
+
+static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
+/* Only support 2 and 4 channel */
+#define SAI_CHANNEL_MAP_MODULO(channel) (channel == 2U ? kEDMA_Modulo8bytes : kEDMA_Modulo16bytes)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct sai_edma_private_handle
+{
+ I2S_Type *base;
+ sai_edma_handle_t *handle;
+} sai_edma_private_handle_t;
+
+/*! @brief sai_edma_transfer_state, sai edma transfer state.*/
+enum
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_BusyLoopTransfer, /*!< SAI is busy for Loop transfer */
+ kSAI_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static sai_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_saiBases)][2];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+static uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief SAI EDMA callback for send.
+ *
+ * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SAI EDMA callback for receive.
+ *
+ * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t SAI_GetInstance(I2S_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_saiBases); instance++)
+ {
+ if (s_saiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_saiBases));
+
+ return instance;
+}
+
+static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+ status_t status = kStatus_SAI_TxBusy;
+
+ if (saiHandle->state != (uint32_t)kSAI_BusyLoopTransfer)
+ {
+ if (saiHandle->queueDriver + tcds > (uint32_t)SAI_XFER_QUEUE_SIZE)
+ {
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0,
+ sizeof(sai_transfer_t) * ((uint32_t)SAI_XFER_QUEUE_SIZE - saiHandle->queueDriver));
+ (void)memset(&saiHandle->saiQueue[0U], 0,
+ sizeof(sai_transfer_t) * (saiHandle->queueDriver + tcds - (uint32_t)SAI_XFER_QUEUE_SIZE));
+ }
+ else
+ {
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t) * tcds);
+ }
+ saiHandle->queueDriver = (uint8_t)((saiHandle->queueDriver + tcds) % (uint32_t)SAI_XFER_QUEUE_SIZE);
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ /* Disable DMA enable bit */
+ SAI_TxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
+ EDMA_AbortTransfer(handle);
+ status = kStatus_SAI_TxIdle;
+ }
+ }
+
+ /* If finished a block, call the callback function */
+ if (saiHandle->callback != NULL)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, status, saiHandle->userData);
+ }
+}
+
+static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+ status_t status = kStatus_SAI_RxBusy;
+
+ if (saiHandle->state != (uint32_t)kSAI_BusyLoopTransfer)
+ {
+ if (saiHandle->queueDriver + tcds > (uint32_t)SAI_XFER_QUEUE_SIZE)
+ {
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0,
+ sizeof(sai_transfer_t) * ((uint32_t)SAI_XFER_QUEUE_SIZE - saiHandle->queueDriver));
+ (void)memset(&saiHandle->saiQueue[0U], 0,
+ sizeof(sai_transfer_t) * (saiHandle->queueDriver + tcds - (uint32_t)SAI_XFER_QUEUE_SIZE));
+ }
+ else
+ {
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t) * tcds);
+ }
+ saiHandle->queueDriver = (uint8_t)((saiHandle->queueDriver + tcds) % (uint32_t)SAI_XFER_QUEUE_SIZE);
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ /* Disable DMA enable bit */
+ SAI_RxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
+ EDMA_AbortTransfer(handle);
+ status = kStatus_SAI_RxIdle;
+ }
+ }
+
+ /* If finished a block, call the callback function */
+ if (saiHandle->callback != NULL)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, status, saiHandle->userData);
+ }
+}
+
+/*!
+ * brief Initializes the SAI eDMA handle.
+ *
+ * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param base SAI peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferTxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *txDmaHandle)
+{
+ assert((handle != NULL) && (txDmaHandle != NULL));
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set sai base to handle */
+ handle->dmaHandle = txDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = (uint32_t)kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(txDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->tcd)), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(txDmaHandle, SAI_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+/*!
+ * brief Initializes the SAI Rx eDMA handle.
+ *
+ * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param base SAI peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferRxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *rxDmaHandle)
+{
+ assert((handle != NULL) && (rxDmaHandle != NULL));
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set sai base to handle */
+ handle->dmaHandle = rxDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = (uint32_t)kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(rxDmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(rxDmaHandle, SAI_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by ref SAI_TransferTxSetConfigEDMA
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param format Pointer to SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master
+ * clock, this value should equals to masterClockHz in format.
+ * retval kStatus_Success Audio format set successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (format->bitWidth == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = (uint8_t)(format->bitWidth / 8U);
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->count = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - format->watermark);
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Configures the SAI Tx.
+ *
+ * note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported.
+ * To activate the multi-channel transfer enable SAI channels by filling the channelMask
+ * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine
+ * mode by assigning kSAI_FifoCombineModeEnabledOnWrite to the fifoCombine member of sai_fifo_combine_t
+ * which is a member of sai_transceiver_t.
+ * This is an example of multi-channel data transfer configuration step.
+ * code
+ * sai_transceiver_t config;
+ * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask);
+ * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnWrite;
+ * SAI_TransferTxSetConfigEDMA(I2S0, &edmaHandle, &config);
+ * endcode
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param saiConfig sai configurations.
+ */
+void SAI_TransferTxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig)
+{
+ assert((handle != NULL) && (saiConfig != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_TxSetConfig(base, saiConfig);
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+ /* Allow multi-channel transfer only if FIFO Combine mode is enabled */
+ assert(
+ (saiConfig->channelNums <= 1U) ||
+ ((saiConfig->channelNums > 1U) && ((saiConfig->fifo.fifoCombine == kSAI_FifoCombineModeEnabledOnWrite) ||
+ (saiConfig->fifo.fifoCombine == kSAI_FifoCombineModeEnabledOnReadWrite))));
+#endif
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (saiConfig->serialData.dataWordLength == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
+ }
+ /* Update the data channel SAI used */
+ handle->channel = saiConfig->startChannel;
+ handle->channelMask = saiConfig->channelMask;
+ handle->channelNums = saiConfig->channelNums;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->count = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - saiConfig->fifo.fifoWatermark);
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by ref SAI_TransferRxSetConfigEDMA
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param format Pointer to SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master
+ * clock, this value should equal to masterClockHz in format.
+ * retval kStatus_Success Audio format set successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (format->bitWidth == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = (uint8_t)(format->bitWidth / 8U);
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->count = format->watermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Configures the SAI Rx.
+ *
+ * note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported.
+ * To activate the multi-channel transfer enable SAI channels by filling the channelMask
+ * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine
+ * mode by assigning kSAI_FifoCombineModeEnabledOnRead to the fifoCombine member of sai_fifo_combine_t
+ * which is a member of sai_transceiver_t.
+ * This is an example of multi-channel data transfer configuration step.
+ * code
+ * sai_transceiver_t config;
+ * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask);
+ * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnRead;
+ * SAI_TransferRxSetConfigEDMA(I2S0, &edmaHandle, &config);
+ * endcode
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param saiConfig sai configurations.
+ */
+void SAI_TransferRxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig)
+{
+ assert((handle != NULL) && (saiConfig != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_RxSetConfig(base, saiConfig);
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE
+ /* Allow multi-channel transfer only if FIFO Combine mode is enabled */
+ assert(
+ (saiConfig->channelNums <= 1U) ||
+ ((saiConfig->channelNums > 1U) && ((saiConfig->fifo.fifoCombine == kSAI_FifoCombineModeEnabledOnRead) ||
+ (saiConfig->fifo.fifoCombine == kSAI_FifoCombineModeEnabledOnReadWrite))));
+#endif
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (saiConfig->serialData.dataWordLength == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = saiConfig->startChannel;
+ handle->channelMask = saiConfig->channelMask;
+ handle->channelNums = saiConfig->channelNums;
+ /* Clear the channel enable bits until do a send/receive */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
+ handle->count = saiConfig->fifo.fifoWatermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_HAS_FIFO */
+}
+
+/*!
+ * brief Performs a non-blocking SAI transfer using DMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * This function support multi channel transfer,
+ * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation
+ * on channel numbers
+ * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using
+ * EDMA modulo feature, but support 2 or 4 channels only.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a SAI eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_TxBusy SAI is busy sending data.
+ */
+status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = SAI_TxGetDataRegisterAddress(base, handle->channel);
+ uint32_t destOffset = 0U;
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+#if !(defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ if (handle->channelNums > 1U)
+ {
+ destOffset = sizeof(uint32_t);
+ }
+#endif
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransferConfig(&config, xfer->data, (uint32_t)handle->bytesPerFrame, (int16_t)handle->bytesPerFrame,
+ (uint32_t *)destAddr, (uint32_t)handle->bytesPerFrame, (int16_t)destOffset,
+ (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize);
+
+ /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
+ handle->nbytes = handle->count * handle->bytesPerFrame;
+
+ if (EDMA_SubmitTransfer(handle->dmaHandle, &config) != kStatus_Success)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+#if !(defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ if (handle->channelNums > 1U)
+ {
+ if ((handle->channelNums % 2U) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ EDMA_SetModulo(handle->dmaHandle->base, handle->dmaHandle->channel, kEDMA_ModuloDisable,
+ SAI_CHANNEL_MAP_MODULO(handle->channelNums));
+ }
+#endif
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable SAI Tx clock */
+ SAI_TxEnable(base, true);
+
+ /* Enable the channel FIFO */
+ base->TCR3 |= I2S_TCR3_TCE(handle->channelMask);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SAI receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * This function support multi channel transfer,
+ * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation
+ * on channel numbers
+ * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using
+ * EDMA modulo feature, but support 2 or 4 channels only.
+ *
+ * param base SAI base pointer
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a SAI eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy SAI is busy receiving data.
+ */
+status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = SAI_RxGetDataRegisterAddress(base, handle->channel);
+ uint32_t srcOffset = 0U;
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Update queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+#if !(defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ if (handle->channelNums > 1U)
+ {
+ srcOffset = sizeof(uint32_t);
+ }
+#endif
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransferConfig(&config, (uint32_t *)srcAddr, (uint32_t)handle->bytesPerFrame, (int16_t)srcOffset,
+ xfer->data, (uint32_t)handle->bytesPerFrame, (int16_t)handle->bytesPerFrame,
+ (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize);
+ /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
+ handle->nbytes = handle->count * handle->bytesPerFrame;
+
+ if (EDMA_SubmitTransfer(handle->dmaHandle, &config) != kStatus_Success)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+#if !(defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ if (handle->channelNums > 1U)
+ {
+ if ((handle->channelNums % 2U) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ EDMA_SetModulo(handle->dmaHandle->base, handle->dmaHandle->channel, SAI_CHANNEL_MAP_MODULO(handle->channelNums),
+ kEDMA_ModuloDisable);
+ }
+#endif
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable the channel FIFO */
+ base->RCR3 |= I2S_RCR3_RCE(handle->channelMask);
+
+ /* Enable SAI Rx clock */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SAI loop transfer using eDMA.
+ *
+ * note This function support loop transfer only,such as A->B->...->A, application must be aware of
+ * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in
+ * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size.
+ * This function support one sai channel only.
+ *
+ * Once the loop transfer start, application can use function SAI_TransferAbortSendEDMA to stop the loop transfer.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount).
+ * param loopTransferCount the counts of xfer array.
+ * retval kStatus_Success Start a SAI eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+status_t SAI_TransferSendLoopEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_t *xfer,
+ uint32_t loopTransferCount)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = SAI_TxGetDataRegisterAddress(base, handle->channel);
+ sai_transfer_t *transfer = xfer;
+ edma_tcd_t *currentTCD = STCD_ADDR(handle->tcd);
+ uint32_t tcdIndex = 0U;
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ for (uint32_t i = 0U; i < loopTransferCount; i++)
+ {
+ transfer = &xfer[i];
+
+ if ((transfer->data == NULL) || (transfer->dataSize == 0U) || (tcdIndex >= (uint32_t)SAI_XFER_QUEUE_SIZE))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Update the queue state */
+ handle->transferSize[tcdIndex] = transfer->dataSize;
+ handle->saiQueue[tcdIndex].data = transfer->data;
+ handle->saiQueue[tcdIndex].dataSize = transfer->dataSize;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, transfer->data, handle->bytesPerFrame, (uint32_t *)destAddr,
+ handle->bytesPerFrame, (uint32_t)handle->count * handle->bytesPerFrame, transfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+
+ if (i == (loopTransferCount - 1U))
+ {
+ EDMA_TcdSetTransferConfig(&currentTCD[tcdIndex], &config, &currentTCD[0U]);
+ EDMA_TcdEnableInterrupts(&currentTCD[tcdIndex], (uint32_t)kEDMA_MajorInterruptEnable);
+ handle->state = (uint32_t)kSAI_BusyLoopTransfer;
+ break;
+ }
+ else
+ {
+ EDMA_TcdSetTransferConfig(&currentTCD[tcdIndex], &config, &currentTCD[tcdIndex + 1U]);
+ EDMA_TcdEnableInterrupts(&currentTCD[tcdIndex], (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+
+ tcdIndex = tcdIndex + 1U;
+ }
+
+ EDMA_InstallTCD(handle->dmaHandle->base, handle->dmaHandle->channel, &currentTCD[0]);
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable SAI Tx clock */
+ SAI_TxEnable(base, true);
+
+ /* Enable the channel FIFO */
+ base->TCR3 |= I2S_TCR3_TCE(1UL << handle->channel);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SAI loop transfer using eDMA.
+ *
+ * note This function support loop transfer only,such as A->B->...->A, application must be aware of
+ * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in
+ * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size.
+ * This function support one sai channel only.
+ *
+ * Once the loop transfer start, application can use function SAI_TransferAbortReceiveEDMA to stop the loop transfer.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount).
+ * param loopTransferCount the counts of xfer array.
+ * retval kStatus_Success Start a SAI eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+status_t SAI_TransferReceiveLoopEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_t *xfer,
+ uint32_t loopTransferCount)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = SAI_RxGetDataRegisterAddress(base, handle->channel);
+ sai_transfer_t *transfer = xfer;
+ edma_tcd_t *currentTCD = STCD_ADDR(handle->tcd);
+ uint32_t tcdIndex = 0U;
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ for (uint32_t i = 0U; i < loopTransferCount; i++)
+ {
+ transfer = &xfer[i];
+
+ if ((tcdIndex >= (uint32_t)SAI_XFER_QUEUE_SIZE) || (xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Update the queue state */
+ handle->transferSize[tcdIndex] = transfer->dataSize;
+ handle->saiQueue[tcdIndex].data = transfer->data;
+ handle->saiQueue[tcdIndex].dataSize = transfer->dataSize;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, transfer->data, handle->bytesPerFrame,
+ (uint32_t)handle->count * handle->bytesPerFrame, transfer->dataSize,
+ kEDMA_PeripheralToMemory);
+
+ if (i == (loopTransferCount - 1U))
+ {
+ EDMA_TcdSetTransferConfig(&currentTCD[tcdIndex], &config, &currentTCD[0U]);
+ EDMA_TcdEnableInterrupts(&currentTCD[tcdIndex], (uint32_t)kEDMA_MajorInterruptEnable);
+ handle->state = (uint32_t)kSAI_BusyLoopTransfer;
+ break;
+ }
+ else
+ {
+ EDMA_TcdSetTransferConfig(&currentTCD[tcdIndex], &config, &currentTCD[tcdIndex + 1U]);
+ EDMA_TcdEnableInterrupts(&currentTCD[tcdIndex], (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+
+ tcdIndex = tcdIndex + 1U;
+ }
+
+ EDMA_InstallTCD(handle->dmaHandle->base, handle->dmaHandle->channel, &currentTCD[0]);
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+ /* Enable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable the channel FIFO */
+ base->RCR3 |= I2S_RCR3_RCE(1UL << handle->channel);
+
+ /* Enable SAI Rx clock */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a SAI transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateSendEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable the channel FIFO */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+
+ /* Disable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Disable Tx */
+ SAI_TxEnable(base, false);
+
+ /* If Tx is disabled, reset the FIFO pointer and clear error flags */
+ if ((base->TCSR & I2S_TCSR_TE_MASK) == 0UL)
+ {
+ base->TCSR |= (I2S_TCSR_FR_MASK | I2S_TCSR_SR_MASK);
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+ }
+
+ /* Handle the queue index */
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kSAI_Idle;
+}
+
+/*!
+ * brief Aborts a SAI receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateReceiveEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable the channel FIFO */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+
+ /* Disable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Disable Rx */
+ SAI_RxEnable(base, false);
+
+ /* If Rx is disabled, reset the FIFO pointer and clear error flags */
+ if ((base->RCSR & I2S_RCSR_RE_MASK) == 0UL)
+ {
+ base->RCSR |= (I2S_RCSR_FR_MASK | I2S_RCSR_SR_MASK);
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+ }
+
+ /* Handle the queue index */
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kSAI_Idle;
+}
+
+/*!
+ * brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSendEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortSendEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(handle->tcd));
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceiveEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortReceiveEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(handle->tcd));
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Gets byte count sent by SAI.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param count Bytes count sent by SAI.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets byte count received by SAI.
+ *
+ * param base SAI base pointer
+ * param handle SAI eDMA handle pointer.
+ * param count Bytes count received by SAI.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * @rief Gets valid transfer slot.
+ *
+ * This function can be used to query the valid transfer request slot that the application can submit.
+ * It should be called in the critical section, that means the application could call it in the corresponding callback
+ * function or disable IRQ before calling it in the application, otherwise, the returned value may not correct.
+ *
+ * param base SAI base pointer
+ * param handle SAI eDMA handle pointer.
+ * retval valid slot count that application submit.
+ */
+uint32_t SAI_TransferGetValidTransferSlotsEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ uint32_t validSlot = 0U;
+
+ for (uint32_t i = 0U; i < (uint32_t)SAI_XFER_QUEUE_SIZE; i++)
+ {
+ if (handle->saiQueue[i].data == NULL)
+ {
+ validSlot++;
+ }
+ }
+
+ return validSlot;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.h
new file mode 100644
index 0000000000..c5cb4d6ece
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_edma.h
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_SAI_EDMA_H_
+#define _FSL_SAI_EDMA_H_
+
+#include "fsl_edma.h"
+#include "fsl_sai.h"
+
+/*!
+ * @addtogroup sai_edma SAI EDMA Driver
+ * @ingroup sai
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SAI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 5, 0)) /*!< Version 2.5.0 */
+/*@}*/
+
+typedef struct sai_edma_handle sai_edma_handle_t;
+
+/*! @brief SAI eDMA transfer callback function for finish and error */
+typedef void (*sai_edma_callback_t)(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SAI DMA transfer handle, users should not touch the content of the handle.*/
+struct sai_edma_handle
+{
+ edma_handle_t *dmaHandle; /*!< DMA handler for SAI send */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t bytesPerFrame; /*!< Bytes in a frame */
+ uint8_t channelMask; /*!< Enabled channel mask value, reference _sai_channel_mask */
+ uint8_t channelNums; /*!< total enabled channel nums */
+ uint8_t channel; /*!< Which data channel */
+ uint8_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for SAI eDMA transfer */
+ sai_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ uint8_t tcd[(SAI_XFER_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA transfer. */
+ sai_transfer_t saiQueue[SAI_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[SAI_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SAI eDMA handle.
+ *
+ * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param txDmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferTxCreateHandleEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *txDmaHandle);
+
+/*!
+ * @brief Initializes the SAI Rx eDMA handle.
+ *
+ * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param rxDmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferRxCreateHandleEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *rxDmaHandle);
+
+/*!
+ * @brief Configures the SAI Tx audio format.
+ *
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferTxSetConfigEDMA
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master
+ * clock, this value should equals to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Rx audio format.
+ *
+ * @deprecated Do not use this function. It has been superceded by @ref SAI_TransferRxSetConfigEDMA
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master
+ * clock, this value should equal to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Tx.
+ *
+ * @note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported.
+ * To activate the multi-channel transfer enable SAI channels by filling the channelMask
+ * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine
+ * mode by assigning kSAI_FifoCombineModeEnabledOnWrite to the fifoCombine member of sai_fifo_combine_t
+ * which is a member of sai_transceiver_t.
+ * This is an example of multi-channel data transfer configuration step.
+ * @code
+ * sai_transceiver_t config;
+ * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask);
+ * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnWrite;
+ * SAI_TransferTxSetConfigEDMA(I2S0, &edmaHandle, &config);
+ * @endcode
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param saiConfig sai configurations.
+ */
+void SAI_TransferTxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig);
+
+/*!
+ * @brief Configures the SAI Rx.
+ *
+ * @note SAI eDMA supports data transfer in a multiple SAI channels if the FIFO Combine feature is supported.
+ * To activate the multi-channel transfer enable SAI channels by filling the channelMask
+ * of sai_transceiver_t with the corresponding values of _sai_channel_mask enum, enable the FIFO Combine
+ * mode by assigning kSAI_FifoCombineModeEnabledOnRead to the fifoCombine member of sai_fifo_combine_t
+ * which is a member of sai_transceiver_t.
+ * This is an example of multi-channel data transfer configuration step.
+ * @code
+ * sai_transceiver_t config;
+ * SAI_GetClassicI2SConfig(&config, kSAI_WordWidth16bits, kSAI_Stereo, kSAI_Channel0Mask|kSAI_Channel1Mask);
+ * config.fifo.fifoCombine = kSAI_FifoCombineModeEnabledOnRead;
+ * SAI_TransferRxSetConfigEDMA(I2S0, &edmaHandle, &config);
+ * @endcode
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param saiConfig sai configurations.
+ */
+void SAI_TransferRxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig);
+
+/*!
+ * @brief Performs a non-blocking SAI transfer using DMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * This function support multi channel transfer,
+ * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation
+ * on channel numbers
+ * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using
+ * EDMA modulo feature, but support 2 or 4 channels only.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a SAI eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_TxBusy SAI is busy sending data.
+ */
+status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SAI receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * This function support multi channel transfer,
+ * 1. for the sai IP support fifo combine mode, application should enable the fifo combine mode, no limitation
+ * on channel numbers
+ * 2. for the sai IP not support fifo combine mode, sai edma provide another solution which using
+ * EDMA modulo feature, but support 2 or 4 channels only.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a SAI eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy SAI is busy receiving data.
+ */
+status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SAI loop transfer using eDMA.
+ *
+ * @note This function support loop transfer only,such as A->B->...->A, application must be aware of
+ * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in
+ * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size.
+ * This function support one sai channel only.
+ *
+ * Once the loop transfer start, application can use function SAI_TransferAbortSendEDMA to stop the loop transfer.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount).
+ * @param loopTransferCount the counts of xfer array.
+ * @retval kStatus_Success Start a SAI eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+status_t SAI_TransferSendLoopEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_t *xfer,
+ uint32_t loopTransferCount);
+
+/*!
+ * @brief Performs a non-blocking SAI loop transfer using eDMA.
+ *
+ * @note This function support loop transfer only,such as A->B->...->A, application must be aware of
+ * that the more counts of the loop transfer, then more tcd memory required, as the function use the tcd pool in
+ * sai_edma_handle_t, so application could redefine the SAI_XFER_QUEUE_SIZE to determine the proper TCD pool size.
+ * This function support one sai channel only.
+ *
+ * Once the loop transfer start, application can use function SAI_TransferAbortReceiveEDMA to stop the loop transfer.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure, should be a array with elements counts >=1(loopTransferCount).
+ * @param loopTransferCount the counts of xfer array.
+ * @retval kStatus_Success Start a SAI eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+status_t SAI_TransferReceiveLoopEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_t *xfer,
+ uint32_t loopTransferCount);
+
+/*!
+ * @brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSendEDMA.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSendEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceiveEDMA.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SAI transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateSendEDMA.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SAI receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateReceiveEDMA.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count sent by SAI.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param count Bytes count sent by SAI.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets byte count received by SAI.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ * @param count Bytes count received by SAI.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets valid transfer slot.
+ *
+ * This function can be used to query the valid transfer request slot that the application can submit.
+ * It should be called in the critical section, that means the application could call it in the corresponding callback
+ * function or disable IRQ before calling it in the application, otherwise, the returned value may not correct.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ * @retval valid slot count that application submit.
+ */
+uint32_t SAI_TransferGetValidTransferSlotsEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_sdma.h b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_sdma.h
new file mode 100644
index 0000000000..64dd81b69c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sai/fsl_sai_sdma.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2017 - 2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_SAI_SDMA_H_
+#define _FSL_SAI_SDMA_H_
+
+#include "fsl_sai.h"
+#include "fsl_sdma.h"
+
+/*!
+ * @addtogroup sai_sdma SAI SDMA Driver
+ * @ingroup sai
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SAI_SDMA_DRIVER_VERSION (MAKE_VERSION(2, 5, 3)) /*!< Version 2.5.3 */
+/*@}*/
+
+typedef struct _sai_sdma_handle sai_sdma_handle_t;
+
+/*! @brief SAI SDMA transfer callback function for finish and error */
+typedef void (*sai_sdma_callback_t)(I2S_Type *base, sai_sdma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SAI DMA transfer handle, users should not touch the content of the handle. */
+struct _sai_sdma_handle
+{
+ sdma_handle_t *dmaHandle; /*!< DMA handler for SAI send */
+ uint8_t bytesPerFrame; /*!< Bytes in a frame */
+ uint8_t channel; /*!< start data channel */
+ uint8_t channelNums; /*!< total transfer channel numbers, used for multififo */
+ uint8_t channelMask; /*!< enabled channel mask value, refernece _sai_channel_mask */
+ uint8_t fifoOffset; /*!< fifo address offset between multifo*/
+ uint32_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for SAI SDMA transfer */
+ uint32_t eventSource; /*!< SAI event source number */
+ sai_sdma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ sdma_buffer_descriptor_t bdPool[SAI_XFER_QUEUE_SIZE]; /*!< BD pool for SDMA transfer. */
+ sai_transfer_t saiQueue[SAI_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[SAI_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/*!
+ * @name SDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SAI SDMA handle.
+ *
+ * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
+ * @param eventSource SAI event source number.
+ */
+void SAI_TransferTxCreateHandleSDMA(I2S_Type *base,
+ sai_sdma_handle_t *handle,
+ sai_sdma_callback_t callback,
+ void *userData,
+ sdma_handle_t *dmaHandle,
+ uint32_t eventSource);
+
+/*!
+ * @brief Initializes the SAI Rx SDMA handle.
+ *
+ * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
+ * @param eventSource SAI event source number.
+ */
+void SAI_TransferRxCreateHandleSDMA(I2S_Type *base,
+ sai_sdma_handle_t *handle,
+ sai_sdma_callback_t callback,
+ void *userData,
+ sdma_handle_t *dmaHandle,
+ uint32_t eventSource);
+
+/*!
+ * @brief Configures the SAI Tx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the SDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master
+ * clock, this value should equals to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferTxSetFormatSDMA(I2S_Type *base,
+ sai_sdma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the SDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master
+ * clock, this value should equal to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferRxSetFormatSDMA(I2S_Type *base,
+ sai_sdma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Performs a non-blocking SAI transfer using DMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a SAI SDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_TxBusy SAI is busy sending data.
+ */
+status_t SAI_TransferSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SAI receive using SDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI SDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a SAI SDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy SAI is busy receiving data.
+ */
+status_t SAI_TransferReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a SAI transfer using SDMA.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ */
+void SAI_TransferAbortSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SAI receive using SDMA.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI SDMA handle pointer.
+ */
+void SAI_TransferAbortReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle);
+
+/*!
+ * @brief Terminate all the SAI sdma receive transfer.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ */
+void SAI_TransferTerminateReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle);
+
+/*!
+ * @brief Terminate all the SAI sdma send transfer.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI SDMA handle pointer.
+ */
+void SAI_TransferTerminateSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle);
+
+/*!
+ * brief Configures the SAI RX.
+ *
+ * param base SAI base pointer.
+ * param handle SAI SDMA handle pointer.
+ * param saiConig sai configurations.
+ */
+void SAI_TransferRxSetConfigSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transceiver_t *saiConfig);
+
+/*!
+ * brief Configures the SAI Tx.
+ *
+ * param base SAI base pointer.
+ * param handle SAI SDMA handle pointer.
+ * param saiConig sai configurations.
+ */
+void SAI_TransferTxSetConfigSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transceiver_t *saiConfig);
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.c b/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.c
new file mode 100644
index 0000000000..847769009c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2017-2019, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_sema4.h"
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.sema4"
+#endif
+
+/* The first number write to RSTGDP when reset SEMA4 gate. */
+#define SEMA4_GATE_RESET_PATTERN_1 (0xE2U)
+/* The second number write to RSTGDP when reset SEMA4 gate. */
+#define SEMA4_GATE_RESET_PATTERN_2 (0x1DU)
+
+/* The first number write to RSTGDP when reset SEMA4 gate IRQ notification. */
+#define SEMA4_GATE_IRQ_RESET_PATTERN_1 (0x47U)
+/* The second number write to RSTGDP when reset SEMA4 gate IRQ notification. */
+#define SEMA4_GATE_IRQ_RESET_PATTERN_2 (0xB8U)
+
+#define SEMA4_RSTGT_RSTNSM_MASK (0x30U)
+
+#define SEMA4_RSTNTF_RSTNSM_MASK (0x30U)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if defined(SEMA4_CLOCKS)
+/*!
+ * @brief Get instance number for SEMA4 module.
+ *
+ * @param base SEMA4 peripheral base address.
+ */
+uint32_t SEMA4_GetInstance(SEMA4_Type *base);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if defined(SEMA4_CLOCKS)
+/*! @brief Pointers to sema4 bases for each instance. */
+static SEMA4_Type *const s_sema4Bases[] = SEMA4_BASE_PTRS;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(SEMA4_CLOCKS)
+/*! @brief Pointers to sema4 clocks for each instance. */
+static const clock_ip_name_t s_sema4Clocks[] = SEMA4_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/******************************************************************************
+ * CODE
+ *****************************************************************************/
+
+#if defined(SEMA4_CLOCKS)
+uint32_t SEMA4_GetInstance(SEMA4_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_sema4Bases); instance++)
+ {
+ if (s_sema4Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_sema4Bases));
+
+ return instance;
+}
+#endif
+
+/*!
+ * brief Initializes the SEMA4 module.
+ *
+ * This function initializes the SEMA4 module. It only enables the clock but does
+ * not reset the gates because the module might be used by other processors
+ * at the same time. To reset the gates, call either SEMA4_ResetGate or
+ * SEMA4_ResetAllGates function.
+ *
+ * param base SEMA4 peripheral base address.
+ */
+void SEMA4_Init(SEMA4_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(SEMA4_CLOCKS)
+ CLOCK_EnableClock(s_sema4Clocks[SEMA4_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief De-initializes the SEMA4 module.
+ *
+ * This function de-initializes the SEMA4 module. It only disables the clock.
+ *
+ * param base SEMA4 peripheral base address.
+ */
+void SEMA4_Deinit(SEMA4_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(SEMA4_CLOCKS)
+ CLOCK_DisableClock(s_sema4Clocks[SEMA4_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Tries to lock the SEMA4 gate.
+ *
+ * This function tries to lock the specific SEMA4 gate. If the gate has been
+ * locked by another processor, this function returns an error code.
+ *
+ * param base SEMA4 peripheral base address.
+ * param gateNum Gate number to lock.
+ * param procNum Current processor number.
+ *
+ * retval kStatus_Success Lock the sema4 gate successfully.
+ * retval kStatus_Fail Sema4 gate has been locked by another processor.
+ */
+status_t SEMA4_TryLock(SEMA4_Type *base, uint8_t gateNum, uint8_t procNum)
+{
+ status_t status;
+
+ assert(gateNum < (uint8_t)FSL_FEATURE_SEMA4_GATE_COUNT);
+
+ ++procNum;
+
+ /* Try to lock. */
+ SEMA4_GATEn(base, gateNum) = procNum;
+
+ /* Check locked or not. */
+ if (procNum != SEMA4_GATEn(base, gateNum))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Locks the SEMA4 gate.
+ *
+ * This function locks the specific SEMA4 gate. If the gate has been
+ * locked by other processors, this function waits until it is unlocked and then
+ * lock it.
+ *
+ * param base SEMA4 peripheral base address.
+ * param gateNum Gate number to lock.
+ * param procNum Current processor number.
+ */
+void SEMA4_Lock(SEMA4_Type *base, uint8_t gateNum, uint8_t procNum)
+{
+ while (kStatus_Success != SEMA4_TryLock(base, gateNum, procNum))
+ {
+ }
+}
+
+/*!
+ * brief Resets the SEMA4 gate to an unlocked status.
+ *
+ * This function resets a SEMA4 gate to an unlocked status.
+ *
+ * param base SEMA4 peripheral base address.
+ * param gateNum Gate number.
+ *
+ * retval kStatus_Success SEMA4 gate is reset successfully.
+ * retval kStatus_Fail Some other reset process is ongoing.
+ */
+status_t SEMA4_ResetGate(SEMA4_Type *base, uint8_t gateNum)
+{
+ status_t status;
+
+ /*
+ * Reset all gates if gateNum >= SEMA4_GATE_NUM_RESET_ALL
+ * Reset specific gate if gateNum < FSL_FEATURE_SEMA4_GATE_COUNT
+ */
+ assert(!((gateNum < SEMA4_GATE_NUM_RESET_ALL) && (gateNum >= (uint8_t)FSL_FEATURE_SEMA4_GATE_COUNT)));
+
+ /* Check whether some reset is ongoing. */
+ if (0U != (base->RSTGT & SEMA4_RSTGT_RSTNSM_MASK))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ /* First step. */
+ base->RSTGT = SEMA4_RSTGT_RSTGSM_RSTGMS_RSTGDP(SEMA4_GATE_RESET_PATTERN_1);
+ /* Second step. */
+ base->RSTGT = SEMA4_RSTGT_RSTGSM_RSTGMS_RSTGDP(SEMA4_GATE_RESET_PATTERN_2) | SEMA4_RSTGT_RSTGTN(gateNum);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Resets the SEMA4 gate IRQ notification.
+ *
+ * This function resets a SEMA4 gate IRQ notification.
+ *
+ * param base SEMA4 peripheral base address.
+ * param gateNum Gate number.
+ *
+ * retval kStatus_Success Reset successfully.
+ * retval kStatus_Fail Some other reset process is ongoing.
+ */
+status_t SEMA4_ResetGateNotify(SEMA4_Type *base, uint8_t gateNum)
+{
+ status_t status;
+
+ /*
+ * Reset all gates if gateNum >= SEMA4_GATE_NUM_RESET_ALL
+ * Reset specific gate if gateNum < FSL_FEATURE_SEMA4_GATE_COUNT
+ */
+ assert(!((gateNum < (uint8_t)SEMA4_GATE_NUM_RESET_ALL) && (gateNum >= (uint8_t)FSL_FEATURE_SEMA4_GATE_COUNT)));
+
+ /* Check whether some reset is ongoing. */
+ if (0U != (base->RSTNTF & SEMA4_RSTNTF_RSTNSM_MASK))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ /* First step. */
+ base->RSTNTF = SEMA4_RSTNTF_RSTNSM_RSTNMS_RSTNDP(SEMA4_GATE_IRQ_RESET_PATTERN_1);
+ /* Second step. */
+ base->RSTNTF = SEMA4_RSTNTF_RSTNSM_RSTNMS_RSTNDP(SEMA4_GATE_IRQ_RESET_PATTERN_2) | SEMA4_RSTNTF_RSTNTN(gateNum);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.h b/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.h
new file mode 100644
index 0000000000..512cc90346
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/sema4/fsl_sema4.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2017-2020, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SEMA4_H_
+#define _FSL_SEMA4_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup sema4
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief SEMA4 driver version */
+#define FSL_SEMA4_DRIVER_VERSION (MAKE_VERSION(2, 0, 3))
+/*@}*/
+
+/*! @brief The number to reset all SEMA4 gates. */
+#define SEMA4_GATE_NUM_RESET_ALL (64U)
+
+#if defined(SEMA4_GATE_COUNT)
+
+/*!
+ * @brief SEMA4 gate n register address.
+ */
+#define SEMA4_GATEn(base, n) ((base)->GATE[(n)])
+
+#ifndef FSL_FEATURE_SEMA4_GATE_COUNT
+#define FSL_FEATURE_SEMA4_GATE_COUNT SEMA4_GATE_COUNT
+#endif
+
+#else
+
+/*!
+ * @brief SEMA4 gate n register address.
+ */
+#define SEMA4_GATEn(base, n) (((volatile uint8_t *)(&((base)->Gate00)))[(n)])
+
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the SEMA4 module.
+ *
+ * This function initializes the SEMA4 module. It only enables the clock but does
+ * not reset the gates because the module might be used by other processors
+ * at the same time. To reset the gates, call either SEMA4_ResetGate or
+ * SEMA4_ResetAllGates function.
+ *
+ * @param base SEMA4 peripheral base address.
+ */
+void SEMA4_Init(SEMA4_Type *base);
+
+/*!
+ * @brief De-initializes the SEMA4 module.
+ *
+ * This function de-initializes the SEMA4 module. It only disables the clock.
+ *
+ * @param base SEMA4 peripheral base address.
+ */
+void SEMA4_Deinit(SEMA4_Type *base);
+
+/*!
+ * @brief Tries to lock the SEMA4 gate.
+ *
+ * This function tries to lock the specific SEMA4 gate. If the gate has been
+ * locked by another processor, this function returns an error code.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number to lock.
+ * @param procNum Current processor number.
+ *
+ * @retval kStatus_Success Lock the sema4 gate successfully.
+ * @retval kStatus_Fail Sema4 gate has been locked by another processor.
+ */
+status_t SEMA4_TryLock(SEMA4_Type *base, uint8_t gateNum, uint8_t procNum);
+
+/*!
+ * @brief Locks the SEMA4 gate.
+ *
+ * This function locks the specific SEMA4 gate. If the gate has been
+ * locked by other processors, this function waits until it is unlocked and then
+ * lock it.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number to lock.
+ * @param procNum Current processor number.
+ */
+void SEMA4_Lock(SEMA4_Type *base, uint8_t gateNum, uint8_t procNum);
+
+/*!
+ * @brief Unlocks the SEMA4 gate.
+ *
+ * This function unlocks the specific SEMA4 gate. It only writes unlock value
+ * to the SEMA4 gate register. However, it does not check whether the SEMA4 gate is locked
+ * by the current processor or not. As a result, if the SEMA4 gate is not locked by the current
+ * processor, this function has no effect.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number to unlock.
+ */
+static inline void SEMA4_Unlock(SEMA4_Type *base, uint8_t gateNum)
+{
+ assert(gateNum < (uint8_t)FSL_FEATURE_SEMA4_GATE_COUNT);
+
+ SEMA4_GATEn(base, gateNum) = 0U;
+}
+
+/*!
+ * @brief Gets the status of the SEMA4 gate.
+ *
+ * This function checks the lock status of a specific SEMA4 gate.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @return Return -1 if the gate is unlocked, otherwise return the
+ * processor number which has locked the gate.
+ */
+static inline int32_t SEMA4_GetLockProc(SEMA4_Type *base, uint8_t gateNum)
+{
+ assert(gateNum < (uint8_t)FSL_FEATURE_SEMA4_GATE_COUNT);
+
+ return (int32_t)(SEMA4_GATEn(base, gateNum)) - 1;
+}
+
+/*!
+ * @brief Resets the SEMA4 gate to an unlocked status.
+ *
+ * This function resets a SEMA4 gate to an unlocked status.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @retval kStatus_Success SEMA4 gate is reset successfully.
+ * @retval kStatus_Fail Some other reset process is ongoing.
+ */
+status_t SEMA4_ResetGate(SEMA4_Type *base, uint8_t gateNum);
+
+/*!
+ * @brief Resets all SEMA4 gates to an unlocked status.
+ *
+ * This function resets all SEMA4 gate to an unlocked status.
+ *
+ * @param base SEMA4 peripheral base address.
+ *
+ * @retval kStatus_Success SEMA4 is reset successfully.
+ * @retval kStatus_Fail Some other reset process is ongoing.
+ */
+static inline status_t SEMA4_ResetAllGates(SEMA4_Type *base)
+{
+ return SEMA4_ResetGate(base, SEMA4_GATE_NUM_RESET_ALL);
+}
+
+/*!
+ * @brief Enable the gate notification interrupt.
+ *
+ * Gate notification provides such feature, when core tried to lock the gate
+ * and failed, it could get notification when the gate is idle.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param procNum Current processor number.
+ * @param mask OR'ed value of the gate index, for example: (1<<0) | (1<<1) means
+ * gate 0 and gate 1.
+ */
+static inline void SEMA4_EnableGateNotifyInterrupt(SEMA4_Type *base, uint8_t procNum, uint32_t mask)
+{
+ mask = __REV(__RBIT(mask));
+ base->CPINE[procNum].CPINE |= (uint16_t)mask;
+}
+
+/*!
+ * @brief Disable the gate notification interrupt.
+ *
+ * Gate notification provides such feature, when core tried to lock the gate
+ * and failed, it could get notification when the gate is idle.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param procNum Current processor number.
+ * @param mask OR'ed value of the gate index, for example: (1<<0) | (1<<1) means
+ * gate 0 and gate 1.
+ */
+static inline void SEMA4_DisableGateNotifyInterrupt(SEMA4_Type *base, uint8_t procNum, uint32_t mask)
+{
+ mask = __REV(__RBIT(mask));
+ base->CPINE[procNum].CPINE &= (uint16_t)(~mask);
+}
+
+/*!
+ * @brief Get the gate notification flags.
+ *
+ * Gate notification provides such feature, when core tried to lock the gate
+ * and failed, it could get notification when the gate is idle. The status flags
+ * are cleared automatically when the gate is locked by current core or locked
+ * again before the other core.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param procNum Current processor number.
+ * @return OR'ed value of the gate index, for example: (1<<0) | (1<<1) means
+ * gate 0 and gate 1 flags are pending.
+ */
+static inline uint32_t SEMA4_GetGateNotifyStatus(SEMA4_Type *base, uint8_t procNum)
+{
+ return __REV(__RBIT(base->CPNTF[procNum].CPNTF));
+}
+
+/*!
+ * @brief Resets the SEMA4 gate IRQ notification.
+ *
+ * This function resets a SEMA4 gate IRQ notification.
+ *
+ * @param base SEMA4 peripheral base address.
+ * @param gateNum Gate number.
+ *
+ * @retval kStatus_Success Reset successfully.
+ * @retval kStatus_Fail Some other reset process is ongoing.
+ */
+status_t SEMA4_ResetGateNotify(SEMA4_Type *base, uint8_t gateNum);
+
+/*!
+ * @brief Resets all SEMA4 gates IRQ notification.
+ *
+ * This function resets all SEMA4 gate IRQ notifications.
+ *
+ * @param base SEMA4 peripheral base address.
+ *
+ * @retval kStatus_Success Reset successfully.
+ * @retval kStatus_Fail Some other reset process is ongoing.
+ */
+static inline status_t SEMA4_ResetAllGateNotify(SEMA4_Type *base)
+{
+ return SEMA4_ResetGateNotify(base, SEMA4_GATE_NUM_RESET_ALL);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_SEMA4_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.c b/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.c
new file mode 100644
index 0000000000..84b54317b8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.c
@@ -0,0 +1,1385 @@
+/*
+ * Copyright 2017-2022 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)
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+#define SEMC_IOCR_PINMUXBITWIDTH (0x4UL)
+#else
+#define SEMC_IOCR_PINMUXBITWIDTH (0x3UL)
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+#define SEMC_IOCR_NAND_CE (4UL)
+#define SEMC_IOCR_NOR_CE (5UL)
+#define SEMC_IOCR_NOR_CE_A8 (2UL)
+#define SEMC_IOCR_PSRAM_CE (6UL)
+#if defined(SEMC_IOCR_PINMUXBITWIDTH) && (SEMC_IOCR_PINMUXBITWIDTH == 0x4UL)
+#define SEMC_IOCR_PSRAM_CE_A8 (6UL)
+#else
+#define SEMC_IOCR_PSRAM_CE_A8 (3UL)
+#endif /* SEMC_IOCR_PINMUXBITWIDTH */
+#define SEMC_IOCR_DBI_CSX (7UL)
+#define SEMC_IOCR_DBI_CSX_A8 (4UL)
+#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 (0x80000000UL)
+#define SEMC_ENDADDRESS (0xDFFFFFFFUL)
+#define SEMC_BR_MEMSIZE_MIN (4U)
+#define SEMC_BR_MEMSIZE_OFFSET (2U)
+#define SEMC_BR_MEMSIZE_MAX (4UL * 1024UL * 1024UL)
+#define SEMC_SDRAM_MODESETCAL_OFFSET (4U)
+#define SEMC_BR_REG_NUM (9U)
+#define SEMC_BYTE_NUMBIT (8U)
+/*******************************************************************************
+ * 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 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(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;
+#if (defined(SEMC_EXSC_CLOCKS))
+static const clock_ip_name_t s_semcExtClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_EXSC_CLOCKS;
+#endif /* 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(uint32_t size_kbytes, uint8_t *sizeConverted)
+{
+ assert(sizeConverted != NULL);
+ uint32_t memsize;
+ status_t status = kStatus_Success;
+
+ if ((size_kbytes < SEMC_BR_MEMSIZE_MIN) || (size_kbytes > SEMC_BR_MEMSIZE_MAX))
+ {
+ status = kStatus_SEMC_InvalidMemorySize;
+ }
+ else
+ {
+ *sizeConverted = 0U;
+ memsize = size_kbytes / 8U;
+ while (memsize != 0x00U)
+ {
+ memsize >>= 1U;
+ (*sizeConverted)++;
+ }
+ }
+
+ return status;
+}
+
+static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz)
+{
+ assert(clkSrc_Hz != 0x00U);
+
+ uint8_t clockCycles = 0;
+ uint32_t tClk_ps;
+
+ clkSrc_Hz /= 1000000U;
+ /* Using ps for high resolution */
+ tClk_ps = 1000000U / clkSrc_Hz;
+
+ while (tClk_ps * clockCycles < time_ns * 1000U)
+ {
+ clockCycles++;
+ }
+
+ return (clockCycles == 0x00U) ? clockCycles : (clockCycles - 0x01U);
+}
+
+static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes)
+{
+ status_t status = kStatus_Success;
+
+ if ((size_bytes > SEMC_IPCOMMANDDATASIZEBYTEMAX) || (size_bytes == 0x00U))
+ {
+ status = kStatus_SEMC_InvalidIpcmdDataSize;
+ }
+ else
+ {
+ /* Set data size. */
+ /* Note: It is better to set data size as the device data port width when transferring
+ * 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 transfers, 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 < 4U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM3_MASK;
+ }
+ if (size_bytes < 3U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM2_MASK;
+ }
+ if (size_bytes < 2U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM1_MASK;
+ }
+ }
+
+ return status;
+}
+
+static status_t SEMC_IsIPCommandDone(SEMC_Type *base)
+{
+ status_t status = kStatus_Success;
+
+ /* Poll status bit till command is done*/
+ while ((base->INTR & (uint32_t)SEMC_INTR_IPCMDDONE_MASK) == 0x00U)
+ {
+ };
+
+ /* Clear status bit */
+ base->INTR |= SEMC_INTR_IPCMDDONE_MASK;
+
+ /* Check error status */
+ if ((base->INTR & (uint32_t)SEMC_INTR_IPCMDERR_MASK) != 0x00U)
+ {
+ base->INTR |= SEMC_INTR_IPCMDERR_MASK;
+ status = kStatus_SEMC_IpCommandExecutionError;
+ }
+
+ return status;
+}
+
+/*!
+ * 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 != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->queueWeight.queueaEnable = true;
+ semc_queuea_weight_struct_t *queueaWeight = &(config->queueWeight.queueaWeight.queueaConfig);
+ config->queueWeight.queuebEnable = true;
+ semc_queueb_weight_struct_t *queuebWeight = &(config->queueWeight.queuebWeight.queuebConfig);
+
+ /* Get default settings. */
+ config->dqsMode = kSEMC_Loopbackinternal;
+ config->cmdTimeoutCycles = 0xFF;
+ 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 != NULL);
+
+ 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)]);
+#if (defined(SEMC_EXSC_CLOCKS))
+ CLOCK_EnableClock(s_semcExtClock[SEMC_GetInstance(base)]);
+#endif /* SEMC_EXSC_CLOCKS */
+#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 & (uint32_t)SEMC_MCR_SWRST_MASK) != 0x00U)
+ {
+ }
+
+ /* 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);
+
+ if (configure->queueWeight.queueaEnable == true)
+ {
+ /* Configure Queue A for AXI bus access to SDRAM, NAND, NOR, SRAM and DBI slaves.*/
+ base->BMCR0 = (uint32_t)(configure->queueWeight.queueaWeight.queueaValue);
+ }
+ else
+ {
+ base->BMCR0 = 0x00U;
+ }
+
+ if (configure->queueWeight.queuebEnable == true)
+ {
+ /* Configure Queue B for AXI bus access to SDRAM slave. */
+ base->BMCR1 = (uint32_t)(configure->queueWeight.queuebWeight.queuebValue);
+ }
+ else
+ {
+ base->BMCR1 = 0x00U;
+ }
+
+ /* 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 & (uint32_t)SEMC_STS0_IDLE_MASK) == 0x00U)
+ {
+ ;
+ }
+
+ 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)]);
+#if (defined(SEMC_EXSC_CLOCKS))
+ CLOCK_DisableClock(s_semcExtClock[SEMC_GetInstance(base)]);
+#endif /* SEMC_EXSC_CLOCKS */
+#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 != NULL);
+ assert(clkSrc_Hz > 0x00U);
+ assert(config->refreshBurstLen > 0x00U);
+
+ uint8_t memsize;
+ status_t result = kStatus_Success;
+ uint16_t prescale = (uint16_t)(config->tPrescalePeriod_Ns / 16U / (1000000000U / clkSrc_Hz));
+ uint32_t refresh;
+ uint32_t urgentRef;
+ uint32_t idle;
+ uint32_t mode;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ if (config->csxPinMux == kSEMC_MUXA8)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+
+ if (prescale > 256U)
+ {
+ 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 << (uint32_t)config->csxPinMux));
+
+ /* Base control. */
+ result = SEMC_CovertMemorySize(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;
+
+#if defined(FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT) && (FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT)
+ if (kSEMC_SdramColunm_8bit == config->columnAddrBitNum)
+ {
+ base->SDRAMCR0 = SEMC_SDRAMCR0_PS(config->portSize) | SEMC_SDRAMCR0_BL(config->burstLen) |
+ SEMC_SDRAMCR0_COL8(true) | SEMC_SDRAMCR0_CL(config->casLatency);
+ }
+ else
+#endif /* FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT */
+ {
+ 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 != kSEMC_SDRAM_CS0)
+ {
+ base->IOCR = iocReg | ((uint32_t)cs << (uint32_t)config->csxPinMux);
+ }
+
+ base->IOCR &= ~SEMC_IOCR_MUX_A8_MASK;
+
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint32_t tempDelayChain = base->DCCR;
+
+ tempDelayChain &= ~(SEMC_DCCR_SDRAMVAL_MASK | SEMC_DCCR_SDRAMEN_MASK);
+ /* Configure delay chain. */
+ base->DCCR = tempDelayChain | SEMC_DCCR_SDRAMVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SDRAMEN_MASK;
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+
+ timing = SEMC_SDRAMCR1_PRE2ACT(SEMC_ConvertTiming(config->tPrecharge2Act_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_ACT2RW(SEMC_ConvertTiming(config->tAct2ReadWrite_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_RFRC(SEMC_ConvertTiming(config->tRefreshRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_WRC(SEMC_ConvertTiming(config->tWriteRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_CKEOFF(SEMC_ConvertTiming(config->tCkeOff_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_ACT2PRE(SEMC_ConvertTiming(config->tAct2Prechage_Ns, clkSrc_Hz));
+ /* SDRAMCR1 timing setting. */
+ base->SDRAMCR1 = timing;
+
+ timing = SEMC_SDRAMCR2_SRRC(SEMC_ConvertTiming(config->tSelfRefRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR2_REF2REF(SEMC_ConvertTiming(config->tRefresh2Refresh_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR2_ACT2ACT(SEMC_ConvertTiming(config->tAct2Act_Ns, clkSrc_Hz)) | SEMC_SDRAMCR2_ITO(idle);
+ /* SDRAMCR2 timing setting. */
+ base->SDRAMCR2 = timing;
+
+ /* SDRAMCR3 timing setting. */
+ base->SDRAMCR3 = SEMC_SDRAMCR3_REBL((uint32_t)config->refreshBurstLen - 1UL) |
+ /* N * 16 * 1s / clkSrc_Hz = config->tPrescalePeriod_Ns */
+ SEMC_SDRAMCR3_PRESCALE(prescale) | SEMC_SDRAMCR3_RT(refresh - 1UL) | SEMC_SDRAMCR3_UT(urgentRef);
+
+ SEMC->IPCR1 = 0x2U;
+ SEMC->IPCR2 = 0U;
+
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_Prechargeall, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ /* Mode setting value. */
+ mode = (uint32_t)config->burstLen | (((uint32_t)config->casLatency) << SEMC_SDRAM_MODESETCAL_OFFSET);
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)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 != NULL);
+ assert(config->timingConfig != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->axiAddress < SEMC_STARTADDRESS) || (config->axiAddress > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ if (config->cePinMux == kSEMC_MUXRDY)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+
+ /* Disable SEMC module during configuring control registers. */
+ base->MCR |= SEMC_MCR_MDIS_MASK;
+
+ uint32_t iocReg =
+ base->IOCR & (~((SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)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(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(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 ((uint32_t)config->cePinMux != 0x00U)
+ {
+ base->IOCR = iocReg | (SEMC_IOCR_NAND_CE << (uint32_t)config->cePinMux);
+ }
+ else
+ {
+ base->IOCR = iocReg | (1UL << (uint32_t)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 = SEMC_NANDCR1_CES(SEMC_ConvertTiming(config->timingConfig->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_CEH(SEMC_ConvertTiming(config->timingConfig->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_WEL(SEMC_ConvertTiming(config->timingConfig->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_WEH(SEMC_ConvertTiming(config->timingConfig->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_REL(SEMC_ConvertTiming(config->timingConfig->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_REH(SEMC_ConvertTiming(config->timingConfig->tReHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_TA(SEMC_ConvertTiming(config->timingConfig->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_CEITV(SEMC_ConvertTiming(config->timingConfig->tCeInterval_Ns, clkSrc_Hz));
+ /* NANDCR1 timing setting. */
+ base->NANDCR1 = timing;
+
+ timing = SEMC_NANDCR2_TWHR(SEMC_ConvertTiming(config->timingConfig->tWehigh2Relow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TRHW(SEMC_ConvertTiming(config->timingConfig->tRehigh2Welow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TADL(SEMC_ConvertTiming(config->timingConfig->tAle2WriteStart_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TRR(SEMC_ConvertTiming(config->timingConfig->tReady2Relow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TWB(SEMC_ConvertTiming(config->timingConfig->tWehigh2Busy_Ns, clkSrc_Hz));
+
+ /* NANDCR2 timing setting. */
+ base->NANDCR2 = timing;
+
+ /* NANDCR3 timing setting. */
+ base->NANDCR3 = (uint32_t)config->arrayAddrOption;
+
+ /* Enables SEMC module after configuring control registers completely. */
+ base->MCR &= ~SEMC_MCR_MDIS_MASK;
+
+ 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 != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux));
+ uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_NOR_CE - 1U) :
+ ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_NOR_CE_A8 : SEMC_IOCR_NOR_CE);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux);
+ /* Address bit setting. */
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE)
+ {
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U))
+ {
+ /* 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 + 2U))
+ {
+ /* 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 + 3U))
+ {
+ /* 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 + 4U))
+ {
+ 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(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);
+
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint32_t tempDelayChain = base->DCCR;
+
+ tempDelayChain &= ~(SEMC_DCCR_NORVAL_MASK | SEMC_DCCR_NOREN_MASK);
+ /* Configure delay chain. */
+ base->DCCR = tempDelayChain | SEMC_DCCR_NORVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_NOREN_MASK;
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+
+ timing = SEMC_NORCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz));
+
+ /* NORCR1 timing setting. */
+ base->NORCR1 = timing;
+
+ timing = SEMC_NORCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME)
+ timing |= 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)
+ timing |= SEMC_NORCR2_WDH(SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz));
+#endif /* FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME */
+ timing |= SEMC_NORCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR2_AWDH((uint32_t)SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz) + 0x01UL);
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_LC_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_LC_TIME)
+ timing |= SEMC_NORCR2_LC(config->latencyCount);
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_RD_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_RD_TIME)
+ timing |= SEMC_NORCR2_RD((uint32_t)config->readCycle - 0x01UL);
+#endif
+
+ /* NORCR2 timing setting. */
+ base->NORCR2 = timing;
+
+ return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U));
+}
+
+/*!
+ * brief Configures SRAM controller in SEMC, which can be used only for specific chip selection CS0.
+ *
+ * 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)
+{
+ return SEMC_ConfigureSRAMWithChipSelection(base, kSEMC_SRAM_CS0, config, clkSrc_Hz);
+}
+
+/*!
+ * brief Configures SRAM controller in SEMC, which can be used up to four chip selections CS0/CS1/CS2/CS3..
+ *
+ * param base SEMC peripheral base address.
+ * param cs The chip selection.
+ * param config The sram configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureSRAMWithChipSelection(SEMC_Type *base,
+ semc_sram_cs_t cs,
+ semc_sram_config_t *config,
+ uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+
+ uint32_t tempBRVal;
+ uint32_t timing;
+ 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 << (uint32_t)config->cePinMux));
+
+ uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_PSRAM_CE - 1U) :
+ ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_PSRAM_CE_A8 : SEMC_IOCR_PSRAM_CE);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux);
+ /* Address bit setting. */
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE)
+ {
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U))
+ {
+ /* 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 + 2U))
+ {
+ /* 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 + 3U))
+ {
+ /* 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 + 4U))
+ {
+ 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(config->memsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ tempBRVal = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+
+ uint32_t tempCtrlVal;
+
+ switch (cs)
+ {
+ case kSEMC_SRAM_CS0:
+ base->BR[6] = tempBRVal;
+ break;
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+ case kSEMC_SRAM_CS1:
+ base->BR9 = tempBRVal;
+ break;
+ case kSEMC_SRAM_CS2:
+ base->BR10 = tempBRVal;
+ break;
+ case kSEMC_SRAM_CS3:
+ base->BR11 = tempBRVal;
+ break;
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+ default:
+ assert(NULL);
+ break;
+ }
+
+ /* PSRAM0 SRAMCRx timing setting. */
+ if (kSEMC_SRAM_CS0 == cs)
+ {
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+ /* Ready/wait(WAITEN and WAITSP) feature is only for async mode. */
+ if (kSEMC_AsyncMode == config->syncMode)
+ {
+ tempCtrlVal = SEMC_SRAMCR0_PS(config->portSize) |
+#if defined(SEMC_SRAMCR4_SYNCEN_MASK) && (SEMC_SRAMCR4_SYNCEN_MASK)
+ SEMC_SRAMCR4_SYNCEN(config->syncMode) |
+#endif /* SEMC_SRAMCR4_SYNCEN_MASK */
+#if defined(SEMC_SRAMCR0_WAITEN_MASK) && (SEMC_SRAMCR0_WAITEN_MASK)
+ SEMC_SRAMCR0_WAITEN(config->waitEnable) |
+#endif /* SEMC_SRAMCR0_WAITEN_MASK */
+#if defined(SEMC_SRAMCR0_WAITSP_MASK) && (SEMC_SRAMCR0_WAITSP_MASK)
+ SEMC_SRAMCR0_WAITSP(config->waitSample) |
+#endif /* SEMC_SRAMCR0_WAITSP_MASK */
+ SEMC_SRAMCR0_BL(config->burstLen) | SEMC_SRAMCR0_AM(config->addrMode) |
+ SEMC_SRAMCR0_ADVP(config->advActivePolarity) |
+#if defined(SEMC_SRAMCR4_ADVH_MASK) && (SEMC_SRAMCR4_ADVH_MASK)
+ SEMC_SRAMCR4_ADVH(config->advLevelCtrl) |
+#endif /* SEMC_SRAMCR4_ADVH_MASK */
+ SEMC_SRAMCR0_COL_MASK;
+ }
+ else
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+ {
+ tempCtrlVal = SEMC_SRAMCR0_PS(config->portSize) |
+#if defined(SEMC_SRAMCR4_SYNCEN_MASK) && (SEMC_SRAMCR4_SYNCEN_MASK)
+ SEMC_SRAMCR4_SYNCEN(config->syncMode) |
+#endif /* SEMC_SRAMCR4_SYNCEN_MASK */
+ SEMC_SRAMCR0_BL(config->burstLen) | SEMC_SRAMCR0_AM(config->addrMode) |
+ SEMC_SRAMCR0_ADVP(config->advActivePolarity) |
+#if defined(SEMC_SRAMCR4_ADVH_MASK) && (SEMC_SRAMCR4_ADVH_MASK)
+ SEMC_SRAMCR4_ADVH(config->advLevelCtrl) |
+#endif /* SEMC_SRAMCR4_ADVH_MASK */
+ SEMC_SRAMCR0_COL_MASK;
+ }
+
+ base->SRAMCR0 = tempCtrlVal;
+ }
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+ /* PSRAM1~PSRAM3 SRAMCRx timing setting. */
+ else
+ {
+ /* Ready/wait(WAITEN and WAITSP) feature is only for async mode. */
+ if (kSEMC_AsyncMode == config->syncMode)
+ {
+ tempCtrlVal = SEMC_SRAMCR4_PS(config->portSize) | SEMC_SRAMCR4_SYNCEN(config->syncMode) |
+ SEMC_SRAMCR4_WAITEN(config->waitEnable) | SEMC_SRAMCR4_WAITSP(config->waitSample) |
+ SEMC_SRAMCR4_BL(config->burstLen) | SEMC_SRAMCR4_AM(config->addrMode) |
+ SEMC_SRAMCR4_ADVP(config->advActivePolarity) | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) |
+ SEMC_SRAMCR4_COL_MASK;
+ }
+ else
+ {
+ tempCtrlVal = SEMC_SRAMCR4_PS(config->portSize) | SEMC_SRAMCR4_SYNCEN(config->syncMode) |
+ SEMC_SRAMCR4_BL(config->burstLen) | SEMC_SRAMCR4_AM(config->addrMode) |
+ SEMC_SRAMCR4_ADVP(config->advActivePolarity) | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) |
+ SEMC_SRAMCR4_COL_MASK;
+ }
+
+ base->SRAMCR4 = tempCtrlVal;
+ }
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint32_t tempDelayChain = base->DCCR;
+
+ /* Configure delay chain. */
+ switch (cs)
+ {
+ case kSEMC_SRAM_CS0:
+ tempDelayChain &= ~(SEMC_DCCR_SRAM0VAL_MASK | SEMC_DCCR_SRAM0EN_MASK);
+ base->DCCR =
+ tempDelayChain | SEMC_DCCR_SRAM0VAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SRAM0EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+ case kSEMC_SRAM_CS1:
+ SUPPRESS_FALL_THROUGH_WARNING();
+ case kSEMC_SRAM_CS2:
+ SUPPRESS_FALL_THROUGH_WARNING();
+ case kSEMC_SRAM_CS3:
+ tempDelayChain &= ~(SEMC_DCCR_SRAMXVAL_MASK | SEMC_DCCR_SRAMXEN_MASK);
+ base->DCCR =
+ tempDelayChain | SEMC_DCCR_SRAMXVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SRAMXEN_MASK;
+ break;
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+ default:
+ assert(NULL);
+ break;
+ }
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+
+ if (kSEMC_SRAM_CS0 == cs)
+ {
+ timing = SEMC_SRAMCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz));
+
+ /* SRAMCR1 timing setting. */
+ base->SRAMCR1 = timing;
+
+ timing = 0x00U;
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME)
+ timing |= SEMC_SRAMCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz));
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME)
+ timing |= SEMC_SRAMCR2_WDH((uint32_t)SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz) + 1UL);
+#endif
+ timing |= SEMC_SRAMCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME)
+ timing |= SEMC_SRAMCR2_LC(config->latencyCount);
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME)
+ timing |= SEMC_SRAMCR2_RD((uint32_t)config->readCycle - 1UL);
+#endif
+ timing |= SEMC_SRAMCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME)
+ timing |= SEMC_SRAMCR2_RDH((uint32_t)SEMC_ConvertTiming(config->readHoldTime_Ns, clkSrc_Hz) + 0x01U);
+#endif /* FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME */
+
+ /* SRAMCR2 timing setting. */
+ base->SRAMCR2 = timing;
+ }
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U)
+ else
+ {
+ timing = SEMC_SRAMCR5_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR5_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz));
+
+ /* SRAMCR5 timing setting. */
+ base->SRAMCR5 = timing;
+
+ timing = 0x00U;
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME)
+ timing = SEMC_SRAMCR6_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz));
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME)
+ timing |= SEMC_SRAMCR6_WDH((uint32_t)SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz) + 1UL);
+#endif
+ timing |= SEMC_SRAMCR6_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR6_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME)
+ timing |= SEMC_SRAMCR6_LC(config->latencyCount);
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME)
+ timing |= SEMC_SRAMCR6_RD((uint32_t)config->readCycle - 1UL);
+#endif
+ timing |= SEMC_SRAMCR6_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME)
+ timing |= SEMC_SRAMCR6_RDH((uint32_t)SEMC_ConvertTiming(config->readHoldTime_Ns, clkSrc_Hz) + 0x01U);
+#endif /* FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME */
+
+ /* SRAMCR6 timing setting. */
+ base->SRAMCR6 = timing;
+ }
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+
+ 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 != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->csxPinMux));
+ uint32_t muxCsx = (config->csxPinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_DBI_CSX - 1U) :
+ ((config->csxPinMux == kSEMC_MUXA8) ? SEMC_IOCR_DBI_CSX_A8 : SEMC_IOCR_DBI_CSX);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCsx << (uint32_t)config->csxPinMux);
+ /* Base control. */
+ result = SEMC_CovertMemorySize(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;
+
+ /* DBICR0 timing setting. */
+ base->DBICR0 =
+ SEMC_DBICR0_PS(config->portSize) | SEMC_DBICR0_BL(config->burstLen) | SEMC_DBICR0_COL(config->columnAddrBitNum);
+
+ timing = SEMC_DBICR1_CES(SEMC_ConvertTiming(config->tCsxSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_CEH(SEMC_ConvertTiming(config->tCsxHold_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_WEL(SEMC_ConvertTiming(config->tWexLow_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_WEH(SEMC_ConvertTiming(config->tWexHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_REL(SEMC_ConvertTiming(config->tRdxLow_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_REH(SEMC_ConvertTiming(config->tRdxHigh_Ns, clkSrc_Hz));
+#if defined(SEMC_DBICR1_CEITV_MASK)
+ timing |= SEMC_DBICR1_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz));
+#endif /* SEMC_DBICR1_CEITV_MASK */
+
+ /* DBICR1 timing setting. */
+ base->DBICR1 = timing;
+
+#if defined(SEMC_DBICR2_CEITV_MASK)
+ timing = SEMC_DBICR2_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz));
+
+ /* DBICR2 timing setting. */
+ base->DBICR2 = timing;
+#endif /* SEMC_DBICR2_CEITV_MASK */
+
+ return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U));
+}
+
+/*!
+ * brief SEMC IP command access.
+ *
+ * param base SEMC peripheral base address.
+ * param memType 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 memType, uint32_t address, uint32_t command, uint32_t write, uint32_t *read)
+{
+ uint32_t cmdMode;
+ bool readCmd = false;
+ bool writeCmd = false;
+ status_t result;
+
+ /* Clear status bit */
+ base->INTR |= SEMC_INTR_IPCMDDONE_MASK;
+ /* Set address. */
+ base->IPCR0 = address;
+
+ /* Check command mode. */
+ cmdMode = (uint32_t)command & 0x0FU;
+ switch (memType)
+ {
+ case kSEMC_MemType_NAND:
+ readCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressRead) ||
+ (cmdMode == (uint32_t)kSEMC_NANDCM_CommandRead) || (cmdMode == (uint32_t)kSEMC_NANDCM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressWrite) ||
+ (cmdMode == (uint32_t)kSEMC_NANDCM_CommandWrite) || (cmdMode == (uint32_t)kSEMC_NANDCM_Write);
+ break;
+ case kSEMC_MemType_NOR:
+ case kSEMC_MemType_8080:
+ readCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Write);
+ break;
+ case kSEMC_MemType_SRAM:
+ readCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayRead) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegRead);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayWrite) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegWrite);
+ break;
+ case kSEMC_MemType_SDRAM:
+ readCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Write) || (cmdMode == (uint32_t)kSEMC_SDRAMCM_Modeset);
+ break;
+ default:
+ assert(false);
+ 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 != NULL);
+
+ 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. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, *(uint32_t *)(void *)data, NULL);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+
+ while (size_bytes != 0x00U)
+ {
+ size_bytes--;
+ tempData <<= SEMC_BYTE_NUMBIT;
+ tempData |= data[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 != NULL);
+
+ status_t result = kStatus_Success;
+ uint16_t ipCmd;
+ uint32_t tempData = 0;
+
+ /* Configure IP command data size. */
+ (void)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 *)(void *)data);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, &tempData);
+
+ while (size_bytes != 0x00U)
+ {
+ size_bytes--;
+ *(data + size_bytes) = (uint8_t)((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 != NULL);
+
+ uint32_t tempData = 0;
+ status_t result = kStatus_Success;
+ uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK;
+
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint32_t)kSEMC_NORDBICM_Read, 0,
+ (uint32_t *)(void *)data);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Read, 0, &tempData);
+ while (size_bytes != 0x00U)
+ {
+ size_bytes--;
+ *(data + size_bytes) = (uint8_t)((tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU);
+ }
+ }
+
+ (void)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 != NULL);
+
+ uint32_t tempData = 0;
+ status_t result = kStatus_Success;
+ uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK;
+
+ /* Write command built */
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write,
+ *(uint32_t *)(void *)data, NULL);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+
+ while (size_bytes != 0x00U)
+ {
+ tempData |= ((uint32_t) * (data + size_bytes - 1U) << ((size_bytes - 1U) * SEMC_BYTE_NUMBIT));
+ size_bytes--;
+ }
+
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write, tempData, NULL);
+ }
+ (void)SEMC_ConfigureIPCommand(base, dataSize);
+
+ return result;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.h b/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.h
new file mode 100644
index 0000000000..e6efec0d8e
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/semc/fsl_semc.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2017-2022 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. */
+#define FSL_SEMC_DRIVER_VERSION (MAKE_VERSION(2, 4, 3))
+/*@}*/
+
+/*! @brief SEMC status, _semc_status. */
+enum
+{
+ kStatus_SEMC_InvalidDeviceType = MAKE_STATUS(kStatusGroup_SEMC, 0), /*!< Invalid device type. */
+ kStatus_SEMC_IpCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 1), /*!< IP command execution error. */
+ kStatus_SEMC_AxiCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 2), /*!< AXI command execution error. */
+ kStatus_SEMC_InvalidMemorySize = MAKE_STATUS(kStatusGroup_SEMC, 3), /*!< Invalid memory sie. */
+ kStatus_SEMC_InvalidIpcmdDataSize = MAKE_STATUS(kStatusGroup_SEMC, 4), /*!< Invalid IP command data size. */
+ kStatus_SEMC_InvalidAddressPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 5), /*!< Invalid address port width. */
+ kStatus_SEMC_InvalidDataPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 6), /*!< Invalid data port width. */
+ kStatus_SEMC_InvalidSwPinmuxSelection = MAKE_STATUS(kStatusGroup_SEMC, 7), /*!< Invalid SW pinmux selection. */
+ kStatus_SEMC_InvalidBurstLength = MAKE_STATUS(kStatusGroup_SEMC, 8), /*!< Invalid burst length */
+ /*! Invalid column address bit width. */
+ kStatus_SEMC_InvalidColumnAddressBitWidth = MAKE_STATUS(kStatusGroup_SEMC, 9),
+ kStatus_SEMC_InvalidBaseAddress = MAKE_STATUS(kStatusGroup_SEMC, 10), /*!< Invalid base address. */
+ kStatus_SEMC_InvalidTimerSetting = MAKE_STATUS(kStatusGroup_SEMC, 11), /*!< Invalid timer setting. */
+};
+
+/*! @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 SRAM Chip selection . */
+typedef enum _semc_sram_cs
+{
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT == 0x04U)
+ kSEMC_SRAM_CS0 = 0, /*!< SEMC SRAM CS0. */
+ kSEMC_SRAM_CS1, /*!< SEMC SRAM CS1. */
+ kSEMC_SRAM_CS2, /*!< SEMC SRAM CS2. */
+ kSEMC_SRAM_CS3 /*!< SEMC SRAM CS3. */
+#else
+ kSEMC_SRAM_CS0 = 0, /*!< SEMC SRAM CS0. */
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */
+} semc_sram_cs_t;
+
+/*! @brief SEMC NAND device type. */
+typedef enum _semc_nand_access_type
+{
+ kSEMC_NAND_ACCESS_BY_AXI = 0, /*!< Access to NAND flash by AXI bus. */
+ kSEMC_NAND_ACCESS_BY_IPCMD, /*!< Access to NAND flash by IP bus. */
+} 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. */
+#if defined(FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT) && (FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT)
+ kSEMC_SdramColunm_8bit, /*!< 8 bit. */
+#endif /* FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT */
+} semc_sdram_column_bit_num_t;
+
+/*! @brief SEMC sdram burst length. */
+typedef enum _semc_sdram_burst_len
+{
+/*! According to ERR050577, Auto-refresh command may possibly fail to be triggered during
+ long time back-to-back write (or read) when SDRAM controller's burst length is greater than 1. */
+#if defined(FSL_FEATURE_SEMC_ERRATA_050577) && (FSL_FEATURE_SEMC_ERRATA_050577 == 0x01U)
+ kSEMC_Sdram_BurstLen1 = 0, /*!< Burst length 1*/
+#else
+ 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*/
+#endif /* FSL_FEATURE_SEMC_ERRATA_050577 */
+} 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. */
+#if defined(FSL_FEATURE_SEMC_SUPPORT_SDRAM_PS_BITWIDTH) && (FSL_FEATURE_SEMC_SUPPORT_SDRAM_PS_BITWIDTH == 0x02U)
+ kSEMC_PortSize32Bit /*!< 32-Bit port size. */
+#endif /* FSL_FEATURE_SEMC_SUPPORT_SDRAM_PS_BITWIDTH */
+} 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 high. */
+} semc_adv_polarity_t;
+
+/*! @brief SEMC sync mode. */
+typedef enum _semc_sync_mode
+{
+ kSEMC_AsyncMode = 0, /*!< Async mode. */
+ kSEMC_SyncMode, /*!< Sync mode. */
+} semc_sync_mode_t;
+
+/*! @brief SEMC ADV signal level control. */
+typedef enum _semc_adv_level_control
+{
+ kSEMC_AdvHigh = 0, /*!< Adv is high during address hold state. */
+ kSEMC_AdvLow, /*!< Adv is low during address hold state. */
+} semc_adv_level_control_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. */
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint8_t delayChain; /*!< Delay chain, which adds delays on DQS clock to compensate timings while DQS is faster than
+ read data. */
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+} 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
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_LC_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_LC_TIME)
+ uint8_t latencyCount; /*!< Latency count for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_RD_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_RD_TIME)
+ uint8_t readCycle; /*!< Read cycle time for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint8_t delayChain; /*!< Delay chain, which adds delays on DQS clock to compensate timings while DQS is faster than
+ read data. */
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+} 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. */
+#if defined(SEMC_SRAMCR4_SYNCEN_MASK) && (SEMC_SRAMCR4_SYNCEN_MASK)
+ semc_sync_mode_t syncMode; /*!< Sync mode. */
+#endif /* SEMC_SRAMCR4_SYNCEN_MASK */
+#if defined(SEMC_SRAMCR0_WAITEN_MASK) && (SEMC_SRAMCR0_WAITEN_MASK)
+ bool waitEnable; /*!< Wait enable. */
+#endif /* SEMC_SRAMCR0_WAITEN_MASK */
+#if defined(SEMC_SRAMCR0_WAITSP_MASK) && (SEMC_SRAMCR0_WAITSP_MASK)
+ uint8_t waitSample; /*!< Wait sample. */
+#endif /* SEMC_SRAMCR0_WAITSP_MASK */
+#if defined(SEMC_SRAMCR4_ADVH_MASK) && (SEMC_SRAMCR4_ADVH_MASK)
+ semc_adv_level_control_t advLevelCtrl; /*!< ADV# level control during address hold state, 1: low, 0: high. */
+#endif /* SEMC_SRAMCR4_ADVH_MASK */
+ uint8_t tCeSetup_Ns; /*!< The CE setup time. */
+ uint8_t tCeHold_Ns; /*!< The CE hold time. */
+ uint8_t tCeInterval_Ns; /*!< CE interval minimum time. */
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME)
+ uint8_t readHoldTime_Ns; /*!< read hold time. */
+#endif /* FSL_FEATURE_SEMC_HAS_SRAM_RDH_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_SRAM_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME)
+ uint8_t tWriteSetup_Ns; /*!<Write data setup time for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME)
+ uint8_t tWriteHold_Ns; /*!<Write hold time for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME)
+ uint8_t latencyCount; /*!<Latency count for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME)
+ uint8_t readCycle; /*!<Read cycle time for sync mode. */
+#endif
+#if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL)
+ uint8_t delayChain; /*!< Delay chain, which adds delays on DQS clock to compensate timings while DQS is faster than
+ read data. */
+#endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */
+} 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
+{
+ bool queueaEnable; /*!< Enable queue a. */
+ semc_queuea_weight_t queueaWeight; /*!< Weight settings for queue a. */
+ bool queuebEnable; /*!< Enable queue b. */
+ 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 cs The chip selection.
+ * @param config The sram configuration.
+ * @param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureSRAMWithChipSelection(SEMC_Type *base,
+ semc_sram_cs_t cs,
+ semc_sram_config_t *config,
+ uint32_t clkSrc_Hz);
+
+/*!
+ * @brief Configures SRAM controller in SEMC.
+ * @deprecated Do not use this function. It has been superceded by @ref SEMC_ConfigureSRAMWithChipSelection.
+ * @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 != 0x00U) ? true : false;
+}
+
+/*!
+ * @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) != 0x00U) ? true : false;
+}
+
+/*!
+ * @brief SEMC IP command access.
+ *
+ * @param base SEMC peripheral base address.
+ * @param memType 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 memType, uint32_t address, uint32_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)userCommand << 8U) | ((uint16_t)addrMode << 4U) | ((uint16_t)cmdMode & 0x000FU);
+}
+
+/*!
+ * @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) != 0x00U) ? 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/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h
new file mode 100644
index 0000000000..2c7f81609b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SMARTCARD_H_
+#define _FSL_SMARTCARD_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup smartcard
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Smart card driver version 2.2.2.
+ */
+#define FSL_SMARTCARD_DRIVER_VERSION (MAKE_VERSION(2, 2, 2))
+/*@}*/
+
+/*! @brief Smart card global define which specify number of clock cycles until initial 'TS' character has to be received
+ */
+#define SMARTCARD_INIT_DELAY_CLOCK_CYCLES (42000u)
+
+/*! @brief Smart card global define which specify number of clock cycles during which ATR string has to be received */
+#define SMARTCARD_EMV_ATR_DURATION_ETU (20150u)
+
+/*! @brief Smart card specification initial TS character definition of direct convention */
+#define SMARTCARD_TS_DIRECT_CONVENTION (0x3Bu)
+
+/*! @brief Smart card specification initial TS character definition of inverse convention */
+#define SMARTCARD_TS_INVERSE_CONVENTION (0x3Fu)
+
+/*! @brief Smart card Error codes. */
+enum
+{
+ kStatus_SMARTCARD_Success = MAKE_STATUS(kStatusGroup_SMARTCARD, 0), /*!< Transfer ends successfully */
+ kStatus_SMARTCARD_TxBusy = MAKE_STATUS(kStatusGroup_SMARTCARD, 1), /*!< Transmit in progress */
+ kStatus_SMARTCARD_RxBusy = MAKE_STATUS(kStatusGroup_SMARTCARD, 2), /*!< Receiving in progress */
+ kStatus_SMARTCARD_NoTransferInProgress = MAKE_STATUS(kStatusGroup_SMARTCARD, 3), /*!< No transfer in progress */
+ kStatus_SMARTCARD_Timeout = MAKE_STATUS(kStatusGroup_SMARTCARD, 4), /*!< Transfer ends with time-out */
+ kStatus_SMARTCARD_Initialized =
+ MAKE_STATUS(kStatusGroup_SMARTCARD, 5), /*!< Smart card driver is already initialized */
+ kStatus_SMARTCARD_PhyInitialized =
+ MAKE_STATUS(kStatusGroup_SMARTCARD, 6), /*!< Smart card PHY drive is already initialized */
+ kStatus_SMARTCARD_CardNotActivated = MAKE_STATUS(kStatusGroup_SMARTCARD, 7), /*!< Smart card is not activated */
+ kStatus_SMARTCARD_InvalidInput =
+ MAKE_STATUS(kStatusGroup_SMARTCARD, 8), /*!< Function called with invalid input arguments */
+ kStatus_SMARTCARD_OtherError = MAKE_STATUS(kStatusGroup_SMARTCARD, 9) /*!< Some other error occur */
+};
+
+/*! @brief Control codes for the Smart card protocol timers and misc. */
+typedef enum _smartcard_control
+{
+ kSMARTCARD_EnableADT = 0x0u,
+ kSMARTCARD_DisableADT = 0x1u,
+ kSMARTCARD_EnableGTV = 0x2u,
+ kSMARTCARD_DisableGTV = 0x3u,
+ kSMARTCARD_ResetWWT = 0x4u,
+ kSMARTCARD_EnableWWT = 0x5u,
+ kSMARTCARD_DisableWWT = 0x6u,
+ kSMARTCARD_ResetCWT = 0x7u,
+ kSMARTCARD_EnableCWT = 0x8u,
+ kSMARTCARD_DisableCWT = 0x9u,
+ kSMARTCARD_ResetBWT = 0xAu,
+ kSMARTCARD_EnableBWT = 0xBu,
+ kSMARTCARD_DisableBWT = 0xCu,
+ kSMARTCARD_EnableInitDetect = 0xDu,
+ kSMARTCARD_EnableAnack = 0xEu,
+ kSMARTCARD_DisableAnack = 0xFu,
+ kSMARTCARD_ConfigureBaudrate = 0x10u,
+ kSMARTCARD_SetupATRMode = 0x11u,
+ kSMARTCARD_SetupT0Mode = 0x12u,
+ kSMARTCARD_SetupT1Mode = 0x13u,
+ kSMARTCARD_EnableReceiverMode = 0x14u,
+ kSMARTCARD_DisableReceiverMode = 0x15u,
+ kSMARTCARD_EnableTransmitterMode = 0x16u,
+ kSMARTCARD_DisableTransmitterMode = 0x17u,
+ kSMARTCARD_ResetWaitTimeMultiplier = 0x18u,
+} smartcard_control_t;
+
+/*! @brief Defines Smart card interface voltage class values */
+typedef enum _smartcard_card_voltage_class
+{
+ kSMARTCARD_VoltageClassUnknown = 0x0u,
+ kSMARTCARD_VoltageClassA5_0V = 0x1u,
+ kSMARTCARD_VoltageClassB3_3V = 0x2u,
+ kSMARTCARD_VoltageClassC1_8V = 0x3u
+} smartcard_card_voltage_class_t;
+
+/*! @brief Defines Smart card I/O transfer states */
+typedef enum _smartcard_transfer_state
+{
+ kSMARTCARD_IdleState = 0x0u,
+ kSMARTCARD_WaitingForTSState = 0x1u,
+ kSMARTCARD_InvalidTSDetecetedState = 0x2u,
+ kSMARTCARD_ReceivingState = 0x3u,
+ kSMARTCARD_TransmittingState = 0x4u,
+} smartcard_transfer_state_t;
+
+/*! @brief Defines Smart card reset types */
+typedef enum _smartcard_reset_type
+{
+ kSMARTCARD_ColdReset = 0x0u,
+ kSMARTCARD_WarmReset = 0x1u,
+ kSMARTCARD_NoColdReset = 0x2u,
+ kSMARTCARD_NoWarmReset = 0x3u,
+} smartcard_reset_type_t;
+
+/*! @brief Defines Smart card transport protocol types */
+typedef enum _smartcard_transport_type
+{
+ kSMARTCARD_T0Transport = 0x0u,
+ kSMARTCARD_T1Transport = 0x1u
+} smartcard_transport_type_t;
+
+/*! @brief Defines Smart card data parity types */
+typedef enum _smartcard_parity_type
+{
+ kSMARTCARD_EvenParity = 0x0u,
+ kSMARTCARD_OddParity = 0x1u
+} smartcard_parity_type_t;
+
+/*! @brief Defines data Convention format */
+typedef enum _smartcard_card_convention
+{
+ kSMARTCARD_DirectConvention = 0x0u,
+ kSMARTCARD_InverseConvention = 0x1u
+} smartcard_card_convention_t;
+
+/*! @brief Defines Smart card interface IC control types */
+typedef enum _smartcard_interface_control
+{
+ kSMARTCARD_InterfaceSetVcc = 0x00u,
+ kSMARTCARD_InterfaceSetClockToResetDelay = 0x01u,
+ kSMARTCARD_InterfaceReadStatus = 0x02u
+} smartcard_interface_control_t;
+
+/*! @brief Defines transfer direction.*/
+typedef enum _smartcard_direction
+{
+ kSMARTCARD_Receive = 0u,
+ kSMARTCARD_Transmit = 1u
+} smartcard_direction_t;
+
+/*! @brief Smart card interface interrupt callback function type */
+typedef void (*smartcard_interface_callback_t)(void *smartcardContext, void *param);
+/*! @brief Smart card transfer interrupt callback function type */
+typedef void (*smartcard_transfer_callback_t)(void *smartcardContext, void *param);
+
+/*! @brief Time Delay function used to passive waiting using RTOS [us] */
+typedef void (*smartcard_time_delay_t)(uint32_t us);
+
+/*! @brief Defines card-specific parameters for Smart card driver */
+typedef struct _smartcard_card_params
+{
+ /* ISO7816/EMV4.3 specification variables */
+ uint16_t Fi; /*!< 4 bits Fi - clock rate conversion integer */
+ uint8_t fMax; /*!< Maximum Smart card frequency in MHz */
+ uint8_t WI; /*!< 8 bits WI - work wait time integer */
+ uint8_t Di; /*!< 4 bits DI - baud rate divisor */
+ uint8_t BWI; /*!< 4 bits BWI - block wait time integer */
+ uint8_t CWI; /*!< 4 bits CWI - character wait time integer */
+ uint8_t BGI; /*!< 4 bits BGI - block guard time integer */
+ uint8_t GTN; /*!< 8 bits GTN - extended guard time integer */
+ uint8_t IFSC; /*!< Indicates IFSC value of the card */
+ uint8_t modeNegotiable; /*!< Indicates if the card acts in negotiable or a specific mode. */
+ uint8_t currentD; /*!< 4 bits DI - current baud rate divisor*/
+ /* Driver-specific variables */
+ uint8_t status; /*!< Indicates smart card status */
+ bool t0Indicated; /*!< Indicates ff T=0 indicated in TD1 byte */
+ bool t1Indicated; /*!< Indicates if T=1 indicated in TD2 byte */
+ bool atrComplete; /*!< Indicates whether the ATR received from the card was complete or not */
+ bool atrValid; /*!< Indicates whether the ATR received from the card was valid or not */
+ bool present; /*!< Indicates if a smart card is present */
+ bool active; /*!< Indicates if the smart card is activated */
+ bool faulty; /*!< Indicates whether smart card/interface is faulty */
+ smartcard_card_convention_t convention; /*!< Card convention, kSMARTCARD_DirectConvention for direct convention,
+ kSMARTCARD_InverseConvention for inverse convention */
+} smartcard_card_params_t;
+
+/*! @brief Smart card defines the state of the EMV timers in the Smart card driver */
+typedef struct _smartcard_timers_state
+{
+ volatile bool adtExpired; /*!< Indicates whether ADT timer expired */
+ volatile bool wwtExpired; /*!< Indicates whether WWT timer expired */
+ volatile bool cwtExpired; /*!< Indicates whether CWT timer expired */
+ volatile bool bwtExpired; /*!< Indicates whether BWT timer expired */
+ volatile bool initCharTimerExpired; /*!< Indicates whether reception timer
+ for initialization character (TS) after the RST has expired */
+} smartcard_timers_state_t;
+
+/*! @brief Defines user specified configuration of Smart card interface */
+typedef struct _smartcard_interface_config
+{
+ uint32_t smartCardClock; /*!< Smart card interface clock [Hz] */
+ uint32_t clockToResetDelay; /*!< Indicates clock to RST apply delay [smart card clock cycles] */
+ uint8_t clockModule; /*!< Smart card clock module number */
+ uint8_t clockModuleChannel; /*!< Smart card clock module channel number */
+ uint8_t clockModuleSourceClock; /*!< Smart card clock module source clock [e.g., BusClk] */
+ smartcard_card_voltage_class_t vcc; /*!< Smart card voltage class */
+ uint8_t controlPort; /*!< Smart card PHY control port instance */
+ uint8_t controlPin; /*!< Smart card PHY control pin instance */
+ uint8_t irqPort; /*!< Smart card PHY Interrupt port instance */
+ uint8_t irqPin; /*!< Smart card PHY Interrupt pin instance */
+ uint8_t resetPort; /*!< Smart card reset port instance */
+ uint8_t resetPin; /*!< Smart card reset pin instance */
+ uint8_t vsel0Port; /*!< Smart card PHY Vsel0 control port instance */
+ uint8_t vsel0Pin; /*!< Smart card PHY Vsel0 control pin instance */
+ uint8_t vsel1Port; /*!< Smart card PHY Vsel1 control port instance */
+ uint8_t vsel1Pin; /*!< Smart card PHY Vsel1 control pin instance */
+ uint8_t dataPort; /*!< Smart card PHY data port instance */
+ uint8_t dataPin; /*!< Smart card PHY data pin instance */
+ uint8_t dataPinMux; /*!< Smart card PHY data pin mux option */
+ uint8_t tsTimerId; /*!< Numerical identifier of the External HW timer for Initial character detection */
+} smartcard_interface_config_t;
+
+/*! @brief Defines user transfer structure used to initialize transfer */
+typedef struct _smartcard_xfer
+{
+ smartcard_direction_t direction; /*!< Direction of communication. (RX/TX) */
+ uint8_t *buff; /*!< The buffer of data. */
+ size_t size; /*!< The number of transferred units. */
+} smartcard_xfer_t;
+
+/*!
+ * @brief Runtime state of the Smart card driver.
+ */
+typedef struct _smartcard_context
+{
+ /* Xfer part */
+ void *base; /*!< Smart card module base address */
+ smartcard_direction_t direction; /*!< Direction of communication. (RX/TX) */
+ uint8_t *xBuff; /*!< The buffer of data being transferred.*/
+ volatile size_t xSize; /*!< The number of bytes to be transferred. */
+ volatile bool xIsBusy; /*!< True if there is an active transfer. */
+ uint8_t txFifoEntryCount; /*!< Number of data word entries in transmit FIFO. */
+ uint8_t rxFifoThreshold; /*!< The max value of the receiver FIFO threshold. */
+ /* Smart card Interface part */
+ smartcard_interface_callback_t interfaceCallback; /*!< Callback to invoke after interface IC raised interrupt.*/
+ smartcard_transfer_callback_t transferCallback; /*!< Callback to invoke after transfer event occur.*/
+ void *interfaceCallbackParam; /*!< Interface callback parameter pointer.*/
+ void *transferCallbackParam; /*!< Transfer callback parameter pointer.*/
+ smartcard_time_delay_t timeDelay; /*!< Function which handles time delay defined by user or RTOS. */
+ smartcard_reset_type_t resetType; /*!< Indicates whether a Cold reset or Warm reset was requested. */
+ smartcard_transport_type_t tType; /*!< Indicates current transfer protocol (T0 or T1) */
+ /* Smart card State part */
+ volatile smartcard_transfer_state_t transferState; /*!< Indicates the current transfer state */
+ smartcard_timers_state_t timersState; /*!< Indicates the state of different protocol timers used in driver */
+ smartcard_card_params_t
+ cardParams; /*!< Smart card parameters(ATR and current) and interface slots states(ATR and current) */
+ uint8_t IFSD; /*!< Indicates the terminal IFSD */
+ smartcard_parity_type_t parity; /*!< Indicates current parity even/odd */
+ volatile bool rxtCrossed; /*!< Indicates whether RXT thresholds has been crossed */
+ volatile bool txtCrossed; /*!< Indicates whether TXT thresholds has been crossed */
+ volatile bool wtxRequested; /*!< Indicates whether WTX has been requested or not*/
+ volatile bool parityError; /*!< Indicates whether a parity error has been detected */
+ uint8_t statusBytes[2]; /*!< Used to store Status bytes SW1, SW2 of the last executed card command response */
+ /* Configuration part */
+ smartcard_interface_config_t interfaceConfig; /*!< Smart card interface configuration structure */
+ bool abortTransfer; /*!< Used to abort transfer. */
+} smartcard_context_t;
+
+/*! @}*/
+#endif /* _FSL_SMARTCARD_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c
new file mode 100644
index 0000000000..61bca20b49
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_smartcard_emvsim.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.smartcard_emvsim"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to emvsim bases for each instance. */
+static EMVSIM_Type *const s_emvsimBases[] = EMVSIM_BASE_PTRS;
+
+/*! @brief Pointers to emvsim IRQ number for each instance. */
+static const IRQn_Type s_emvsimIRQ[] = EMVSIM_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to emvsim clocks for each instance. */
+static const clock_ip_name_t s_emvsimClock[] = EMVSIM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* #define CARDSIM_EXTRADELAY_USED */
+
+/*******************************************************************************
+ * Private Functions
+ ******************************************************************************/
+static void smartcard_emvsim_CompleteSendData(EMVSIM_Type *base, smartcard_context_t *context);
+static void smartcard_emvsim_StartSendData(EMVSIM_Type *base, smartcard_context_t *context);
+static void smartcard_emvsim_CompleteReceiveData(EMVSIM_Type *base, smartcard_context_t *context);
+static void smartcard_emvsim_StartReceiveData(EMVSIM_Type *base, smartcard_context_t *context);
+static void smartcard_emvsim_SetTransferType(EMVSIM_Type *base,
+ smartcard_context_t *context,
+ smartcard_control_t control);
+static uint32_t smartcard_emvsim_GetInstance(EMVSIM_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * @brief Get the UART instance from peripheral base address.
+ *
+ * @param base UART peripheral base address.
+ * @return UART instance.
+ */
+static uint32_t smartcard_emvsim_GetInstance(EMVSIM_Type *base)
+{
+ uint8_t instance = 0;
+ uint32_t emvsimArrayCount = (sizeof(s_emvsimBases) / sizeof(s_emvsimBases[0]));
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < emvsimArrayCount; instance++)
+ {
+ if (s_emvsimBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < emvsimArrayCount);
+
+ return instance;
+}
+/*!
+ * @brief Finish up a transmit by completing the process of sending data and disabling the interrupt.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a SMARTCARD driver context structure.
+ */
+static void smartcard_emvsim_CompleteSendData(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ assert((NULL != context));
+
+ /* Disable ETC and TDT interrupt */
+ base->INT_MASK |= (EMVSIM_INT_MASK_ETC_IM_MASK | EMVSIM_INT_MASK_TDT_IM_MASK);
+
+ /* Disable transmitter */
+ base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK;
+ /* Clear receive status flag */
+ base->RX_STATUS = EMVSIM_RX_STATUS_RX_DATA_MASK;
+ /* Enable Receiver */
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ /* Update the information of the module driver context */
+ context->xIsBusy = false;
+ context->transferState = kSMARTCARD_IdleState;
+ /* Clear txSize to avoid any spurious transmit from ISR */
+ context->xSize = 0u;
+ /* Invoke user call-back */
+ if (NULL != context->transferCallback)
+ {
+ context->transferCallback(context, context->transferCallbackParam);
+ }
+}
+
+/*!
+ * @brief Finish up a receive by completing the process of receiving data and disabling the interrupt.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a SMARTCARD driver context structure.
+ */
+static void smartcard_emvsim_CompleteReceiveData(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ assert((NULL != context));
+
+ /* Disable RDT and RX_DATA interrupt */
+ base->INT_MASK |= (EMVSIM_INT_MASK_RDT_IM_MASK | EMVSIM_INT_MASK_RX_DATA_IM_MASK);
+
+ /* Read data from fifo */
+ while (((base->RX_STATUS & EMVSIM_RX_STATUS_RX_CNT_MASK) != 0u) && ((context->xSize) > 0u))
+ {
+ /* Get data and put into receive buffer */
+ *context->xBuff = (uint8_t)(base->RX_BUF);
+ ++context->xBuff;
+ --context->xSize;
+ }
+
+ /* Update the information of the module driver context */
+ context->xIsBusy = false;
+ /* Invoke user call-back */
+ if (NULL != context->transferCallback)
+ {
+ context->transferCallback(context, context->transferCallbackParam);
+ }
+}
+
+/*!
+ * @brief Initiate (start) a transmit by beginning the process of sending data and enabling the interrupt.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a SMARTCARD driver context structure.
+ */
+static void smartcard_emvsim_StartSendData(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ assert((NULL != context));
+
+ uint32_t delay = 0u;
+ uint32_t control = 0u;
+
+ /* Block guard time */
+ /* 22 etus (16 Receiver Clocks == 1 etu) */
+ delay = 22u * 16u;
+ /* Disable all functionality like protocol timers, NACK generation */
+ control = base->CTRL;
+ base->CTRL = 0u;
+ base->TX_GETU = context->cardParams.GTN;
+ /* Clear Global counter time-out flag */
+ base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK;
+ /* Disable counter interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK;
+ /* Set counter value */
+ base->GPCNT1_VAL = delay;
+ /* Select the clock for GPCNT */
+ base->CLKCFG =
+ (base->CLKCFG & ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK) | EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCRxClock);
+ /* Trigger the counter */
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ /* Wait until counter overflow event occur */
+ while ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT1_TO_MASK) == 0u)
+ {
+ }
+ /* Clear status flag and disable GPCNT1 clock */
+ base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK;
+ base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK;
+ /* Restore Control register */
+ base->CTRL = control & ~(EMVSIM_CTRL_XMT_EN_MASK | EMVSIM_CTRL_RCV_EN_MASK);
+ /* Update transferState */
+ context->transferState = kSMARTCARD_TransmittingState;
+ context->xIsBusy = true;
+
+ /* Flush transmitter */
+ base->CTRL |= EMVSIM_CTRL_FLSH_TX_MASK;
+
+ /* Enable transmitter */
+ base->CTRL |= EMVSIM_CTRL_XMT_EN_MASK;
+
+ /* Set transmitter data threshold value to 0 - TDTF is set when the fifo is empty */
+ base->TX_THD &= ~EMVSIM_TX_THD_TDT_MASK;
+
+ /* Enable TDT interrupt */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_TDT_IM_MASK;
+}
+
+/*!
+ * @brief Initiate (start) a receive by beginning the process of receiving data and enabling the interrupt.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a SMARTCARD driver context structure.
+ */
+static void smartcard_emvsim_StartReceiveData(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ assert((NULL != context));
+
+ /* Initialize the module driver context structure to indicate transfer in progress */
+ context->xIsBusy = true;
+ /* Enable BWT Timer interrupt to occur */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
+ /* Disable transmitter */
+ base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK;
+ /* Enable receiver and switch to receive direction */
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+
+ /* Set rx threshold value - number of bytes that must exist in the Receive FIFO to trigger the receive data
+ * threshold interrupt flag (RDTF).*/
+ if (context->xSize < context->rxFifoThreshold)
+ {
+ uint32_t rx_thd;
+ rx_thd = (base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK);
+ rx_thd |= context->xSize;
+ base->RX_THD = rx_thd;
+ }
+ else
+ {
+ base->RX_THD = ((base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK) | context->rxFifoThreshold);
+ }
+
+ /* Enable RDT interrupt - count of bytes in rx fifo is equal or greater than threshold RX_THD[RDT] */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_RDT_IM_MASK;
+
+ if (context->tType == kSMARTCARD_T1Transport)
+ {
+ /* Enable interrupt when new byte is received - in T=1 is necessary to disable BWT interrupt and enable CWT
+ * interrupt after receiving the first byte */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_RX_DATA_IM_MASK;
+ }
+}
+
+/*!
+ * @brief Sets up the EMVSIM hardware for T=0 or T=1 protocol data exchange and initialize timer values.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a SMARTCARD driver context structure.
+ */
+static void smartcard_emvsim_SetTransferType(EMVSIM_Type *base,
+ smartcard_context_t *context,
+ smartcard_control_t control)
+{
+ assert((NULL != context));
+ assert((control == kSMARTCARD_SetupATRMode) || (control == kSMARTCARD_SetupT0Mode) ||
+ (control == kSMARTCARD_SetupT1Mode));
+
+ uint16_t temp16 = 0u;
+ uint32_t bwiVal = 0u;
+ uint8_t tdt = 0u;
+
+ if (control == kSMARTCARD_SetupATRMode)
+ {
+ /* Disable all functionality at first */
+ base->CTRL &= ~(EMVSIM_CTRL_RCVR_11_MASK | EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK |
+ EMVSIM_CTRL_ANACK_MASK | EMVSIM_CTRL_ONACK_MASK | EMVSIM_CTRL_RCV_EN_MASK);
+ /* Set default values as per EMV specification */
+ context->cardParams.Fi = 372u;
+ context->cardParams.Di = 1u;
+ context->cardParams.currentD = 1u;
+ context->cardParams.WI = 0x0Au;
+ context->cardParams.GTN = 0x00u;
+ /* Set default baudrate/ETU time based on EMV parameters and card clock */
+ base->DIVISOR = (((uint32_t)context->cardParams.Fi / context->cardParams.currentD) & 0x1FFu);
+ /* EMV expectation: WWT = (960 x D x WI) + (D x 480)
+ * EMVSIM formula: BWT_VAL[15:0] = CWT_VAL[15:0] */
+ temp16 = (960u * context->cardParams.currentD * context->cardParams.WI) +
+ (context->cardParams.currentD * 480u) + SMARTCARD_WWT_ADJUSTMENT;
+ base->CWT_VAL = temp16;
+ base->BWT_VAL = temp16;
+ /* Set Extended Guard Timer value
+ * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 12
+ * EMVSIM formula: same as above */
+ base->TX_GETU = context->cardParams.GTN;
+ /* Setting Rx threshold so that an interrupt is generated when a NACK is
+ sent either due to parity error or wrong INIT char*/
+ base->RX_THD = EMVSIM_RX_THD_RDT(1);
+ /* Setting up Tx NACK threshold */
+ tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u);
+ base->TX_THD = (EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD) | EMVSIM_TX_THD_TDT(tdt));
+ /* Clear all pending interrupts */
+ base->RX_STATUS = 0xFFFFFFFFu;
+ /* Enable Tx NACK threshold interrupt to occur */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_TNACK_IM_MASK;
+ /* Set transport type to T=0 in SMARTCARD context structure */
+ context->tType = kSMARTCARD_T0Transport;
+ }
+ else if (control == kSMARTCARD_SetupT0Mode)
+ {
+ /* Disable receiver at first if it's not, Disable T=0 mode counters 1st,
+ * Setup for single wire ISO7816 mode (setup 12 etu mode).
+ * Set transport protocol type to T=0, Disable initial character detection.*/
+ base->CTRL &=
+ ~(EMVSIM_CTRL_RCV_EN_MASK | EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_RCVR_11_MASK |
+ EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK | EMVSIM_CTRL_ICM_MASK);
+ /* EMV expectation: WWT = (960 x D x WI) + (D x 480)
+ * EMVSIM formula: BWT_VAL[15:0] = CWT_VAL[15:0] */
+ temp16 = (960u * context->cardParams.currentD * context->cardParams.WI) +
+ (context->cardParams.currentD * 480u) + SMARTCARD_WWT_ADJUSTMENT;
+ base->CWT_VAL = temp16;
+ base->BWT_VAL = temp16;
+ /* Set Extended Guard Timer value
+ * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 12
+ * EMVSIM formula: same as above for range [0:254]
+ * Fix for EMV. If TX_GETU == 0 in T0 mode, 3 stop bits are inserted. */
+ context->cardParams.GTN = (context->cardParams.GTN == 0xFFu) ? 0x00u : context->cardParams.GTN;
+ base->TX_GETU = context->cardParams.GTN;
+ /* Setting Rx threshold so that an interrupt is generated when a NACK is
+ sent either due to parity error or wrong INIT char */
+ base->RX_THD = (EMVSIM_RX_THD_RNCK_THD(SMARTCARD_EMV_RX_NACK_THRESHOLD) | EMVSIM_RX_THD_RDT(1));
+ /* Setting up Tx NACK threshold */
+ tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u);
+ base->TX_THD = (EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD) | EMVSIM_TX_THD_TDT(tdt));
+ /* Enable Tx NACK threshold interrupt to occur */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_TNACK_IM_MASK;
+ /* Enable T=0 mode counters, Enable NACK on error interrupt and NACK on overflow interrupt */
+ base->CTRL |=
+ (EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_ANACK_MASK | EMVSIM_CTRL_ONACK_MASK);
+ /* Set transport type to T=0 in SMARTCARD context structure */
+ context->tType = kSMARTCARD_T0Transport;
+ }
+ else
+ { /* Disable T=1 mode counters 1st, Disable NACK on error interrupt, Disable NACK on overflow interrupt */
+ base->CTRL &= ~(EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_ANACK_MASK |
+ EMVSIM_CTRL_ONACK_MASK | EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK);
+ /* Calculate and set Block Wait Timer (BWT) value
+ * EMV expectation: BWT = 11 + (2^BWI x 960 x D) + (D x 960) = 11 + (2^BWI + 1) x 960 x D
+ * EMVSIM formula: BWT = Same */
+ bwiVal = 11u + ((((uint32_t)1u << context->cardParams.BWI) + 1u) * 960u * context->cardParams.currentD);
+#ifdef CARDSIM_EXTRADELAY_USED
+ base->BWT_VAL = bwiVal + 100u;
+#else
+ base->BWT_VAL = bwiVal;
+#endif
+ /* Calculate and set Character Wait Timer (CWT) value
+ * EMV expectation: CWT = ((2^CWI + 11) + 4)
+ * EMVSIM formula: CWT = Same */
+ if (context->cardParams.currentD == 1u)
+ {
+#ifdef CARDSIM_EXTRADELAY_USED
+ temp16 = ((uint16_t)1u << context->cardParams.CWI) + 16u;
+#else
+ temp16 = ((uint16_t)1u << context->cardParams.CWI) + 15u;
+#endif
+ }
+ else
+ {
+#ifdef CARDSIM_EXTRADELAY_USED
+ temp16 = ((uint16_t)1u << context->cardParams.CWI) + 20u + SMARTCARD_CWT_ADJUSTMENT;
+#else
+ temp16 = ((uint16_t)1u << context->cardParams.CWI) + 15u + SMARTCARD_CWT_ADJUSTMENT;
+#endif
+ }
+ /* EMV = 15, ISO = 11,
+ * EMV expectation: BGT = 22
+ * EMVSIM formula: BGT = Same */
+ base->CWT_VAL = temp16;
+ context->cardParams.BGI = 22u;
+ base->BGT_VAL = context->cardParams.BGI;
+ /* Set Extended Guard Timer value
+ * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 11
+ * EMVSIM formula: same as above */
+ base->TX_GETU = context->cardParams.GTN;
+ /* Setup for single wire ISO7816 mode,
+ * Set transport protocol type to T=1, Enable T=0 mode counters */
+ base->CTRL |= (EMVSIM_CTRL_RCVR_11_MASK | EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK);
+ /* Setting Rx threshold */
+ base->RX_THD = (EMVSIM_RX_THD_RNCK_THD(SMARTCARD_EMV_RX_NACK_THRESHOLD) | EMVSIM_RX_THD_RDT(1));
+ /* Setting up Tx threshold */
+ tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u);
+ base->TX_THD = (EMVSIM_TX_THD_TDT(tdt) | EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD));
+ /* Set transport type to T=1 in SMARTCARD context structure */
+ context->tType = kSMARTCARD_T1Transport;
+ }
+}
+
+/*!
+ * brief Fills in the smartcard_card_params structure with default values according to the EMV 4.3 specification.
+ *
+ * param cardParams The configuration structure of type smartcard_interface_config_t.
+ * Function fill in members:
+ * Fi = 372;
+ * Di = 1;
+ * currentD = 1;
+ * WI = 0x0A;
+ * GTN = 0x00;
+ * with default values.
+ */
+void SMARTCARD_EMVSIM_GetDefaultConfig(smartcard_card_params_t *cardParams)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(cardParams, 0, sizeof(*cardParams));
+
+ /* EMV default values */
+ cardParams->Fi = 372u;
+ cardParams->Di = 1u;
+ cardParams->currentD = 1u;
+ cardParams->WI = 0x0Au;
+ cardParams->GTN = 0x00u;
+}
+
+/*!
+ * brief Initializes an EMVSIM peripheral for the Smart card/ISO-7816 operation.
+ *
+ * This function un-gates the EMVSIM clock, initializes the module to EMV default settings,
+ * configures the IRQ, enables the module-level interrupt to the core and, initializes the driver context.
+ *
+ * param base The EMVSIM peripheral base address.
+ * param context A pointer to the smart card driver context structure.
+ * param srcClock_Hz Smart card clock generation module source clock.
+ *
+ * return An error code or kStatus_SMARTCARD_Success.
+ */
+status_t SMARTCARD_EMVSIM_Init(EMVSIM_Type *base, smartcard_context_t *context, uint32_t srcClock_Hz)
+{
+ assert((NULL != base));
+
+ if ((NULL == context) || (srcClock_Hz == 0u))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ uint32_t instance = smartcard_emvsim_GetInstance(base);
+/* Set source clock for EMVSIM MCGPLLCLK */
+#if (defined(FSL_FEATURE_SOC_MCG_COUNT) && FSL_FEATURE_SOC_MCG_COUNT)
+ CLOCK_SetEmvsimClock(1u);
+#endif
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable emvsim clock */
+ CLOCK_EnableClock(s_emvsimClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ context->base = base;
+ /* Initialize EMVSIM to a known context. */
+ base->CLKCFG = 0u;
+ base->DIVISOR = 372u;
+ base->CTRL = 0x300u;
+ base->INT_MASK = 0x7FFFu;
+ base->RX_THD = 1u;
+ base->TX_THD = 0u;
+ base->PCSR = 0x1000000u;
+ base->TX_GETU = 0u;
+ base->CWT_VAL = 0xFFFFu;
+ base->BWT_VAL = 0xFFFFFFFFu;
+ base->BGT_VAL = 0u;
+ base->GPCNT0_VAL = 0xFFFFu;
+ base->GPCNT1_VAL = 0xFFFFu;
+ /* Initialize EMVSIM module for SMARTCARD mode of default operation */
+ smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupATRMode);
+ /* Store information about tx fifo depth */
+ context->txFifoEntryCount =
+ (uint8_t)((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT);
+ /* Compute max value of rx fifo threshold */
+ context->rxFifoThreshold =
+ (uint8_t)((base->PARAM & EMVSIM_PARAM_RX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_RX_FIFO_DEPTH_SHIFT);
+ if ((EMVSIM_RX_THD_RDT_MASK >> EMVSIM_RX_THD_RDT_SHIFT) < context->rxFifoThreshold)
+ {
+ context->rxFifoThreshold = (EMVSIM_RX_THD_RDT_MASK >> EMVSIM_RX_THD_RDT_SHIFT);
+ }
+/* Enable EMVSIM interrupt on NVIC level. */
+#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && FSL_FEATURE_SOC_INTMUX_COUNT
+ if ((uint32_t)s_emvsimIRQ[instance] < (uint32_t)FSL_FEATURE_INTMUX_IRQ_START_INDEX)
+ {
+ NVIC_EnableIRQ(s_emvsimIRQ[instance]);
+ }
+#else
+ NVIC_EnableIRQ(s_emvsimIRQ[instance]);
+#endif
+ /* Finally, disable the EMVSIM receiver and transmitter */
+ base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK & ~EMVSIM_CTRL_RCV_EN_MASK;
+
+ return kStatus_SMARTCARD_Success;
+}
+
+/*!
+ * brief This function disables the EMVSIM interrupts, disables the transmitter and receiver,
+ * flushes the FIFOs, and gates EMVSIM clock in SIM.
+ *
+ * param base The EMVSIM module base address.
+ */
+void SMARTCARD_EMVSIM_Deinit(EMVSIM_Type *base)
+{
+ uint32_t instance = 0u;
+ /* In case there is still data in the TX FIFO or shift register that is
+ * being transmitted wait till transmit is complete.
+ * Wait until the data is completely shifted out of shift register */
+ if ((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) != 0u)
+ {
+ while ((base->TX_STATUS & EMVSIM_TX_STATUS_ETCF_MASK) == 0u)
+ {
+ }
+ }
+ instance = smartcard_emvsim_GetInstance(base);
+ /* Disable TX and RX */
+ base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK & ~EMVSIM_CTRL_RCV_EN_MASK;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate EMVSIM module clock */
+ CLOCK_DisableClock(s_emvsimClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/* Disable emvsim interrupt in NVIC */
+#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && FSL_FEATURE_SOC_INTMUX_COUNT
+ if ((uint32_t)s_emvsimIRQ[instance] < (uint32_t)FSL_FEATURE_INTMUX_IRQ_START_INDEX)
+ {
+ NVIC_DisableIRQ(s_emvsimIRQ[instance]);
+ }
+#else
+ NVIC_DisableIRQ(s_emvsimIRQ[instance]);
+#endif
+}
+
+/*!
+ * brief Transfer data using interrupts.
+ *
+ * A non-blocking (also known as asynchronous) function means that the function returns
+ * immediately after initiating the transfer function. The application has to get the
+ * transfer status to see when the transfer is complete. In other words, after calling the non-blocking
+ * (asynchronous) transfer function, the application must get the transfer status to check if the transmit
+ * is completed or not.
+ *
+ * param base The EMVSIM peripheral base address.
+ * param context A pointer to a smart card driver context structure.
+ * param xfer A pointer to the smart card transfer structure where the linked buffers and sizes are stored.
+ *
+ * return An error code or kStatus_SMARTCARD_Success.
+ */
+status_t SMARTCARD_EMVSIM_TransferNonBlocking(EMVSIM_Type *base, smartcard_context_t *context, smartcard_xfer_t *xfer)
+{
+ if ((NULL == context) || (NULL == xfer) || (xfer->buff == NULL))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ /* Check input parameters */
+ if ((0u == xfer->size))
+ {
+ return kStatus_SMARTCARD_Success;
+ }
+ /* Check if some transfer is in progress */
+ if (0 != SMARTCARD_EMVSIM_GetTransferRemainingBytes(base, context))
+ {
+ if (kSMARTCARD_Receive == context->direction)
+ {
+ return kStatus_SMARTCARD_RxBusy;
+ }
+ else
+ {
+ return kStatus_SMARTCARD_TxBusy;
+ }
+ }
+ /* Initialize error check flags */
+ context->rxtCrossed = false;
+ context->txtCrossed = false;
+ context->parityError = false;
+ /* Initialize SMARTCARD context structure to start transfer */
+ context->xBuff = xfer->buff;
+ context->xSize = xfer->size;
+
+ if (kSMARTCARD_Receive == xfer->direction)
+ {
+ context->direction = xfer->direction;
+ context->transferState = kSMARTCARD_ReceivingState;
+ /* Start transfer */
+ smartcard_emvsim_StartReceiveData(base, context);
+ }
+ else if (kSMARTCARD_Transmit == xfer->direction)
+ {
+ context->direction = xfer->direction;
+ context->transferState = kSMARTCARD_TransmittingState;
+ /* Start transfer */
+ smartcard_emvsim_StartSendData(base, context);
+ }
+ else
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ return kStatus_SMARTCARD_Success;
+}
+
+/*!
+ * brief Returns whether the previous EMVSIM transfer has finished.
+ *
+ * When performing an async transfer, call this function to ascertain the context of the
+ * current transfer: in progress (or busy) or complete (success). If the
+ * transfer is still in progress, the user can obtain the number of words that have not been
+ * transferred.
+ *
+ * param base The EMVSIM module base address.
+ * param context A pointer to a smart card driver context structure.
+ *
+ * return The number of bytes not transferred.
+ */
+int32_t SMARTCARD_EMVSIM_GetTransferRemainingBytes(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ if ((NULL == context))
+ {
+ return -1;
+ }
+ if (context->xIsBusy)
+ {
+ if (context->direction == kSMARTCARD_Transmit)
+ {
+ /* Count of bytes in buffer + data in fifo */
+ uint32_t count;
+ count = context->xSize;
+ count += ((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) >> EMVSIM_TX_STATUS_TX_CNT_SHIFT);
+ return (int32_t)count;
+ }
+ return (int32_t)context->xSize;
+ }
+
+ return 0;
+}
+
+/*!
+ * brief Terminates an asynchronous EMVSIM transfer early.
+ *
+ * During an async EMVSIM transfer, the user can terminate the transfer early
+ * if the transfer is still in progress.
+ *
+ * param base The EMVSIM peripheral address.
+ * param context A pointer to a smart card driver context structure.
+ * retval kStatus_SMARTCARD_Success The transmit abort was successful.
+ * retval kStatus_SMARTCARD_NoTransmitInProgress No transmission is currently in progress.
+ */
+status_t SMARTCARD_EMVSIM_AbortTransfer(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ if ((NULL == context))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ context->abortTransfer = true;
+
+ /* Check if a transfer is running. */
+ if ((!context->xIsBusy))
+ {
+ return kStatus_SMARTCARD_NoTransferInProgress;
+ }
+ /* Call transfer complete to abort transfer */
+ if (kSMARTCARD_Receive == context->direction)
+ { /* Stop the running transfer. */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ else if (kSMARTCARD_Transmit == context->direction)
+ { /* Stop the running transfer. */
+ smartcard_emvsim_CompleteSendData(base, context);
+ }
+ else
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ return kStatus_SMARTCARD_Success;
+}
+
+/*!
+ * brief Handles EMVSIM module interrupts.
+ *
+ * param base The EMVSIM peripheral base address.
+ * param context A pointer to a smart card driver context structure.
+ */
+void SMARTCARD_EMVSIM_IRQHandler(EMVSIM_Type *base, smartcard_context_t *context)
+{
+ if (NULL == context)
+ {
+ return;
+ }
+
+ /* Check card insertion/removal interrupt occurs, only EMVSIM DIRECT interface driver using enables this interrupt
+ * to occur */
+ if (((base->PCSR & EMVSIM_PCSR_SPDIM_MASK) == 0u) && ((base->PCSR & EMVSIM_PCSR_SPDIF_MASK) != 0u))
+ {
+ /* Clear card presence interrupt status */
+ base->PCSR |= EMVSIM_PCSR_SPDIF_MASK;
+ /* Set PD signal edge behaviour */
+ if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >>
+ EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnFallingEdge) &&
+ ((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >>
+ EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow))
+ { /* Set rising edge interrupt */
+ base->PCSR |= EMVSIM_PCSR_SPDES_MASK;
+ }
+ if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >>
+ EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnRisingEdge) &&
+ ((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >>
+ EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsHigh))
+ { /* Set falling edge interrupt */
+ base->PCSR &= ~EMVSIM_PCSR_SPDES_MASK;
+ }
+ /* Card presence(insertion)/removal detected */
+ /* Invoke callback if there is one */
+ if (NULL != context->interfaceCallback)
+ {
+ context->interfaceCallback(context, context->interfaceCallbackParam);
+ }
+ return;
+ }
+ /* Check if timer for initial character (TS) detection has expired */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT0_IM_MASK) >> EMVSIM_INT_MASK_GPCNT0_IM_SHIFT == 0u) &&
+ ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT0_TO_MASK) != 0u))
+ {
+ /* Disable TS and ADT timers by clearing source clock to 0 */
+ base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
+ context->timersState.initCharTimerExpired = true;
+ /* Disable and clear GPCNT interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK;
+ base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT0_TO_MASK;
+ /* Down counter trigger, and clear any pending counter status flag */
+ base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK;
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ context->transferState = kSMARTCARD_IdleState;
+ /* Unblock the caller */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ return;
+ }
+ /* Check if timer for ATR duration timer has expired */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT1_IM_MASK) == 0u) &&
+ ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT1_TO_MASK) != 0u))
+ { /* Disable clock counter by clearing source clock to 0 */
+ base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK;
+ /* Disable and clear GPCNT interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK;
+ base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK;
+ context->timersState.adtExpired = true;
+ /* Unblock the caller */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ return;
+ }
+ /*
+ * Check if a parity error was indicated.
+ * A parity error will cause transmission of NACK if ANACK bit is set in
+ * CTRL register and PEF bit will not be asserted. When ANACK is not set,
+ * PEF will be asserted.
+ */
+ if ((base->RX_STATUS & EMVSIM_RX_STATUS_PEF_MASK) != 0u)
+ {
+ context->parityError = true;
+ /* Clear parity error indication */
+ base->RX_STATUS = EMVSIM_RX_STATUS_PEF_MASK;
+ }
+ /* Check if transmit NACK generation threshold was reached */
+ if ((base->TX_STATUS & EMVSIM_TX_STATUS_TNTE_MASK) != 0u)
+ {
+ context->txtCrossed = true;
+ /* Disable transmit NACK threshold interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_TNACK_IM_MASK;
+ /* Clear transmit NACK threshold error flag */
+ base->TX_STATUS = EMVSIM_TX_STATUS_TNTE_MASK;
+ /* Unblock the caller */
+ smartcard_emvsim_CompleteSendData(base, context);
+ return;
+ }
+ /* Check if receive NACK generation threshold was reached */
+ if ((base->RX_STATUS & EMVSIM_RX_STATUS_RTE_MASK) != 0u)
+ {
+ context->rxtCrossed = true;
+ /* Clear receiver NACK threshold interrupt status */
+ base->RX_STATUS = EMVSIM_RX_STATUS_RTE_MASK;
+ if (context->xIsBusy)
+ { /* Unblock the caller */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ }
+ /* Check if a Character Wait Timer expired */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_CWT_ERR_IM_MASK) == 0u) &&
+ ((base->RX_STATUS & EMVSIM_RX_STATUS_CWT_ERR_MASK) != 0u))
+ { /* Disable Character Wait Timer interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK;
+ /* Reset the counter */
+ base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK;
+ /* Clear interrupt status */
+ base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK;
+ /* Enable CWT timer */
+ base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
+ context->transferState = kSMARTCARD_IdleState;
+
+ if (kSMARTCARD_T0Transport == context->tType)
+ { /* Indicate WWT expired */
+ context->timersState.wwtExpired = true;
+ }
+ else
+ { /* Indicate CWT expired */
+ context->timersState.cwtExpired = true;
+ }
+ if (context->xIsBusy)
+ { /* Terminate and unblock any caller */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ }
+ /* Check if a Block Wait Timer expired */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u) &&
+ ((base->RX_STATUS & EMVSIM_RX_STATUS_BWT_ERR_MASK) != 0u))
+ { /* Disable Block Wait Timer interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
+ /* Clear interrupt status flag */
+ base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK;
+ /* Clear error */
+ base->RX_STATUS = EMVSIM_RX_STATUS_BWT_ERR_MASK;
+ /* Enable BWT timer */
+ base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK;
+
+ if (kSMARTCARD_T0Transport == context->tType)
+ { /* Indicate WWT expired */
+ context->timersState.wwtExpired = true;
+ }
+ else
+ { /* Indicate BWT expired */
+ context->timersState.bwtExpired = true;
+ }
+ /* Check if Wait Time Extension(WTX) was requested */
+ if (context->wtxRequested)
+ { /* Reset WTX to default */
+ (void)SMARTCARD_EMVSIM_Control(base, context, kSMARTCARD_ResetWaitTimeMultiplier, 1u);
+ }
+ if (context->xIsBusy)
+ { /* Terminate and unblock any caller */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ }
+
+ /* RX_DATA IRQ */
+ /* Used in T=1 after receive 1st byte - disable BWT and enable CWT interrupt */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_RX_DATA_IM_MASK) == 0u) &&
+ ((base->RX_STATUS & EMVSIM_RX_STATUS_RX_DATA_MASK) != 0u))
+ {
+ if ((context->tType == kSMARTCARD_T1Transport) && (context->xSize > 0u) &&
+ ((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u))
+ {
+ context->timersState.cwtExpired = false;
+ /* Clear CWT error flag */
+ base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK;
+ /* Enable CWT */
+ base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
+ /* Only the 1st byte has been received, now time to disable BWT interrupt and enable CWT interrupt */
+ base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK) | EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
+ }
+ /* Disable interrupt when is received new byte */
+ base->INT_MASK |= EMVSIM_INT_MASK_RX_DATA_IM_MASK;
+ }
+
+ /* RDT IRQ - count of bytes in rx fifo reached the rx threshold value RX_THD[RDT] */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_RDT_IM_MASK) == 0u) &&
+ ((base->RX_STATUS & EMVSIM_RX_STATUS_RDTF_MASK) != 0u))
+ {
+ if (kSMARTCARD_WaitingForTSState == context->transferState)
+ {
+ /* Read byte */
+ (void)(base->RX_BUF);
+
+ if ((base->CTRL & EMVSIM_CTRL_ICM_MASK) != 0u)
+ { /* ICM mode still enabled, this is due to parity error */
+ context->transferState = kSMARTCARD_InvalidTSDetecetedState;
+ }
+ else
+ { /* Received valid TS */
+ context->transferState = kSMARTCARD_ReceivingState;
+ /* Get Data Convention form by reading IC bit of EMVSIM_CTRL register */
+ context->cardParams.convention =
+ (smartcard_card_convention_t)(uint32_t)((base->CTRL & EMVSIM_CTRL_IC_MASK) >> EMVSIM_CTRL_IC_SHIFT);
+ }
+ if (kSMARTCARD_InvalidTSDetecetedState == context->transferState)
+ { /* Stop initial character (TS) detection timer, ADT timer and it's interrupt to occur */
+ base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
+ base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK;
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ if (kSMARTCARD_ReceivingState == context->transferState)
+ { /* Stop initial character (TS) detection timer and disable ATR duration timer to reset it */
+ base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
+ /* Start ATR duration counter (restart GPCNT) */
+ base->CLKCFG |= EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock);
+ /* Start ATR duration counter, Disable counter 0 interrupt and Enable counter 1 interrupt */
+ base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_GPCNT1_IM_MASK) | EMVSIM_INT_MASK_GPCNT0_IM_MASK;
+ /* Complete receive transfer */
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ /* Return anyway */
+ return;
+ }
+
+ while (((base->RX_STATUS & EMVSIM_RX_STATUS_RX_CNT_MASK) != 0u) && ((context->xSize) > 0u))
+ {
+ /* Get data and put into receive buffer */
+ *context->xBuff = (uint8_t)(base->RX_BUF);
+ ++context->xBuff;
+ --context->xSize;
+ }
+
+ /* Check if the last byte was received */
+ if (context->xSize == 0u)
+ {
+ smartcard_emvsim_CompleteReceiveData(base, context);
+ }
+ else
+ {
+ /* If the count of remaining bytes to receive is less than depth of fifo, update the value of the receiver
+ * data threshold */
+ if (context->xSize < context->rxFifoThreshold)
+ {
+ /* Set receiver data threshold value to count of remaining bytes */
+ uint32_t rx_thd;
+ rx_thd = (base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK);
+ rx_thd |= context->xSize;
+ base->RX_THD = rx_thd;
+ }
+ }
+ }
+
+ /* ETC IRQ - all data from fifo is transmitted */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_ETC_IM_MASK) == 0u) &&
+ ((base->TX_STATUS & EMVSIM_TX_STATUS_ETCF_MASK) != 0u))
+ {
+ smartcard_emvsim_CompleteSendData(base, context);
+ }
+
+ /* TDT IRQ - tx fifo is empty */
+ if (((base->INT_MASK & EMVSIM_INT_MASK_TDT_IM_MASK) == 0u) &&
+ ((base->TX_STATUS & EMVSIM_TX_STATUS_TDTF_MASK) != 0u))
+ {
+ if (context->xSize == 0u)
+ {
+ smartcard_emvsim_CompleteSendData(base, context);
+ }
+
+ if (context->xSize == 1u)
+ {
+ /* Disable TDT interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK;
+ /* When the TX_GETU is not zero while sending last byte, the transmitter sends one byte more */
+ base->TX_GETU = 0;
+
+ /* Write data to fifo */
+ base->TX_BUF = *(context->xBuff);
+ ++context->xBuff;
+ --context->xSize;
+
+ /* Last byte was written to fifo - wait for ETC interrupt */
+ /* Clear ETC flag and enable ETC interrupt */
+ base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK;
+ base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK;
+ }
+ else
+ {
+ /* To fifo will be written 2 or more bytes */
+ size_t getu_tail = (size_t)(base->TX_GETU > 0u);
+ while (((context->txFifoEntryCount - (uint8_t)((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) >>
+ EMVSIM_TX_STATUS_TX_CNT_SHIFT)) > 0u) &&
+ (context->xSize > getu_tail))
+ {
+ /* Write data to fifo */
+ base->TX_BUF = *(context->xBuff);
+ ++context->xBuff;
+ --context->xSize;
+ }
+
+ if (context->xSize == 0u)
+ {
+ /* Disable TDT interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK;
+
+ /* Clear ETC flag and enable ETC interrupt */
+ base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK;
+ base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK;
+ }
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+/*!
+ * brief Controls the EMVSIM module per different user request.
+ *
+ * param base The EMVSIM peripheral base address.
+ * param context A pointer to a smart card driver context structure.
+ * param control Control type.
+ * param param Integer value of specific to control command.
+ *
+ * return kStatus_SMARTCARD_Success in success.
+ * return kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_EMVSIM_Control(EMVSIM_Type *base,
+ smartcard_context_t *context,
+ smartcard_control_t control,
+ uint32_t param)
+{
+ if ((NULL == context))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ status_t status = kStatus_SMARTCARD_Success;
+ uint32_t temp32 = 0u;
+
+ switch (control)
+ {
+ case kSMARTCARD_EnableADT:
+ /* Do nothing, ADT counter has been loaded and started after reset
+ * and during starting TS delay counter only. This is because, once
+ * TS counter has been triggered with RCV_EN down-up, we should not
+ * trigger again after TS is received(to avoid missing next character to
+ * TS. Rather, after TS is received, the ATR duration counter should just
+ * be restarted w/o re-triggering the counter. */
+ break;
+ case kSMARTCARD_DisableADT:
+ base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK;
+ /* Stop ADT specific counter and it's interrupt to occur */
+ base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK;
+ base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK;
+ base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK;
+ break;
+ case kSMARTCARD_EnableGTV:
+ /* Enable GTV specific interrupt */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_BGT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_DisableGTV:
+ /* Disable GTV specific interrupt */
+ base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_ResetWWT:
+ /* Reset WWT Timer */
+ base->CTRL &= ~(EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK);
+ base->CTRL |= (EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK);
+ break;
+ case kSMARTCARD_EnableWWT:
+ /* BGT must be masked */
+ base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK;
+ /* Enable WWT Timer interrupt to occur */
+ base->INT_MASK &= (~EMVSIM_INT_MASK_CWT_ERR_IM_MASK & ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK);
+ break;
+ case kSMARTCARD_DisableWWT:
+ /* Disable WWT Timer interrupt to occur */
+ base->INT_MASK |= (EMVSIM_INT_MASK_CWT_ERR_IM_MASK | EMVSIM_INT_MASK_BWT_ERR_IM_MASK);
+ break;
+ case kSMARTCARD_ResetCWT:
+ /* Reset CWT Timer */
+ base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK;
+ base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
+ break;
+ case kSMARTCARD_EnableCWT:
+ base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
+ /* Enable CWT Timer interrupt to occur */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_DisableCWT:
+ /* CWT counter is for receive mode only */
+ base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK;
+ /* Disable CWT Timer interrupt to occur */
+ base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_ResetBWT:
+ /* Reset BWT Timer */
+ base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK;
+ base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK;
+ break;
+ case kSMARTCARD_EnableBWT:
+ base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK;
+ /* Enable BWT Timer interrupt to occur */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_DisableBWT:
+ /* Disable BWT Timer interrupt to occur */
+ base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
+ break;
+ case kSMARTCARD_EnableInitDetect:
+ /* Clear all ISO7816 interrupt flags */
+ base->RX_STATUS = 0xFFFFFFFFu;
+ /* Enable initial character detection : hardware method */
+ context->transferState = kSMARTCARD_WaitingForTSState;
+ /* Enable initial character detection */
+ base->CTRL |= EMVSIM_CTRL_ICM_MASK;
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ break;
+ case kSMARTCARD_EnableAnack:
+ /* Enable NACK-on-error interrupt to occur */
+ base->CTRL |= EMVSIM_CTRL_ANACK_MASK;
+ break;
+ case kSMARTCARD_DisableAnack:
+ /* Disable NACK-on-error interrupt to occur */
+ base->CTRL &= ~EMVSIM_CTRL_ANACK_MASK;
+ break;
+ case kSMARTCARD_ConfigureBaudrate:
+ /* Set default baudrate/ETU time based on EMV parameters and card clock */
+ base->DIVISOR = (((uint32_t)context->cardParams.Fi / context->cardParams.currentD) & 0x1FFu);
+ break;
+ case kSMARTCARD_SetupATRMode:
+ /* Set in default ATR mode */
+ smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupATRMode);
+ break;
+ case kSMARTCARD_SetupT0Mode:
+ /* Set transport protocol type to T=0 */
+ smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupT0Mode);
+ break;
+ case kSMARTCARD_SetupT1Mode:
+ /* Set transport protocol type to T=1 */
+ smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupT1Mode);
+ break;
+ case kSMARTCARD_EnableReceiverMode:
+ /* Enable receiver mode and switch to receive direction */
+ base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ /* Set receiver threshold value to 1 */
+ base->RX_THD = ((base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK) | 1u);
+ /* Enable RDT interrupt */
+ base->INT_MASK &= ~EMVSIM_INT_MASK_RDT_IM_MASK;
+ break;
+ case kSMARTCARD_DisableReceiverMode:
+ /* Disable receiver */
+ base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK;
+ break;
+ case kSMARTCARD_EnableTransmitterMode:
+ /* Enable transmitter mode and switch to transmit direction */
+ base->CTRL |= EMVSIM_CTRL_XMT_EN_MASK;
+ break;
+ case kSMARTCARD_DisableTransmitterMode:
+ /* Disable transmitter */
+ base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK;
+ break;
+ case kSMARTCARD_ResetWaitTimeMultiplier:
+ base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK;
+ /* Reset Wait Timer Multiplier
+ * EMV Formula : WTX x (11 + ((2^BWI + 1) x 960 x D)) */
+ temp32 = ((uint8_t)param) *
+ (11u + ((((uint32_t)1u << context->cardParams.BWI) + 1u) * 960u * context->cardParams.currentD));
+#ifdef CARDSIM_EXTRADELAY_USED
+ temp32 += context->cardParams.currentD * 50;
+#endif
+ base->BWT_VAL = temp32;
+ /* Set flag to SMARTCARD context accordingly */
+ if (param > 1u)
+ {
+ context->wtxRequested = true;
+ }
+ else
+ {
+ context->wtxRequested = false;
+ }
+ base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK;
+ break;
+ default:
+ status = kStatus_SMARTCARD_InvalidInput;
+ break;
+ }
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h
new file mode 100644
index 0000000000..397966bc02
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SMARTCARD_EMVSIM_H_
+#define _FSL_SMARTCARD_EMVSIM_H_
+
+#include "fsl_smartcard.h"
+
+/*!
+ * @addtogroup smartcard_emvsim_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief EMV RX NACK interrupt generation threshold */
+#define SMARTCARD_EMV_RX_NACK_THRESHOLD (5u)
+
+/*! @brief EMV TX NACK interrupt generation threshold */
+#define SMARTCARD_EMV_TX_NACK_THRESHOLD (5u)
+
+/*! @brief Smart card Word Wait Timer adjustment value */
+#define SMARTCARD_WWT_ADJUSTMENT (160u)
+
+/*! @brief Smart card Character Wait Timer adjustment value */
+#define SMARTCARD_CWT_ADJUSTMENT (3u)
+
+/*! @brief General Purpose Counter clock selections */
+typedef enum _emvsim_gpc_clock_select
+{
+ kEMVSIM_GPCClockDisable = 0u, /*!< Disabled */
+ kEMVSIM_GPCCardClock = 1u, /*!< Card clock */
+ kEMVSIM_GPCRxClock = 2u, /*!< Receive clock */
+ kEMVSIM_GPCTxClock = 3u, /*!< Transmit ETU clock */
+} emvsim_gpc_clock_select_t;
+
+/*! @brief EMVSIM card presence detection edge control */
+typedef enum _presence_detect_edge
+{
+ kEMVSIM_DetectOnFallingEdge = 0u, /*!< Presence detected on the falling edge */
+ kEMVSIM_DetectOnRisingEdge = 1u, /*!< Presence detected on the rising edge */
+} emvsim_presence_detect_edge_t;
+
+/*! @brief EMVSIM card presence detection status */
+typedef enum _presence_detect_status
+{
+ kEMVSIM_DetectPinIsLow = 0u, /*!< Presence detected pin is logic low */
+ kEMVSIM_DetectPinIsHigh = 1u, /*!< Presence detected pin is logic high */
+} emvsim_presence_detect_status_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Smart card EMVSIM Driver
+ * @{
+ */
+
+/*!
+ * @brief Fills in the smartcard_card_params structure with default values according to the EMV 4.3 specification.
+ *
+ * @param cardParams The configuration structure of type smartcard_interface_config_t.
+ * Function fill in members:
+ * Fi = 372;
+ * Di = 1;
+ * currentD = 1;
+ * WI = 0x0A;
+ * GTN = 0x00;
+ * with default values.
+ */
+void SMARTCARD_EMVSIM_GetDefaultConfig(smartcard_card_params_t *cardParams);
+
+/*!
+ * @brief Initializes an EMVSIM peripheral for the Smart card/ISO-7816 operation.
+ *
+ * This function un-gates the EMVSIM clock, initializes the module to EMV default settings,
+ * configures the IRQ, enables the module-level interrupt to the core and, initializes the driver context.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to the smart card driver context structure.
+ * @param srcClock_Hz Smart card clock generation module source clock.
+ *
+ * @return An error code or kStatus_SMARTCARD_Success.
+ */
+status_t SMARTCARD_EMVSIM_Init(EMVSIM_Type *base, smartcard_context_t *context, uint32_t srcClock_Hz);
+
+/*!
+ * @brief This function disables the EMVSIM interrupts, disables the transmitter and receiver,
+ * flushes the FIFOs, and gates EMVSIM clock in SIM.
+ *
+ * @param base The EMVSIM module base address.
+ */
+void SMARTCARD_EMVSIM_Deinit(EMVSIM_Type *base);
+
+/*!
+ * @brief Returns whether the previous EMVSIM transfer has finished.
+ *
+ * When performing an async transfer, call this function to ascertain the context of the
+ * current transfer: in progress (or busy) or complete (success). If the
+ * transfer is still in progress, the user can obtain the number of words that have not been
+ * transferred.
+ *
+ * @param base The EMVSIM module base address.
+ * @param context A pointer to a smart card driver context structure.
+ *
+ * @return The number of bytes not transferred.
+ */
+int32_t SMARTCARD_EMVSIM_GetTransferRemainingBytes(EMVSIM_Type *base, smartcard_context_t *context);
+
+/*!
+ * @brief Terminates an asynchronous EMVSIM transfer early.
+ *
+ * During an async EMVSIM transfer, the user can terminate the transfer early
+ * if the transfer is still in progress.
+ *
+ * @param base The EMVSIM peripheral address.
+ * @param context A pointer to a smart card driver context structure.
+ * @retval kStatus_SMARTCARD_Success The transmit abort was successful.
+ * @retval kStatus_SMARTCARD_NoTransmitInProgress No transmission is currently in progress.
+ */
+status_t SMARTCARD_EMVSIM_AbortTransfer(EMVSIM_Type *base, smartcard_context_t *context);
+
+/*!
+ * @brief Transfer data using interrupts.
+ *
+ * A non-blocking (also known as asynchronous) function means that the function returns
+ * immediately after initiating the transfer function. The application has to get the
+ * transfer status to see when the transfer is complete. In other words, after calling the non-blocking
+ * (asynchronous) transfer function, the application must get the transfer status to check if the transmit
+ * is completed or not.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a smart card driver context structure.
+ * @param xfer A pointer to the smart card transfer structure where the linked buffers and sizes are stored.
+ *
+ * @return An error code or kStatus_SMARTCARD_Success.
+ */
+status_t SMARTCARD_EMVSIM_TransferNonBlocking(EMVSIM_Type *base, smartcard_context_t *context, smartcard_xfer_t *xfer);
+
+/*!
+ * @brief Controls the EMVSIM module per different user request.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a smart card driver context structure.
+ * @param control Control type.
+ * @param param Integer value of specific to control command.
+ *
+ * return kStatus_SMARTCARD_Success in success.
+ * return kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_EMVSIM_Control(EMVSIM_Type *base,
+ smartcard_context_t *context,
+ smartcard_control_t control,
+ uint32_t param);
+
+/*!
+ * @brief Handles EMVSIM module interrupts.
+ *
+ * @param base The EMVSIM peripheral base address.
+ * @param context A pointer to a smart card driver context structure.
+ */
+void SMARTCARD_EMVSIM_IRQHandler(EMVSIM_Type *base, smartcard_context_t *context);
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_SMARTCARD_EMVSIM_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h
new file mode 100644
index 0000000000..21408bef76
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SMARTCARD_PHY_H_
+#define _FSL_SMARTCARD_PHY_H_
+
+#include "fsl_smartcard.h"
+
+/*!
+ * @addtogroup smartcard_phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Smart card definition which specifies the adjustment number of clock cycles during which an ATR string has to
+ * be received.
+ */
+#define SMARTCARD_ATR_DURATION_ADJUSTMENT (360u)
+
+/*! @brief Smart card definition which specifies the adjustment number of clock cycles until an initial 'TS' character
+ * has to be
+ * received. */
+#define SMARTCARD_INIT_DELAY_CLOCK_CYCLES_ADJUSTMENT (4200u)
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Fills in the configuration structure with default values.
+ *
+ * @param config The Smart card user configuration structure which contains configuration structure of type
+ * smartcard_interface_config_t.
+ * Function fill in members:
+ * clockToResetDelay = 42000,
+ * vcc = kSmartcardVoltageClassB3_3V,
+ * with default values.
+ */
+void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config);
+
+/*!
+ * @brief Initializes a Smart card interface instance.
+ *
+ * @param base The Smart card peripheral base address.
+ * @param config The user configuration structure of type smartcard_interface_config_t. Call the
+ * function SMARTCARD_PHY_GetDefaultConfig() to fill the configuration structure.
+ * @param srcClock_Hz Smart card clock generation module source clock.
+ *
+ * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_PHY_Init(void *base, smartcard_interface_config_t const *config, uint32_t srcClock_Hz);
+
+/*!
+ * @brief De-initializes a Smart card interface, stops the Smart card clock, and disables the VCC.
+ *
+ * @param base The Smart card peripheral module base address.
+ * @param config The user configuration structure of type smartcard_interface_config_t.
+ */
+void SMARTCARD_PHY_Deinit(void *base, smartcard_interface_config_t const *config);
+
+/*!
+ * @brief Activates the Smart card IC.
+ *
+ * @param base The Smart card peripheral module base address.
+ * @param context A pointer to a Smart card driver context structure.
+ * @param resetType type of reset to be performed, possible values
+ * = kSmartcardColdReset, kSmartcardWarmReset
+ *
+ * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_PHY_Activate(void *base, smartcard_context_t *context, smartcard_reset_type_t resetType);
+
+/*!
+ * @brief De-activates the Smart card IC.
+ *
+ * @param base The Smart card peripheral module base address.
+ * @param context A pointer to a Smart card driver context structure.
+ *
+ * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_PHY_Deactivate(void *base, smartcard_context_t *context);
+
+/*!
+ * @brief Controls the Smart card interface IC.
+ *
+ * @param base The Smart card peripheral module base address.
+ * @param context A pointer to a Smart card driver context structure.
+ * @param control A interface command type.
+ * @param param Integer value specific to control type
+ *
+ * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error.
+ */
+status_t SMARTCARD_PHY_Control(void *base,
+ smartcard_context_t *context,
+ smartcard_interface_control_t control,
+ uint32_t param);
+
+/*!
+ * @brief Smart card interface IC IRQ ISR.
+ *
+ * @param base The Smart card peripheral module base address.
+ * @param context The Smart card context pointer.
+ */
+#if defined(USING_PHY_TDA8035)
+void SMARTCARD_PHY_IRQHandler(void *base, smartcard_context_t *context);
+#endif
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_SMARTCARD_PHY_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c
new file mode 100644
index 0000000000..1be83f8101
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_smartcard_emvsim.h"
+#include "fsl_smartcard_phy.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.smartcard_phy_emvsim"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Private Functions
+ ******************************************************************************/
+static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base,
+ const smartcard_interface_config_t *config,
+ uint32_t srcClock_Hz);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief This function initializes clock module used for card clock generation
+ */
+static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base,
+ const smartcard_interface_config_t *config,
+ uint32_t srcClock_Hz)
+{
+ assert((NULL != config) && (0u != srcClock_Hz));
+
+ uint32_t emvsimClkMhz = 0u;
+ uint8_t emvsimPRSCValue;
+
+ /* Retrieve EMV SIM clock */
+ emvsimClkMhz = srcClock_Hz / 1000000u;
+ /* Calculate MOD value */
+ emvsimPRSCValue = (uint8_t)((emvsimClkMhz * 1000u) / (config->smartCardClock / 1000u));
+ /* Set clock prescaler */
+ base->CLKCFG = (base->CLKCFG & ~EMVSIM_CLKCFG_CLK_PRSC_MASK) | EMVSIM_CLKCFG_CLK_PRSC(emvsimPRSCValue);
+
+ return config->smartCardClock;
+}
+
+void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config)
+{
+ assert((NULL != config));
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->clockToResetDelay = SMARTCARD_INIT_DELAY_CLOCK_CYCLES;
+ config->vcc = kSMARTCARD_VoltageClassB3_3V;
+}
+
+status_t SMARTCARD_PHY_Init(void *base, smartcard_interface_config_t const *config, uint32_t srcClock_Hz)
+{
+ if ((NULL == config) || (0u == srcClock_Hz))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+ EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base;
+
+ /* SMARTCARD clock initialization. Clock is still not active after this call */
+ (void)smartcard_phy_emvsim_InterfaceClockInit(emvsimBase, config, srcClock_Hz);
+
+ /* Configure EMVSIM direct interface driver interrupt occur according card presence */
+ if ((emvsimBase->PCSR & EMVSIM_PCSR_SPDP_MASK) != 0u)
+ {
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDES_MASK;
+ }
+ else
+ {
+ emvsimBase->PCSR |= EMVSIM_PCSR_SPDES_MASK;
+ }
+ /* Un-mask presence detect interrupt flag */
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDIM_MASK;
+
+ return kStatus_SMARTCARD_Success;
+}
+
+void SMARTCARD_PHY_Deinit(void *base, smartcard_interface_config_t const *config)
+{
+ assert((NULL != config));
+ /* Deactivate VCC, CLOCK */
+ ((EMVSIM_Type *)base)->PCSR &= ~(EMVSIM_PCSR_SCEN_MASK | EMVSIM_PCSR_SVCC_EN_MASK);
+}
+
+status_t SMARTCARD_PHY_Activate(void *base, smartcard_context_t *context, smartcard_reset_type_t resetType)
+{
+ if ((NULL == context) || (NULL == context->timeDelay))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+ assert(context->interfaceConfig.vcc == kSMARTCARD_VoltageClassB3_3V);
+
+ EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base;
+
+ context->timersState.initCharTimerExpired = false;
+ context->resetType = resetType;
+
+ /* Disable receiver to deactivate GPC timers trigger */
+ emvsimBase->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK;
+ if (resetType == kSMARTCARD_ColdReset)
+ { /* Set polarity of VCC to active high, Enable VCC for SMARTCARD, Enable smart card clock */
+ emvsimBase->PCSR =
+ (emvsimBase->PCSR & ~EMVSIM_PCSR_VCCENP_MASK) | (EMVSIM_PCSR_SVCC_EN_MASK | EMVSIM_PCSR_SCEN_MASK);
+ /* Set transfer inversion to default(direct) value */
+ emvsimBase->CTRL &= ~EMVSIM_CTRL_IC_MASK;
+ }
+ else if (resetType == kSMARTCARD_WarmReset)
+ { /* Ensure that card is already active */
+ if (!context->cardParams.active)
+ { /* Card is not active;hence return */
+ return kStatus_SMARTCARD_CardNotActivated;
+ }
+ }
+ else
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+ /* Set Reset low */
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK;
+ /* Calculate time delay needed for reset */
+ uint32_t temp =
+ ((((uint32_t)10000u * context->interfaceConfig.clockToResetDelay) / context->interfaceConfig.smartCardClock) *
+ 100u) +
+ 1u;
+ context->timeDelay(temp);
+ /* Pull reset HIGH Now to mark the end of Activation sequence */
+ emvsimBase->PCSR |= EMVSIM_PCSR_SRST_MASK;
+ /* Disable GPC timers input clock */
+ emvsimBase->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
+ /* Down counter trigger, and clear any pending counter status flag */
+ emvsimBase->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK | EMVSIM_TX_STATUS_GPCNT0_TO_MASK;
+ /* Set counter value for TS detection delay */
+ emvsimBase->GPCNT0_VAL = (SMARTCARD_INIT_DELAY_CLOCK_CYCLES + SMARTCARD_INIT_DELAY_CLOCK_CYCLES_ADJUSTMENT);
+ /* Pre-load counter value for ATR duration delay */
+ emvsimBase->GPCNT1_VAL = (SMARTCARD_EMV_ATR_DURATION_ETU + SMARTCARD_ATR_DURATION_ADJUSTMENT);
+ /* Select the clock for GPCNT for both TS detection and early start of ATR duration counter */
+ emvsimBase->CLKCFG |=
+ (EMVSIM_CLKCFG_GPCNT0_CLK_SEL(kEMVSIM_GPCCardClock) | EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock));
+ /* Set receiver to ICM mode, Flush RX FIFO */
+ emvsimBase->CTRL |= (EMVSIM_CTRL_ICM_MASK | EMVSIM_CTRL_FLSH_RX_MASK);
+ /* Enable counter interrupt for TS detection */
+ emvsimBase->INT_MASK &= ~EMVSIM_INT_MASK_GPCNT0_IM_MASK;
+ /* Clear any pending status flags */
+ emvsimBase->RX_STATUS = 0xFFFFFFFFu;
+ /* Enable receiver */
+ emvsimBase->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
+ /* Here the card was activated */
+ context->cardParams.active = true;
+
+ return kStatus_SMARTCARD_Success;
+}
+
+status_t SMARTCARD_PHY_Deactivate(void *base, smartcard_context_t *context)
+{
+ if ((NULL == context))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base;
+
+ /* Assert Reset */
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK;
+ /* Stop SMARTCARD clock generation */
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SCEN_MASK;
+ /* Deactivate card by disabling VCC */
+ emvsimBase->PCSR &= ~EMVSIM_PCSR_SVCC_EN_MASK;
+ /* According EMV 4.3 specification deactivation sequence should be done within 100ms.
+ * The period is measured from the time that RST is set to state L to the time that Vcc
+ * reaches 0.4 V or less.
+ */
+ context->timeDelay(100 * 1000);
+ /* Here the card was deactivated */
+ context->cardParams.active = false;
+
+ return kStatus_SMARTCARD_Success;
+}
+
+status_t SMARTCARD_PHY_Control(void *base,
+ smartcard_context_t *context,
+ smartcard_interface_control_t control,
+ uint32_t param)
+{
+ if ((NULL == context))
+ {
+ return kStatus_SMARTCARD_InvalidInput;
+ }
+
+ status_t status = kStatus_SMARTCARD_Success;
+
+ switch (control)
+ {
+ case kSMARTCARD_InterfaceSetVcc:
+ /* Only 3.3V interface supported by the direct interface */
+ assert((smartcard_card_voltage_class_t)param == kSMARTCARD_VoltageClassB3_3V);
+ context->interfaceConfig.vcc = (smartcard_card_voltage_class_t)param;
+ break;
+ case kSMARTCARD_InterfaceSetClockToResetDelay:
+ /* Set interface clock to Reset delay set by caller */
+ context->interfaceConfig.clockToResetDelay = param;
+ break;
+ case kSMARTCARD_InterfaceReadStatus:
+ /* Expecting active low present detect */
+ context->cardParams.present = (bool)((emvsim_presence_detect_status_t)(uint32_t)(
+ (((EMVSIM_Type *)base)->PCSR & EMVSIM_PCSR_SPDP_MASK) >>
+ EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow);
+ break;
+ default:
+ status = kStatus_SMARTCARD_InvalidInput;
+ break;
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.c b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.c
new file mode 100644
index 0000000000..485ba01b58
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_snvs_hp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.snvs_hp"
+#endif
+
+#define SECONDS_IN_A_DAY (86400U)
+#define SECONDS_IN_A_HOUR (3600U)
+#define SECONDS_IN_A_MINUTE (60U)
+#define DAYS_IN_A_YEAR (365U)
+#define YEAR_RANGE_START (1970U)
+#define YEAR_RANGE_END (2099U)
+
+#if !(defined(SNVS_HPSR_PI_MASK))
+#define SNVS_HPSR_PI_MASK (0x2U)
+#endif
+#if !(defined(SNVS_HPSR_HPTA_MASK))
+#define SNVS_HPSR_HPTA_MASK (0x1U)
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Checks whether the date and time passed in is valid
+ *
+ * @param datetime Pointer to structure where the date and time details are stored
+ *
+ * @return Returns false if the date & time details are out of range; true if in range
+ */
+static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from datetime to seconds
+ *
+ * @param datetime Pointer to datetime structure where the date and time details are stored
+ *
+ * @return The result of the conversion in seconds
+ */
+static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from seconds to a datetime structure
+ *
+ * @param seconds Seconds value that needs to be converted to datetime format
+ * @param datetime Pointer to the datetime structure where the result of the conversion is stored
+ */
+static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Returns RTC time in seconds.
+ *
+ * This function is used internally to get actual RTC time in seconds.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return RTC time in seconds
+ */
+static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+/*!
+ * @brief Get the SNVS instance from peripheral base address.
+ *
+ * @param base SNVS peripheral base address.
+ *
+ * @return SNVS instance.
+ */
+static uint32_t SNVS_HP_GetInstance(SNVS_Type *base);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+/*! @brief Pointer to snvs_hp clock. */
+static const clock_ip_name_t s_snvsHpClock[] = SNVS_HP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Check year, month, hour, minute, seconds */
+ if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
+ (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
+ {
+ /* If not correct then error*/
+ return false;
+ }
+
+ /* Adjust the days in February for a leap year */
+ if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ /* Check the validity of the day */
+ if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Number of days from begin of the non Leap-year*/
+ /* Number of days from begin of the non Leap-year*/
+ uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
+ uint32_t seconds;
+
+ /* Compute number of days from 1970 till given year*/
+ seconds = (((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR);
+ /* Add leap year days */
+ seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
+ /* Add number of days till given month*/
+ seconds += monthDays[datetime->month];
+ /* Add days in given month. We subtract the current day as it is
+ * represented in the hours, minutes and seconds field*/
+ seconds += ((uint32_t)datetime->day - 1U);
+ /* For leap year if month less than or equal to Febraury, decrement day counter*/
+ if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
+ {
+ seconds--;
+ }
+
+ seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
+ (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
+
+ return seconds;
+}
+
+static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t x;
+ uint32_t secondsRemaining, days;
+ uint16_t daysInYear;
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Start with the seconds value that is passed in to be converted to date time format */
+ secondsRemaining = seconds;
+
+ /* Calcuate the number of days, we add 1 for the current day which is represented in the
+ * hours and seconds field
+ */
+ days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
+
+ /* Update seconds left*/
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
+
+ /* Calculate the datetime hour, minute and second fields */
+ datetime->hour = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
+ datetime->minute = (uint8_t)(secondsRemaining / 60U);
+ datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
+
+ /* Calculate year */
+ daysInYear = DAYS_IN_A_YEAR;
+ datetime->year = YEAR_RANGE_START;
+ while (days > daysInYear)
+ {
+ /* Decrease day count by a year and increment year by 1 */
+ days -= daysInYear;
+ datetime->year++;
+
+ /* Adjust the number of days for a leap year */
+ if ((datetime->year & 3U) != 0U)
+ {
+ daysInYear = DAYS_IN_A_YEAR;
+ }
+ else
+ {
+ daysInYear = DAYS_IN_A_YEAR + 1U;
+ }
+ }
+
+ /* Adjust the days in February for a leap year */
+ if (0U == (datetime->year & 3U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ for (x = 1U; x <= 12U; x++)
+ {
+ if (days <= daysPerMonth[x])
+ {
+ datetime->month = (uint8_t)x;
+ break;
+ }
+ else
+ {
+ days -= daysPerMonth[x];
+ }
+ }
+
+ datetime->day = (uint8_t)days;
+}
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+static uint32_t SNVS_HP_GetInstance(SNVS_Type *base)
+{
+ return 0U;
+}
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*!
+ * brief Initialize the SNVS.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_Init(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitialize the SNVS.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_Deinit(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config)
+{
+ assert(config != NULL);
+
+ SNVS_HP_Init(base);
+
+ base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN_MASK;
+
+ base->HPCR = (base->HPCR & ~SNVS_HPCR_PI_FREQ_MASK) | SNVS_HPCR_PI_FREQ(config->periodicInterruptFreq);
+
+ if (config->rtcCalEnable)
+ {
+ base->HPCR = (base->HPCR & ~SNVS_HPCR_HPCALB_VAL_MASK) | SNVS_HPCR_HPCALB_VAL(config->rtcCalValue);
+ base->HPCR |= SNVS_HPCR_HPCALB_EN_MASK;
+ }
+}
+
+/*!
+ * brief Stops the RTC and SRTC timers.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_Deinit(SNVS_Type *base)
+{
+ base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
+
+ SNVS_HP_Deinit(base);
+}
+
+/*!
+ * brief Fills in the SNVS config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->rtccalenable = false;
+ * config->rtccalvalue = 0U;
+ * config->PIFreq = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->rtcCalEnable = false;
+ config->rtcCalValue = 0U;
+ config->periodicInterruptFreq = 0U;
+}
+
+static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base)
+{
+ uint32_t seconds = 0;
+ uint32_t tmp = 0;
+
+ /* Do consecutive reads until value is correct */
+ do
+ {
+ seconds = tmp;
+ tmp = (base->HPRTCMR << 17U);
+ tmp |= (base->HPRTCLR >> 15U);
+ } while (tmp != seconds);
+
+ return seconds;
+}
+
+/*!
+ * brief Sets the SNVS RTC date and time according to the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * return kStatus_Success: Success in setting the time and starting the SNVS RTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t seconds = 0U;
+ uint32_t tmp = base->HPCR;
+
+ /* disable RTC */
+ SNVS_HP_RTC_StopTimer(base);
+
+ /* Return error if the time provided is not valid */
+ if (!(SNVS_HP_CheckDatetimeFormat(datetime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set time in seconds */
+ seconds = SNVS_HP_ConvertDatetimeToSeconds(datetime);
+
+ base->HPRTCMR = (uint32_t)(seconds >> 17U);
+ base->HPRTCLR = (uint32_t)(seconds << 15U);
+
+ /* reenable RTC in case that it was enabled before */
+ if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
+ {
+ SNVS_HP_RTC_StartTimer(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the SNVS RTC time and stores it in the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ SNVS_HP_ConvertSecondsToDatetime(SNVS_HP_RTC_GetSeconds(base), datetime);
+}
+
+/*!
+ * brief Sets the SNVS RTC alarm time.
+ *
+ * The function sets the RTC alarm. It also checks whether the specified alarm time
+ * is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ *
+ * param base SNVS peripheral base address
+ * param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * return kStatus_Success: success in setting the SNVS RTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed
+ */
+status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime)
+{
+ assert(alarmTime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+ uint32_t currSeconds = 0U;
+ uint32_t tmp = base->HPCR;
+
+ /* Return error if the alarm time provided is not valid */
+ if (!(SNVS_HP_CheckDatetimeFormat(alarmTime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ alarmSeconds = SNVS_HP_ConvertDatetimeToSeconds(alarmTime);
+ currSeconds = SNVS_HP_RTC_GetSeconds(base);
+
+ /* Return error if the alarm time has passed */
+ if (alarmSeconds < currSeconds)
+ {
+ return kStatus_Fail;
+ }
+
+ /* disable RTC alarm interrupt */
+ base->HPCR &= ~SNVS_HPCR_HPTA_EN_MASK;
+ while ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
+ {
+ }
+
+ /* Set alarm in seconds*/
+ base->HPTAMR = (uint32_t)(alarmSeconds >> 17U);
+ base->HPTALR = (uint32_t)(alarmSeconds << 15U);
+
+ /* reenable RTC alarm interrupt in case that it was enabled before */
+ base->HPCR = tmp;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Returns the SNVS RTC alarm time.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+
+ /* Get alarm in seconds */
+ alarmSeconds = (base->HPTAMR << 17U);
+ alarmSeconds |= (base->HPTALR >> 15U);
+
+ SNVS_HP_ConvertSecondsToDatetime(alarmSeconds, datetime);
+}
+
+#if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
+/*!
+ * brief The function synchronizes RTC counter value with SRTC.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base)
+{
+ uint32_t tmp = base->HPCR;
+
+ /* disable RTC */
+ SNVS_HP_RTC_StopTimer(base);
+
+ base->HPCR |= SNVS_HPCR_HP_TS_MASK;
+
+ /* reenable RTC in case that it was enabled before */
+ if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
+ {
+ SNVS_HP_RTC_StartTimer(base);
+ }
+}
+#endif /* FSL_FEATURE_SNVS_HAS_SRTC */
+
+/*!
+ * brief Gets the SNVS status flags.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::snvs_status_flags_t
+ */
+uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base)
+{
+ uint32_t flags = 0U;
+
+ if ((base->HPSR & SNVS_HPSR_PI_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_RTC_PeriodicInterruptFlag;
+ }
+
+ if ((base->HPSR & SNVS_HPSR_HPTA_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_RTC_AlarmInterruptFlag;
+ }
+
+ return flags;
+}
+
+/*!
+ * brief Gets the enabled SNVS interrupts.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::snvs_interrupt_enable_t
+ */
+uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base)
+{
+ uint32_t val = 0U;
+
+ if ((base->HPCR & SNVS_HPCR_PI_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_RTC_PeriodicInterrupt;
+ }
+
+ if ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_RTC_AlarmInterrupt;
+ }
+
+ return val;
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_SET_LOCK) && (FSL_FEATURE_SNVS_HAS_SET_LOCK > 0)
+/*!
+ * brief Set SNVS HP Set locks.
+ *
+ * param base SNVS peripheral base address
+ *
+ */
+void SNVS_HP_SetLocks(SNVS_Type *base)
+{
+ uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
+ OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
+
+ if (sec_config == SEC_CONFIG_OPEN)
+ {
+ /* Enable non-secure SW access */
+ base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN(1);
+ }
+
+ /* Set LP Software Reset Disable lock and ZMK Write Soft Lock */
+ base->HPCOMR |= SNVS_HPCOMR_LP_SWR_DIS(1);
+ base->HPLR |= SNVS_HPLR_ZMK_WSL(1);
+}
+#endif /* FSL_FEATURE_SNVS_HAS_SET_LOCK */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.h b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.h
new file mode 100644
index 0000000000..713f16b037
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_hp/fsl_snvs_hp.h
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2022, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SNVS_HP_H_
+#define _FSL_SNVS_HP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup snvs_hp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SNVS_HP_DRIVER_VERSION (MAKE_VERSION(2, 3, 2)) /*!< Version 2.3.2 */
+/*@}*/
+
+/*! @brief List of SNVS interrupts */
+typedef enum _snvs_hp_interrupts
+{
+ kSNVS_RTC_AlarmInterrupt = SNVS_HPCR_HPTA_EN_MASK, /*!< RTC time alarm */
+ kSNVS_RTC_PeriodicInterrupt = SNVS_HPCR_PI_EN_MASK, /*!< RTC periodic interrupt */
+} snvs_hp_interrupts_t;
+
+/*! @brief List of SNVS flags */
+typedef enum _snvs_hp_status_flags
+{
+ kSNVS_RTC_AlarmInterruptFlag = SNVS_HPSR_HPTA_MASK, /*!< RTC time alarm flag */
+ kSNVS_RTC_PeriodicInterruptFlag = SNVS_HPSR_PI_MASK, /*!< RTC periodic interrupt flag */
+ kSNVS_ZMK_ZeroFlag = (int)SNVS_HPSR_ZMK_ZERO_MASK, /*!< The ZMK is zero */
+ kSNVS_OTPMK_ZeroFlag = SNVS_HPSR_OTPMK_ZERO_MASK, /*!< The OTPMK is zero */
+} snvs_hp_status_flags_t;
+
+/* Re-map Security Violation for RT11xx specific violation*/
+#ifndef SNVS_HPSVSR_SV0_MASK
+#define SNVS_HPSVSR_SV0_MASK SNVS_HPSVSR_CAAM_MASK
+#endif
+
+#ifndef SNVS_HPSVSR_SV1_MASK
+#define SNVS_HPSVSR_SV1_MASK SNVS_HPSVSR_JTAGC_MASK
+#endif
+
+#ifndef SNVS_HPSVSR_SV2_MASK
+#define SNVS_HPSVSR_SV2_MASK SNVS_HPSVSR_WDOG2_MASK
+#endif
+
+#ifndef SNVS_HPSVSR_SV4_MASK
+#define SNVS_HPSVSR_SV4_MASK SNVS_HPSVSR_SRC_MASK
+#endif
+
+#ifndef SNVS_HPSVSR_SV5_MASK
+#define SNVS_HPSVSR_SV5_MASK SNVS_HPSVSR_OCOTP_MASK
+#endif
+
+/*! @brief List of SNVS security violation flags */
+typedef enum _snvs_hp_sv_status_flags
+{
+ kSNVS_LP_ViolationFlag = SNVS_HPSVSR_SW_LPSV_MASK, /*!< Low Power section Security Violation */
+ kSNVS_ZMK_EccFailFlag = SNVS_HPSVSR_ZMK_ECC_FAIL_MASK, /*!< Zeroizable Master Key Error Correcting Code Check
+ Failure */
+ kSNVS_LP_SoftwareViolationFlag = SNVS_HPSVSR_SW_LPSV_MASK, /*!< LP Software Security Violation */
+ kSNVS_FatalSoftwareViolationFlag = SNVS_HPSVSR_SW_FSV_MASK, /*!< Software Fatal Security Violation */
+ kSNVS_SoftwareViolationFlag = SNVS_HPSVSR_SW_SV_MASK, /*!< Software Security Violation */
+ kSNVS_Violation0Flag = SNVS_HPSVSR_SV0_MASK, /*!< Security Violation 0 */
+ kSNVS_Violation1Flag = SNVS_HPSVSR_SV1_MASK, /*!< Security Violation 1 */
+ kSNVS_Violation2Flag = SNVS_HPSVSR_SV2_MASK, /*!< Security Violation 2 */
+#if defined(SNVS_HPSVSR_SV3_MASK)
+ kSNVS_Violation3Flag = SNVS_HPSVSR_SV3_MASK, /*!< Security Violation 3 */
+#endif /* SNVS_HPSVSR_SV3_MASK */
+ kSNVS_Violation4Flag = SNVS_HPSVSR_SV4_MASK, /*!< Security Violation 4 */
+ kSNVS_Violation5Flag = SNVS_HPSVSR_SV5_MASK, /*!< Security Violation 5 */
+} snvs_hp_sv_status_flags_t;
+
+/*!
+ * @brief Macro to make security violation flag
+ *
+ * Macro help to make security violation flag kSNVS_Violation0Flag to kSNVS_Violation5Flag,
+ * For example, SNVS_MAKE_HP_SV_FLAG(0) is kSNVS_Violation0Flag.
+ */
+#define SNVS_MAKE_HP_SV_FLAG(x) (1U << (SNVS_HPSVSR_SV0_SHIFT + (x)))
+
+/*! @brief Structure is used to hold the date and time */
+typedef struct _snvs_hp_rtc_datetime
+{
+ uint16_t year; /*!< Range from 1970 to 2099.*/
+ uint8_t month; /*!< Range from 1 to 12.*/
+ uint8_t day; /*!< Range from 1 to 31 (depending on month).*/
+ uint8_t hour; /*!< Range from 0 to 23.*/
+ uint8_t minute; /*!< Range from 0 to 59.*/
+ uint8_t second; /*!< Range from 0 to 59.*/
+} snvs_hp_rtc_datetime_t;
+
+/*!
+ * @brief SNVS config structure
+ *
+ * This structure holds the configuration settings for the SNVS peripheral. To initialize this
+ * structure to reasonable defaults, call the SNVS_GetDefaultConfig() function and pass a
+ * pointer to your config structure instance.
+ *
+ * The config struct can be made const so it resides in flash
+ */
+typedef struct _snvs_hp_rtc_config
+{
+ bool rtcCalEnable; /*!< true: RTC calibration mechanism is enabled;
+ false:No calibration is used */
+ uint32_t rtcCalValue; /*!< Defines signed calibration value for nonsecure RTC;
+ This is a 5-bit 2's complement value, range from -16 to +15 */
+ uint32_t periodicInterruptFreq; /*!< Defines frequency of the periodic interrupt;
+ Range from 0 to 15 */
+} snvs_hp_rtc_config_t;
+
+/*! @brief List of SNVS Security State Machine State */
+typedef enum _snvs_hp_ssm_state
+{
+ kSNVS_SSMInit = 0x00, /*!< Init */
+ kSNVS_SSMHardFail = 0x01, /*!< Hard Fail */
+ kSNVS_SSMSoftFail = 0x03, /*!< Soft Fail */
+ kSNVS_SSMInitInter = 0x08, /*!< Init Intermediate (transition state between Init and Check) */
+ kSNVS_SSMCheck = 0x09, /*!< Check */
+ kSNVS_SSMNonSecure = 0x0B, /*!< Non-Secure */
+ kSNVS_SSMTrusted = 0x0D, /*!< Trusted */
+ kSNVS_SSMSecure = 0x0F, /*!< Secure */
+} snvs_hp_ssm_state_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initialize the SNVS.
+ *
+ * @note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_HP_Init(SNVS_Type *base);
+
+/*!
+ * @brief Deinitialize the SNVS.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_HP_Deinit(SNVS_Type *base);
+
+/*!
+ * @brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * @note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * @param base SNVS peripheral base address
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config);
+
+/*!
+ * @brief Stops the RTC and SRTC timers.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_Deinit(SNVS_Type *base);
+
+/*!
+ * @brief Fills in the SNVS config struct with the default settings.
+ *
+ * The default values are as follows.
+ * @code
+ * config->rtccalenable = false;
+ * config->rtccalvalue = 0U;
+ * config->PIFreq = 0U;
+ * @endcode
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config);
+
+/*! @}*/
+
+/*!
+ * @name Non secure RTC current Time & Alarm
+ * @{
+ */
+
+/*!
+ * @brief Sets the SNVS RTC date and time according to the given time structure.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * @return kStatus_Success: Success in setting the time and starting the SNVS RTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Gets the SNVS RTC time and stores it in the given time structure.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Sets the SNVS RTC alarm time.
+ *
+ * The function sets the RTC alarm. It also checks whether the specified alarm time
+ * is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ *
+ * @param base SNVS peripheral base address
+ * @param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * @return kStatus_Success: success in setting the SNVS RTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed
+ */
+status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime);
+
+/*!
+ * @brief Returns the SNVS RTC alarm time.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime);
+
+#if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
+/*!
+ * @brief The function synchronizes RTC counter value with SRTC.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base);
+#endif /* FSL_FEATURE_SNVS_HAS_SRTC */
+
+/*! @}*/
+
+/*!
+ * @name Interrupt Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration :: _snvs_hp_interrupts_t
+ */
+static inline void SNVS_HP_RTC_EnableInterrupts(SNVS_Type *base, uint32_t mask)
+{
+ base->HPCR |= mask;
+}
+
+/*!
+ * @brief Disables the selected SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The interrupts to disable. This is a logical OR of members of the
+ * enumeration :: _snvs_hp_interrupts_t
+ */
+static inline void SNVS_HP_RTC_DisableInterrupts(SNVS_Type *base, uint32_t mask)
+{
+ base->HPCR &= ~mask;
+}
+
+/*!
+ * @brief Gets the enabled SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration :: _snvs_hp_interrupts_t
+ */
+uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base);
+
+/*! @}*/
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Gets the SNVS status flags.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration :: _snvs_hp_status_flags_t
+ */
+uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base);
+
+/*!
+ * @brief Clears the SNVS status flags.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration :: _snvs_hp_status_flags_t
+ */
+static inline void SNVS_HP_RTC_ClearStatusFlags(SNVS_Type *base, uint32_t mask)
+{
+ base->HPSR |= mask;
+}
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+
+/*!
+ * @brief Starts the SNVS RTC time counter.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_RTC_StartTimer(SNVS_Type *base)
+{
+ base->HPCR |= SNVS_HPCR_RTC_EN_MASK;
+ while (0U == (base->HPCR & SNVS_HPCR_RTC_EN_MASK))
+ {
+ }
+}
+
+/*!
+ * @brief Stops the SNVS RTC time counter.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_RTC_StopTimer(SNVS_Type *base)
+{
+ base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
+ while ((base->HPCR & SNVS_HPCR_RTC_EN_MASK) != 0U)
+ {
+ }
+}
+
+/*! @}*/
+
+/*!
+ * @brief Enable or disable master key selection.
+ *
+ * @param base SNVS peripheral base address
+ * @param enable Pass true to enable, false to disable.
+ */
+static inline void SNVS_HP_EnableMasterKeySelection(SNVS_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->HPCOMR |= SNVS_HPCOMR_MKS_EN_MASK;
+ }
+ else
+ {
+ base->HPCOMR &= (~SNVS_HPCOMR_MKS_EN_MASK);
+ }
+}
+
+/*!
+ * @brief Trigger to program Zeroizable Master Key.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_ProgramZeroizableMasterKey(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_PROG_ZMK_MASK;
+}
+
+/*!
+ * @brief Trigger SSM State Transition
+ *
+ * Trigger state transition of the system security monitor (SSM). It results only
+ * the following transitions of the SSM:
+ * - Check State -> Non-Secure (when Non-Secure Boot and not in Fab Configuration)
+ * - Check State --> Trusted (when Secure Boot or in Fab Configuration )
+ * - Trusted State --> Secure
+ * - Secure State --> Trusted
+ * - Soft Fail --> Non-Secure
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_ChangeSSMState(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_SSM_ST_MASK;
+}
+
+/*!
+ * @brief Trigger Software Fatal Security Violation
+ *
+ * The result SSM state transition is:
+ * - Check State -> Soft Fail
+ * - Non-Secure State -> Soft Fail
+ * - Trusted State -> Soft Fail
+ * - Secure State -> Soft Fail
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_SetSoftwareFatalSecurityViolation(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_SW_FSV_MASK;
+}
+
+/*!
+ * @brief Trigger Software Security Violation
+ *
+ * The result SSM state transition is:
+ * - Check -> Non-Secure
+ * - Trusted -> Soft Fail
+ * - Secure -> Soft Fail
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_SetSoftwareSecurityViolation(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_SW_SV_MASK;
+}
+
+/*!
+ * @brief Get current SSM State
+ *
+ * @param base SNVS peripheral base address
+ * @return Current SSM state
+ */
+static inline snvs_hp_ssm_state_t SNVS_HP_GetSSMState(SNVS_Type *base)
+{
+ return (snvs_hp_ssm_state_t)((uint32_t)((base->HPSR & SNVS_HPSR_SSM_STATE_MASK) >> SNVS_HPSR_SSM_STATE_SHIFT));
+}
+
+/*!
+ * @brief Reset the SNVS LP section.
+ *
+ * Reset the LP section except SRTC and Time alarm.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_ResetLP(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_LP_SWR_MASK;
+}
+
+/*!
+ * @name High Assurance Counter (HAC)
+ * @{
+ */
+
+/*!
+ * @brief Enable or disable the High Assurance Counter (HAC)
+ *
+ * @param base SNVS peripheral base address
+ * @param enable Pass true to enable, false to disable.
+ */
+static inline void SNVS_HP_EnableHighAssuranceCounter(SNVS_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->HPCOMR |= SNVS_HPCOMR_HAC_EN_MASK;
+ }
+ else
+ {
+ base->HPCOMR &= (~SNVS_HPCOMR_HAC_EN_MASK);
+ }
+}
+
+/*!
+ * @brief Start or stop the High Assurance Counter (HAC)
+ *
+ * @param base SNVS peripheral base address
+ * @param start Pass true to start, false to stop.
+ */
+static inline void SNVS_HP_StartHighAssuranceCounter(SNVS_Type *base, bool start)
+{
+ if (start)
+ {
+ base->HPCOMR &= (~SNVS_HPCOMR_HAC_STOP_MASK);
+ }
+ else
+ {
+ base->HPCOMR |= SNVS_HPCOMR_HAC_STOP_MASK;
+ }
+}
+
+/*!
+ * @brief Set the High Assurance Counter (HAC) initialize value.
+ *
+ * @param base SNVS peripheral base address
+ * @param value The initial value to set.
+ */
+static inline void SNVS_HP_SetHighAssuranceCounterInitialValue(SNVS_Type *base, uint32_t value)
+{
+ base->HPHACIVR = value;
+}
+
+/*!
+ * @brief Load the High Assurance Counter (HAC)
+ *
+ * This function loads the HAC initialize value to counter register.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_LoadHighAssuranceCounter(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_HAC_LOAD_MASK;
+}
+
+/*!
+ * @brief Get the current High Assurance Counter (HAC) value
+ *
+ * @param base SNVS peripheral base address
+ * @return HAC currnet value.
+ */
+static inline uint32_t SNVS_HP_GetHighAssuranceCounter(SNVS_Type *base)
+{
+ return base->HPHACR;
+}
+
+/*!
+ * @brief Clear the High Assurance Counter (HAC)
+ *
+ * This function can be called in a functional or soft fail state. When the HAC
+ * is enabled:
+ * - If the HAC is cleared in the soft fail state, the SSM transitions to the
+ * hard fail state immediately;
+ * - If the HAC is cleared in functional state, the SSM will transition to
+ * hard fail immediately after transitioning to soft fail.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_ClearHighAssuranceCounter(SNVS_Type *base)
+{
+ base->HPCOMR |= SNVS_HPCOMR_HAC_CLEAR_MASK;
+}
+
+/*!
+ * @brief Lock the High Assurance Counter (HAC)
+ *
+ * Once locked, the HAC initialize value could not be changed, the HAC enable
+ * status could not be changed. This could only be unlocked by system reset.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_HP_LockHighAssuranceCounter(SNVS_Type *base)
+{
+ base->HPLR |= SNVS_HPLR_HAC_L_MASK;
+}
+
+/*! @}*/
+
+/*!
+ * @brief Get the SNVS HP status flags.
+ *
+ * The flags are returned as the OR'ed value f the
+ * enumeration :: _snvs_hp_status_flags_t.
+ *
+ * @param base SNVS peripheral base address
+ * @return The OR'ed value of status flags.
+ */
+static inline uint32_t SNVS_HP_GetStatusFlags(SNVS_Type *base)
+{
+ return base->HPSR;
+}
+
+/*!
+ * @brief Clear the SNVS HP status flags.
+ *
+ * The flags to clear are passed in as the OR'ed value of the
+ * enumeration :: _snvs_hp_status_flags_t.
+ * Only these flags could be cleared using this API.
+ * - @ref kSNVS_RTC_PeriodicInterruptFlag
+ * - @ref kSNVS_RTC_AlarmInterruptFlag
+ *
+ * @param base SNVS peripheral base address
+ * @param mask OR'ed value of the flags to clear.
+ */
+static inline void SNVS_HP_ClearStatusFlags(SNVS_Type *base, uint32_t mask)
+{
+ base->HPSR = mask;
+}
+
+/*!
+ * @brief Get the SNVS HP security violation status flags.
+ *
+ * The flags are returned as the OR'ed value of the
+ * enumeration :: _snvs_hp_sv_status_flags_t.
+ *
+ * @param base SNVS peripheral base address
+ * @return The OR'ed value of security violation status flags.
+ */
+static inline uint32_t SNVS_HP_GetSecurityViolationStatusFlags(SNVS_Type *base)
+{
+ return base->HPSVSR;
+}
+
+/*!
+ * @brief Clear the SNVS HP security violation status flags.
+ *
+ * The flags to clear are passed in as the OR'ed value of the
+ * enumeration :: _snvs_hp_sv_status_flags_t.
+ * Only these flags could be cleared using this API.
+ *
+ * - @ref kSNVS_ZMK_EccFailFlag
+ * - @ref kSNVS_Violation0Flag
+ * - @ref kSNVS_Violation1Flag
+ * - @ref kSNVS_Violation2Flag
+ * - kSNVS_Violation3Flag
+ * - @ref kSNVS_Violation4Flag
+ * - @ref kSNVS_Violation5Flag
+ *
+ * @param base SNVS peripheral base address
+ * @param mask OR'ed value of the flags to clear.
+ */
+static inline void SNVS_HP_ClearSecurityViolationStatusFlags(SNVS_Type *base, uint32_t mask)
+{
+ base->HPSVSR = mask;
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_SET_LOCK) && (FSL_FEATURE_SNVS_HAS_SET_LOCK > 0)
+/*!
+ * brief Set SNVS HP Set locks.
+ *
+ * param base SNVS peripheral base address
+ *
+ */
+void SNVS_HP_SetLocks(SNVS_Type *base);
+#endif /* FSL_FEATURE_SNVS_HAS_SET_LOCK */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_SNVS_HP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.c b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.c
new file mode 100644
index 0000000000..c9a703eebe
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.c
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2022, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_snvs_lp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.snvs_lp"
+#endif
+
+#define SECONDS_IN_A_DAY (86400U)
+#define SECONDS_IN_A_HOUR (3600U)
+#define SECONDS_IN_A_MINUTE (60U)
+#define DAYS_IN_A_YEAR (365U)
+#define YEAR_RANGE_START (1970U)
+#define YEAR_RANGE_END (2099U)
+
+#define SNVS_DEFAULT_PGD_VALUE (0x41736166U)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Checks whether the date and time passed in is valid
+ *
+ * @param datetime Pointer to structure where the date and time details are stored
+ *
+ * @return Returns false if the date & time details are out of range; true if in range
+ */
+static bool SNVS_LP_CheckDatetimeFormat(const snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from datetime to seconds
+ *
+ * @param datetime Pointer to datetime structure where the date and time details are stored
+ *
+ * @return The result of the conversion in seconds
+ */
+static uint32_t SNVS_LP_ConvertDatetimeToSeconds(const snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from seconds to a datetime structure
+ *
+ * @param seconds Seconds value that needs to be converted to datetime format
+ * @param datetime Pointer to the datetime structure where the result of the conversion is stored
+ */
+static void SNVS_LP_ConvertSecondsToDatetime(uint32_t seconds, snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Returns SRTC time in seconds.
+ *
+ * This function is used internally to get actual SRTC time in seconds.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return SRTC time in seconds
+ */
+static uint32_t SNVS_LP_SRTC_GetSeconds(SNVS_Type *base);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+/*!
+ * @brief Get the SNVS instance from peripheral base address.
+ *
+ * @param base SNVS peripheral base address.
+ *
+ * @return SNVS instance.
+ */
+static uint32_t SNVS_LP_GetInstance(SNVS_Type *base);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+/*! @brief Pointer to snvs_lp clock. */
+const clock_ip_name_t s_snvsLpClock[] = SNVS_LP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SNVS_LP_CheckDatetimeFormat(const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Check year, month, hour, minute, seconds */
+ if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
+ (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
+ {
+ /* If not correct then error*/
+ return false;
+ }
+
+ /* Adjust the days in February for a leap year */
+ if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ /* Check the validity of the day */
+ if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t SNVS_LP_ConvertDatetimeToSeconds(const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Number of days from begin of the non Leap-year*/
+ /* Number of days from begin of the non Leap-year*/
+ uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
+ uint32_t seconds;
+
+ /* Compute number of days from 1970 till given year*/
+ seconds = ((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR;
+ /* Add leap year days */
+ seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
+ /* Add number of days till given month*/
+ seconds += monthDays[datetime->month];
+ /* Add days in given month. We subtract the current day as it is
+ * represented in the hours, minutes and seconds field*/
+ seconds += ((uint32_t)datetime->day - 1U);
+ /* For leap year if month less than or equal to Febraury, decrement day counter*/
+ if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
+ {
+ seconds--;
+ }
+
+ seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
+ (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
+
+ return seconds;
+}
+
+static void SNVS_LP_ConvertSecondsToDatetime(uint32_t seconds, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t x;
+ uint32_t secondsRemaining, days;
+ uint16_t daysInYear;
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Start with the seconds value that is passed in to be converted to date time format */
+ secondsRemaining = seconds;
+
+ /* Calcuate the number of days, we add 1 for the current day which is represented in the
+ * hours and seconds field
+ */
+ days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
+
+ /* Update seconds left*/
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
+
+ /* Calculate the datetime hour, minute and second fields */
+ datetime->hour = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
+ datetime->minute = (uint8_t)(secondsRemaining / 60U);
+ datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
+
+ /* Calculate year */
+ daysInYear = DAYS_IN_A_YEAR;
+ datetime->year = YEAR_RANGE_START;
+ while (days > daysInYear)
+ {
+ /* Decrease day count by a year and increment year by 1 */
+ days -= daysInYear;
+ datetime->year++;
+
+ /* Adjust the number of days for a leap year */
+ if ((datetime->year & 3U) != 0U)
+ {
+ daysInYear = DAYS_IN_A_YEAR;
+ }
+ else
+ {
+ daysInYear = DAYS_IN_A_YEAR + 1U;
+ }
+ }
+
+ /* Adjust the days in February for a leap year */
+ if (0U == (datetime->year & 3U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ for (x = 1U; x <= 12U; x++)
+ {
+ if (days <= daysPerMonth[x])
+ {
+ datetime->month = (uint8_t)x;
+ break;
+ }
+ else
+ {
+ days -= daysPerMonth[x];
+ }
+ }
+
+ datetime->day = (uint8_t)days;
+}
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+static uint32_t SNVS_LP_GetInstance(SNVS_Type *base)
+{
+ return 0U;
+}
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_Init(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Power glitch detector: set the PGD/LVD value and clear the previous status. */
+#if defined(SNVS_LPPGDR_PGD)
+ base->LPPGDR = SNVS_DEFAULT_PGD_VALUE;
+ base->LPSR = SNVS_LPSR_PGD_MASK;
+#elif defined(SNVS_LPLVDR_LVD)
+ base->LPLVDR = SNVS_DEFAULT_PGD_VALUE;
+ base->LPSR = SNVS_LPSR_LVD_MASK;
+#else
+#error "No power/voltage detector register defined"
+#endif
+}
+
+/*!
+ * brief Deinit the SNVS LP section.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_Deinit(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_Init(SNVS_Type *base, const snvs_lp_srtc_config_t *config)
+{
+ assert(config != NULL);
+
+ SNVS_LP_Init(base);
+
+ if (config->srtcCalEnable)
+ {
+ base->LPCR = (base->LPCR & ~SNVS_LPCR_LPCALB_VAL_MASK) | SNVS_LPCR_LPCALB_VAL(config->srtcCalValue);
+ base->LPCR |= SNVS_LPCR_LPCALB_EN_MASK;
+ }
+
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)
+
+ int pin;
+
+ for (pin = (int32_t)kSNVS_ExternalTamper1; pin <= (int32_t)SNVS_LP_MAX_TAMPER; pin++)
+ {
+ SNVS_LP_DisableExternalTamper(SNVS, (snvs_lp_external_tamper_t)pin);
+ SNVS_LP_ClearExternalTamperStatus(SNVS, (snvs_lp_external_tamper_t)pin);
+ }
+#endif /* defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0) */
+}
+
+/*!
+ * brief Stops the SRTC timer.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_SRTC_Deinit(SNVS_Type *base)
+{
+ base->LPCR &= ~SNVS_LPCR_SRTC_ENV_MASK;
+
+ SNVS_LP_Deinit(base);
+}
+
+/*!
+ * brief Fills in the SNVS_LP config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->srtccalenable = false;
+ * config->srtccalvalue = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_GetDefaultConfig(snvs_lp_srtc_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->srtcCalEnable = false;
+ config->srtcCalValue = 0U;
+}
+
+static uint32_t SNVS_LP_SRTC_GetSeconds(SNVS_Type *base)
+{
+ uint32_t seconds = 0;
+ uint32_t tmp = 0;
+
+ /* Do consecutive reads until value is correct */
+ do
+ {
+ seconds = tmp;
+ tmp = (base->LPSRTCMR << 17U);
+ tmp |= (base->LPSRTCLR >> 15U);
+ } while (tmp != seconds);
+
+ return seconds;
+}
+
+/*!
+ * brief Sets the SNVS SRTC date and time according to the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * return kStatus_Success: Success in setting the time and starting the SNVS SRTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_LP_SRTC_SetDatetime(SNVS_Type *base, const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t seconds = 0U;
+ uint32_t tmp = base->LPCR;
+
+ /* disable RTC */
+ SNVS_LP_SRTC_StopTimer(base);
+
+ /* Return error if the time provided is not valid */
+ if (!(SNVS_LP_CheckDatetimeFormat(datetime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set time in seconds */
+ seconds = SNVS_LP_ConvertDatetimeToSeconds(datetime);
+
+ base->LPSRTCMR = (uint32_t)(seconds >> 17U);
+ base->LPSRTCLR = (uint32_t)(seconds << 15U);
+
+ /* reenable SRTC in case that it was enabled before */
+ if ((tmp & SNVS_LPCR_SRTC_ENV_MASK) != 0U)
+ {
+ SNVS_LP_SRTC_StartTimer(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the SNVS SRTC time and stores it in the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetDatetime(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ SNVS_LP_ConvertSecondsToDatetime(SNVS_LP_SRTC_GetSeconds(base), datetime);
+}
+
+/*!
+ * brief Sets the SNVS SRTC alarm time.
+ *
+ * The function sets the SRTC alarm. It also checks whether the specified alarm
+ * time is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ * Please note, that SRTC alarm has limited resolution because only 32 most
+ * significant bits of SRTC counter are compared to SRTC Alarm register.
+ * If the alarm time is beyond SRTC resolution, the function does not set the alarm
+ * and returns an error.
+ *
+ * param base SNVS peripheral base address
+ * param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * return kStatus_Success: success in setting the SNVS SRTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed or is beyond resolution
+ */
+status_t SNVS_LP_SRTC_SetAlarm(SNVS_Type *base, const snvs_lp_srtc_datetime_t *alarmTime)
+{
+ assert(alarmTime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+ uint32_t currSeconds = 0U;
+ uint32_t tmp = base->LPCR;
+
+ /* Return error if the alarm time provided is not valid */
+ if (!(SNVS_LP_CheckDatetimeFormat(alarmTime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ alarmSeconds = SNVS_LP_ConvertDatetimeToSeconds(alarmTime);
+ currSeconds = SNVS_LP_SRTC_GetSeconds(base);
+
+ /* Return error if the alarm time has passed */
+ if (alarmSeconds <= currSeconds)
+ {
+ return kStatus_Fail;
+ }
+
+ /* disable SRTC alarm interrupt */
+ base->LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
+ while ((base->LPCR & SNVS_LPCR_LPTA_EN_MASK) != 0U)
+ {
+ }
+
+ /* Set alarm in seconds*/
+ base->LPTAR = alarmSeconds;
+
+ /* reenable SRTC alarm interrupt in case that it was enabled before */
+ base->LPCR = tmp;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Returns the SNVS SRTC alarm time.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetAlarm(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+
+ /* Get alarm in seconds */
+ alarmSeconds = base->LPTAR;
+
+ SNVS_LP_ConvertSecondsToDatetime(alarmSeconds, datetime);
+}
+
+/*!
+ * brief Gets the SNVS status flags.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::snvs_status_flags_t
+ */
+uint32_t SNVS_LP_SRTC_GetStatusFlags(SNVS_Type *base)
+{
+ uint32_t flags = 0U;
+
+ if ((base->LPSR & SNVS_LPSR_LPTA_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_SRTC_AlarmInterruptFlag;
+ }
+
+ return flags;
+}
+
+/*!
+ * brief Gets the enabled SNVS interrupts.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::snvs_interrupt_enable_t
+ */
+uint32_t SNVS_LP_SRTC_GetEnabledInterrupts(SNVS_Type *base)
+{
+ uint32_t val = 0U;
+
+ if ((base->LPCR & SNVS_LPCR_LPTA_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_SRTC_AlarmInterrupt;
+ }
+
+ return val;
+}
+
+/*!
+ * brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->polarity = 0U;
+ * config->filterenable = 0U;
+ * config->filter = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_PassiveTamperPin_GetDefaultConfig(snvs_lp_passive_tamper_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->polarity = 0U;
+#if defined(FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER) && (FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER > 0)
+ config->filterenable = 0U;
+ config->filter = 0U;
+#endif /* FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER */
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0)
+/*!
+ * brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->clock = kSNVS_ActiveTamper16HZ;
+ * config->seed = 0U;
+ * config->polynomial = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_TamperPinTx_GetDefaultConfig(tamper_active_tx_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->clock = kSNVS_ActiveTamper16HZ;
+ config->seed = 0U;
+ config->polynomial = 0U;
+}
+
+/*!
+ * brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->filterenable = 0U;
+ * config->filter = 0U;
+ * config->tx = kSNVS_ActiveTamper1;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_TamperPinRx_GetDefaultConfig(tamper_active_rx_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->filterenable = 0U;
+ config->filter = 0U;
+ config->activeTamper = kSNVS_ActiveTamper1;
+}
+#endif /* FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS */
+
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)
+
+/*!
+ * brief Enables the specified SNVS external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ * param config Configuration structure of external passive tamper
+ */
+void SNVS_LP_EnablePassiveTamper(SNVS_Type *base, snvs_lp_external_tamper_t pin, snvs_lp_passive_tamper_t config)
+{
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ /* Set polarity */
+ if (config.polarity != 0U)
+ {
+ SNVS->LPTDCR |= SNVS_LPTDCR_ET1P_MASK;
+ }
+ else
+ {
+ SNVS->LPTDCR &= ~SNVS_LPTDCR_ET1P_MASK;
+ }
+#if defined(FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER) && (FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER > 0)
+ /* Enable filter and set it's value, dissable otherwise */
+ if (config.filterenable != 0U)
+ {
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF1_EN_MASK;
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF1(config.filter);
+ }
+ else
+ {
+ SNVS->LPTGFCR &= ~SNVS_LPTGFCR_ETGF1_EN_MASK;
+ }
+#endif /* FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER */
+ /* enable tamper pin */
+ base->LPTDCR |= SNVS_LPTDCR_ET1_EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ /* Set polarity */
+ base->LPTDCR =
+ (base->LPTDCR & ~(SNVS_LPTDCR_ET2P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDCR_ET2P_SHIFT);
+ /* Enable filter and set it's value, dissable otherwise */
+ if (config.filterenable != 0U)
+ {
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF2_EN_MASK;
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF2(config.filter);
+ }
+ else
+ {
+ SNVS->LPTGFCR &= ~SNVS_LPTGFCR_ETGF2_EN_MASK;
+ }
+
+ /* enable tamper pin */
+ SNVS->LPTDCR |= SNVS_LPTDCR_ET2_EN_MASK;
+
+ break;
+ case (kSNVS_ExternalTamper3):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET3P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET3P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF3(config.filter);
+ /* Enable tamper 3 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF3_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET3_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET4P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET4P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF4(config.filter);
+ /* Enable tamper 4 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF4_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET4_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET5P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET5P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF5(config.filter);
+ /* Enable tamper 5 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF5_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET5_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET6P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET6P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF6(config.filter);
+ /* Enable tamper 6 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF6_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET6_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET7P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET7P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF7(config.filter);
+ /* Enable tamper 6 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF7_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET7_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET8P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET8P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF8(config.filter);
+ /* Enable tamper 8 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF8_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET8_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET9P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET9P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF9(config.filter);
+ /* Enable tamper 9 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF9_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET9_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ /* Set polarity */
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(SNVS_LPTDC2R_ET10P_MASK)) | ((uint32_t)config.polarity << SNVS_LPTDC2R_ET10P_SHIFT);
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF10(config.filter);
+ /* Enable tamper 10 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF10_EN(1U);
+ }
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET10_EN_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Disables the specified SNVS external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ */
+void SNVS_LP_DisableExternalTamper(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ base->LPTDCR &= ~SNVS_LPTDCR_ET1_EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ base->LPTDCR &= ~SNVS_LPTDCR_ET2_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper3):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET3_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET4_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET5_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET6_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET7_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET8_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET9_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET10_EN_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Disable all external tamper.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_DisableAllExternalTamper(SNVS_Type *base)
+{
+ for (int pin = (int8_t)kSNVS_ExternalTamper1; pin <= (int8_t)SNVS_LP_MAX_TAMPER; pin++)
+ {
+ SNVS_LP_DisableExternalTamper(SNVS, (snvs_lp_external_tamper_t)pin);
+ }
+}
+
+/*!
+ * brief Returns status of the specified external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ *
+ * return The status flag. This is the enumeration ::snvs_external_tamper_status_t
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_GetExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ snvs_lp_external_tamper_status_t status = kSNVS_TamperNotDetected;
+
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ status = (bool)(base->LPSR & SNVS_LPSR_ET1D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ status = (bool)(base->LPSR & SNVS_LPSR_ET2D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper3):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET3D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper4):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET4D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper5):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET5D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper6):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET6D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper7):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET7D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper8):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET8D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper9):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET9D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper10):
+ status = (bool)(base->LPTDSR & SNVS_LPTDSR_ET10D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ return status;
+}
+
+/*!
+ * brief Clears status of the specified external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ */
+void SNVS_LP_ClearExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ base->LPSR |= SNVS_LPSR_ET1D_MASK;
+
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ base->LPSR |= SNVS_LPSR_ET1D_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ base->LPSR |= SNVS_LPSR_ET2D_MASK;
+ break;
+ case (kSNVS_ExternalTamper3):
+ base->LPTDSR |= SNVS_LPTDSR_ET3D_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ base->LPTDSR |= SNVS_LPTDSR_ET4D_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ base->LPTDSR |= SNVS_LPTDSR_ET5D_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ base->LPTDSR |= SNVS_LPTDSR_ET6D_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ base->LPTDSR |= SNVS_LPTDSR_ET7D_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ base->LPTDSR |= SNVS_LPTDSR_ET8D_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ base->LPTDSR |= SNVS_LPTDSR_ET9D_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ base->LPTDSR |= SNVS_LPTDSR_ET10D_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Clears status of the all external tamper.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_ClearAllExternalTamperStatus(SNVS_Type *base)
+{
+ for (int pin = (int8_t)kSNVS_ExternalTamper1; pin <= (int8_t)SNVS_LP_MAX_TAMPER; pin++)
+ {
+ SNVS_LP_ClearExternalTamperStatus(SNVS, (snvs_lp_external_tamper_t)pin);
+ }
+}
+
+#endif /* (!(defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)) */
+
+#if defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0)
+/*!
+ * brief Enable active tamper tx external pad
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ */
+status_t SNVS_LP_EnableTxActiveTamper(SNVS_Type *base, snvs_lp_active_tx_tamper_t pin, tamper_active_tx_config_t config)
+{
+ status_t status = kStatus_Success;
+
+ switch (pin)
+ {
+ case (kSNVS_ActiveTamper1):
+ {
+ /* Enable active tamper tx external pad */
+ base->LPATCTLR |= SNVS_LPATCTLR_AT1_PAD_EN_MASK;
+ /* Set seed and polynomial */
+ base->LPATCR[0] |= SNVS_LPATCR_Seed(config.seed) | SNVS_LPATCR_Polynomial(config.polynomial);
+ /* Set clock */
+ base->LPATCLKR |= SNVS_LPATCLKR_AT1_CLK_CTL(config.clock);
+ /* Enable active tamper pin */
+ base->LPATCTLR |= SNVS_LPATCTLR_AT1_EN_MASK;
+ break;
+ }
+ case (kSNVS_ActiveTamper2):
+ {
+ base->LPATCTLR |= SNVS_LPATCTLR_AT2_PAD_EN_MASK;
+ base->LPATCR[1] |= SNVS_LPATCR_Seed(config.seed) | SNVS_LPATCR_Polynomial(config.polynomial);
+ base->LPATCLKR |= SNVS_LPATCLKR_AT2_CLK_CTL(config.clock);
+ base->LPATCTLR |= SNVS_LPATCTLR_AT2_EN_MASK;
+ break;
+ }
+ case (kSNVS_ActiveTamper3):
+ {
+ base->LPATCTLR |= SNVS_LPATCTLR_AT3_PAD_EN_MASK;
+ base->LPATCR[2] |= SNVS_LPATCR_Seed(config.seed) | SNVS_LPATCR_Polynomial(config.polynomial);
+ base->LPATCLKR |= SNVS_LPATCLKR_AT3_CLK_CTL(config.clock);
+ base->LPATCTLR |= SNVS_LPATCTLR_AT3_EN_MASK;
+ break;
+ }
+ case (kSNVS_ActiveTamper4):
+ {
+ base->LPATCTLR |= SNVS_LPATCTLR_AT4_PAD_EN_MASK;
+ base->LPATCR[3] |= SNVS_LPATCR_Seed(config.seed) | SNVS_LPATCR_Polynomial(config.polynomial);
+ base->LPATCLKR |= SNVS_LPATCLKR_AT4_CLK_CTL(config.clock);
+ base->LPATCTLR |= SNVS_LPATCTLR_AT4_EN_MASK;
+ break;
+ }
+ case (kSNVS_ActiveTamper5):
+ {
+ base->LPATCTLR |= SNVS_LPATCTLR_AT5_PAD_EN_MASK;
+ base->LPATCR[4] |= SNVS_LPATCR_Seed(config.seed) | SNVS_LPATCR_Polynomial(config.polynomial);
+ base->LPATCLKR |= SNVS_LPATCLKR_AT5_CLK_CTL(config.clock);
+ base->LPATCTLR |= SNVS_LPATCTLR_AT5_EN_MASK;
+ break;
+ }
+ default:
+ status = kStatus_InvalidArgument;
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ return status;
+}
+
+/*!
+ * brief Enable active tamper rx external pad
+ *
+ * param base SNVS peripheral base address
+ * param rx SNVS external RX tamper pin
+ * param config SNVS RX tamper config structure
+ */
+status_t SNVS_LP_EnableRxActiveTamper(SNVS_Type *base, snvs_lp_external_tamper_t rx, tamper_active_rx_config_t config)
+{
+ status_t status = kStatus_Success;
+
+ switch (rx)
+ {
+ case (kSNVS_ExternalTamper1):
+ /* Enable filter and set it's value, dissable otherwise */
+ if (config.filterenable != 0U)
+ {
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF1_EN_MASK;
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF1(config.filter);
+ }
+ else
+ {
+ SNVS->LPTGFCR &= ~SNVS_LPTGFCR_ETGF1_EN_MASK;
+ }
+
+ /* Route TX to external tamper 1 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET1RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDCR |= SNVS_LPTDCR_ET1_EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ /* Enable filter and set it's value, dissable otherwise */
+ if (config.filterenable != 0U)
+ {
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF2_EN_MASK;
+ SNVS->LPTGFCR |= SNVS_LPTGFCR_ETGF2(config.filter);
+ }
+ else
+ {
+ SNVS->LPTGFCR &= ~SNVS_LPTGFCR_ETGF2_EN_MASK;
+ }
+
+ /* Route TX to external tamper 2 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET2RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ SNVS->LPTDCR |= SNVS_LPTDCR_ET2_EN_MASK;
+
+ break;
+ case (kSNVS_ExternalTamper3):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF3(config.filter);
+ /* Enable tamper 3 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF3_EN(1U);
+ }
+
+ /* Route TX to external tamper 3 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET3RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET3_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF4(config.filter);
+ /* Enable tamper 4 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF4_EN(1U);
+ }
+
+ /* Route TX to external tamper 4 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET4RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET4_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF5(config.filter);
+ /* Enable tamper 5 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF5_EN(1U);
+ }
+
+ /* Route TX to external tamper 5 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET5RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET5_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF6(config.filter);
+ /* Enable tamper 6 glitch filter */
+ SNVS->LPTGF1CR |= SNVS_LPTGF1CR_ETGF6_EN(1U);
+ }
+
+ /* Route TX to external tamper 6 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET6RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET6_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF7(config.filter);
+ /* Enable tamper 6 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF7_EN(1U);
+ }
+
+ /* Route TX to external tamper 7 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET7RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET7_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF8(config.filter);
+ /* Enable tamper 8 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF8_EN(1U);
+ }
+
+ /* Route TX to external tamper 8 */
+ base->LPATRC1R = SNVS_LPATRC1R_ET8RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET8_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF9(config.filter);
+ /* Enable tamper 9 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF9_EN(1U);
+ }
+
+ /* Route TX to external tamper 9 */
+ base->LPATRC1R = SNVS_LPATRC2R_ET9RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET9_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ /* Enable filter and set it's value if set */
+ if (config.filterenable != 0U)
+ {
+ /* Set filter value */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF10(config.filter);
+ /* Enable tamper 10 glitch filter */
+ SNVS->LPTGF2CR |= SNVS_LPTGF2CR_ETGF10_EN(1U);
+ }
+
+ /* Route TX to external tamper 10 */
+ base->LPATRC1R = SNVS_LPATRC2R_ET10RCTL(config.activeTamper);
+
+ /* enable tamper pin */
+ base->LPTDC2R |= SNVS_LPTDC2R_ET10_EN_MASK;
+ break;
+#endif
+ default:
+ status = kStatus_InvalidArgument;
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Sets voltage tamper detect
+ *
+ * param base SNVS peripheral base address
+ * param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetVoltageTamper(SNVS_Type *base, bool enable)
+{
+ base->LPTDCR |= SNVS_LPTDCR_VT_EN(enable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets temperature tamper detect
+ *
+ * param base SNVS peripheral base address
+ * param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetTemperatureTamper(SNVS_Type *base, bool enable)
+{
+ SNVS->LPTDCR |= SNVS_LPTDCR_TT_EN(enable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets clock tamper detect
+ *
+ * param base SNVS peripheral base address
+ * param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetClockTamper(SNVS_Type *base, bool enable)
+{
+ SNVS->LPTDCR |= SNVS_LPTDCR_CT_EN(enable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Check voltage tamper
+ *
+ * param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckVoltageTamper(SNVS_Type *base)
+{
+ return ((SNVS->LPSR & SNVS_LPSR_VTD_MASK) != 0U) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+}
+
+/*!
+ * brief Check temperature tamper
+ *
+ * param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckTemperatureTamper(SNVS_Type *base)
+{
+ return ((SNVS->LPSR & SNVS_LPSR_TTD_MASK) != 0U) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+}
+
+/*!
+ * brief Check clock tamper
+ *
+ * param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckClockTamper(SNVS_Type *base)
+{
+ return ((SNVS->LPSR & SNVS_LPSR_CTD_MASK) != 0U) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+}
+#endif /* defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0) */
+
+/*!
+ * brief Get the current Monotonic Counter.
+ *
+ * param base SNVS peripheral base address
+ * return Current Monotonic Counter value.
+ */
+uint64_t SNVS_LP_GetMonotonicCounter(SNVS_Type *base)
+{
+ uint32_t mc_lsb, mc_msb;
+
+ mc_msb = base->LPSMCMR;
+ mc_lsb = base->LPSMCLR;
+
+ return ((uint64_t)mc_msb << 32UL) | (uint64_t)mc_lsb;
+}
+
+/*!
+ * brief Write Zeroizable Master Key (ZMK) to the SNVS registers.
+ *
+ * param base SNVS peripheral base address
+ * param ZMKey The ZMK write to the SNVS register.
+ */
+void SNVS_LP_WriteZeroizableMasterKey(SNVS_Type *base, uint32_t ZMKey[SNVS_ZMK_REG_COUNT])
+{
+ uint8_t i = 0;
+
+ for (i = 0; i < SNVS_ZMK_REG_COUNT; i++)
+ {
+ base->LPZMKR[i] = ZMKey[i];
+ }
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_STATE_TRANSITION) && (FSL_FEATURE_SNVS_HAS_STATE_TRANSITION > 0)
+/*!
+ * brief Transition SNVS SSM state to Trusted/Non-secure from Check state
+ *
+ * param base SNVS peripheral base address
+ *
+ * return kStatus_Success: Success in transitioning SSM State
+ * kStatus_Fail: SSM State transition failed
+ */
+status_t SNVS_LP_SSM_State_Transition(SNVS_Type *base)
+{
+ uint32_t curr_ssm_state = ((base->HPSR & SNVS_HPSR_SSM_STATE_MASK) >> SNVS_HPSR_SSM_STATE_SHIFT);
+ uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
+ OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
+
+ /* Check if SSM State is Check state */
+ if (curr_ssm_state == SNVS_SSM_STATE_CHECK)
+ {
+ if (sec_config == SEC_CONFIG_OPEN)
+ {
+ /* Transition to Non-secure state */
+ base->HPCOMR |= SNVS_HPCOMR_SW_SV(1);
+ }
+ else
+ {
+ /* Transition to Trusted state */
+ base->HPCOMR |= SNVS_HPCOMR_SSM_ST(1);
+ }
+ }
+
+ uint32_t new_ssm_state = ((base->HPSR & SNVS_HPSR_SSM_STATE_MASK) >> SNVS_HPSR_SSM_STATE_SHIFT);
+
+ if (new_ssm_state != SNVS_SSM_STATE_CHECK)
+ {
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+}
+#endif /* FSL_FEATURE_SNVS_HAS_STATE_TRANSITION */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.h b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.h
new file mode 100644
index 0000000000..44b9aa02d6
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/snvs_lp/fsl_snvs_lp.h
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2022, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SNVS_LP_H_
+#define _FSL_SNVS_LP_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup snvs_lp
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SNVS_LP_DRIVER_VERSION (MAKE_VERSION(2, 4, 4)) /*!< Version 2.4.4 */
+/*@}*/
+
+/*! @brief Define of SNVS_LP Zeroizable Master Key registers */
+#define SNVS_ZMK_REG_COUNT 8U /* 8 Zeroizable Master Key registers. */
+
+/*! @brief List of SNVS_LP interrupts */
+typedef enum _snvs_lp_srtc_interrupts
+{
+ kSNVS_SRTC_AlarmInterrupt = SNVS_LPCR_LPTA_EN_MASK, /*!< SRTC time alarm.*/
+} snvs_lp_srtc_interrupts_t;
+
+/*! @brief List of SNVS_LP flags */
+typedef enum _snvs_lp_srtc_status_flags
+{
+ kSNVS_SRTC_AlarmInterruptFlag = SNVS_LPSR_LPTA_MASK, /*!< SRTC time alarm flag */
+} snvs_lp_srtc_status_flags_t;
+
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)
+
+/*! @brief List of SNVS_LP external tampers */
+typedef enum _snvs_lp_external_tamper
+{
+ kSNVS_ExternalTamper1 = 1U,
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ kSNVS_ExternalTamper2 = 2U,
+ kSNVS_ExternalTamper3 = 3U,
+ kSNVS_ExternalTamper4 = 4U,
+ kSNVS_ExternalTamper5 = 5U,
+ kSNVS_ExternalTamper6 = 6U,
+ kSNVS_ExternalTamper7 = 7U,
+ kSNVS_ExternalTamper8 = 8U,
+ kSNVS_ExternalTamper9 = 9U,
+ kSNVS_ExternalTamper10 = 10U
+#endif /* defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1) */
+} snvs_lp_external_tamper_t;
+
+#endif /* defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0) */
+
+#if defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0)
+/*! @brief List of SNVS_LP active tampers */
+typedef enum _snvs_lp_active_tamper
+{
+ kSNVS_ActiveTamper1 = 1U,
+ kSNVS_ActiveTamper2 = 2U,
+ kSNVS_ActiveTamper3 = 3U,
+ kSNVS_ActiveTamper4 = 4U,
+ kSNVS_ActiveTamper5 = 5U,
+} snvs_lp_active_tx_tamper_t;
+
+/*! @brief List of SNVS_LP external tampers */
+typedef enum _snvs_lp_active_clock
+{
+ kSNVS_ActiveTamper16HZ = 0U,
+ kSNVS_ActiveTamper8HZ = 1U,
+ kSNVS_ActiveTamper4HZ = 2U,
+ kSNVS_ActiveTamper2HZ = 3U
+} snvs_lp_active_clock_t;
+
+/*! @brief Structure is used to configure SNVS LP active TX tamper pins */
+typedef struct
+{
+ uint16_t polynomial;
+ uint16_t seed;
+ snvs_lp_active_clock_t clock;
+} tamper_active_tx_config_t;
+
+/*! @brief Structure is used to configure SNVS LP active RX tamper pins */
+typedef struct
+{
+ uint16_t filterenable;
+ uint8_t filter;
+ snvs_lp_active_tx_tamper_t activeTamper;
+} tamper_active_rx_config_t;
+
+#endif /* FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS */
+
+/*! @brief Structure is used to configure SNVS LP passive tamper pins */
+typedef struct
+{
+ uint8_t polarity;
+#if defined(FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER) && (FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER > 0)
+ uint8_t filterenable;
+ uint8_t filter;
+#endif /* FSL_FEATURE_SNVS_PASSIVE_TAMPER_FILTER */
+} snvs_lp_passive_tamper_t;
+
+/* define max possible tamper present */
+/*! @brief Define of SNVS_LP Max possible tamper */
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+#define SNVS_LP_MAX_TAMPER kSNVS_ExternalTamper10
+#else
+#define SNVS_LP_MAX_TAMPER kSNVS_ExternalTamper1
+#endif
+
+/*! @brief List of SNVS_LP external tampers status */
+typedef enum _snvs_lp_external_tamper_status
+{
+ kSNVS_TamperNotDetected = 0U,
+ kSNVS_TamperDetected = 1U
+} snvs_lp_external_tamper_status_t;
+
+/*! @brief SNVS_LP external tamper polarity */
+typedef enum _snvs_lp_external_tamper_polarity
+{
+ kSNVS_ExternalTamperActiveLow = 0U,
+ kSNVS_ExternalTamperActiveHigh = 1U
+} snvs_lp_external_tamper_polarity_t;
+
+/*! @brief Structure is used to hold the date and time */
+typedef struct _snvs_lp_srtc_datetime
+{
+ uint16_t year; /*!< Range from 1970 to 2099.*/
+ uint8_t month; /*!< Range from 1 to 12.*/
+ uint8_t day; /*!< Range from 1 to 31 (depending on month).*/
+ uint8_t hour; /*!< Range from 0 to 23.*/
+ uint8_t minute; /*!< Range from 0 to 59.*/
+ uint8_t second; /*!< Range from 0 to 59.*/
+} snvs_lp_srtc_datetime_t;
+
+/*!
+ * @brief SNVS_LP config structure
+ *
+ * This structure holds the configuration settings for the SNVS_LP peripheral. To initialize this
+ * structure to reasonable defaults, call the SNVS_LP_GetDefaultConfig() function and pass a
+ * pointer to your config structure instance.
+ *
+ * The config struct can be made const so it resides in flash
+ */
+typedef struct _snvs_lp_srtc_config
+{
+ bool srtcCalEnable; /*!< true: SRTC calibration mechanism is enabled;
+ false: No calibration is used */
+ uint32_t srtcCalValue; /*!< Defines signed calibration value for SRTC;
+ This is a 5-bit 2's complement value, range from -16 to +15 */
+} snvs_lp_srtc_config_t;
+
+/*!
+ * @brief SNVS_LP Zeroizable Master Key programming mode.
+ */
+typedef enum _snvs_lp_zmk_program_mode
+{
+ kSNVS_ZMKSoftwareProgram, /*!< Software programming mode. */
+ kSNVS_ZMKHardwareProgram, /*!< Hardware programming mode. */
+} snvs_lp_zmk_program_mode_t;
+
+/*!
+ * @brief SNVS_LP Master Key mode.
+ */
+typedef enum _snvs_lp_master_key_mode
+{
+ kSNVS_OTPMK = 0, /*!< One Time Programmable Master Key. */
+ kSNVS_ZMK = 2, /*!< Zeroizable Master Key. */
+ kSNVS_CMK = 3, /*!< Combined Master Key, it is XOR of OPTMK and ZMK. */
+} snvs_lp_master_key_mode_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * @note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_LP_Init(SNVS_Type *base);
+
+/*!
+ * @brief Deinit the SNVS LP section.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_LP_Deinit(SNVS_Type *base);
+
+/*! @}*/
+
+/*!
+ * @brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * @note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * @param base SNVS peripheral base address
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_Init(SNVS_Type *base, const snvs_lp_srtc_config_t *config);
+
+/*!
+ * @brief Stops the SRTC timer.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_LP_SRTC_Deinit(SNVS_Type *base);
+
+/*!
+ * @brief Fills in the SNVS_LP config struct with the default settings.
+ *
+ * The default values are as follows.
+ * @code
+ * config->srtccalenable = false;
+ * config->srtccalvalue = 0U;
+ * @endcode
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_GetDefaultConfig(snvs_lp_srtc_config_t *config);
+
+/*!
+ * @name Secure RTC (SRTC) current Time & Alarm
+ * @{
+ */
+
+/*!
+ * @brief Sets the SNVS SRTC date and time according to the given time structure.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * @return kStatus_Success: Success in setting the time and starting the SNVS SRTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_LP_SRTC_SetDatetime(SNVS_Type *base, const snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Gets the SNVS SRTC time and stores it in the given time structure.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetDatetime(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Sets the SNVS SRTC alarm time.
+ *
+ * The function sets the SRTC alarm. It also checks whether the specified alarm
+ * time is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ * Please note, that SRTC alarm has limited resolution because only 32 most
+ * significant bits of SRTC counter are compared to SRTC Alarm register.
+ * If the alarm time is beyond SRTC resolution, the function does not set the alarm
+ * and returns an error.
+ *
+ * @param base SNVS peripheral base address
+ * @param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * @return kStatus_Success: success in setting the SNVS SRTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed or is beyond resolution
+ */
+status_t SNVS_LP_SRTC_SetAlarm(SNVS_Type *base, const snvs_lp_srtc_datetime_t *alarmTime);
+
+/*!
+ * @brief Returns the SNVS SRTC alarm time.
+ *
+ * @param base SNVS peripheral base address
+ * @param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetAlarm(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime);
+
+/*! @}*/
+
+/*!
+ * @name Interrupt Interface
+ * @{
+ */
+
+/*!
+ * @brief Enables the selected SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration :: _snvs_lp_srtc_interrupts
+ */
+static inline void SNVS_LP_SRTC_EnableInterrupts(SNVS_Type *base, uint32_t mask)
+{
+ base->LPCR |= mask;
+}
+
+/*!
+ * @brief Disables the selected SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration :: _snvs_lp_srtc_interrupts
+ */
+static inline void SNVS_LP_SRTC_DisableInterrupts(SNVS_Type *base, uint32_t mask)
+{
+ base->LPCR &= ~mask;
+}
+
+/*!
+ * @brief Gets the enabled SNVS interrupts.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return The enabled interrupts. This is the logical OR of members of the
+ * enumeration :: _snvs_lp_srtc_interrupts
+ */
+uint32_t SNVS_LP_SRTC_GetEnabledInterrupts(SNVS_Type *base);
+
+/*! @}*/
+
+/*!
+ * @name Status Interface
+ * @{
+ */
+
+/*!
+ * @brief Gets the SNVS status flags.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return The status flags. This is the logical OR of members of the
+ * enumeration :: _snvs_lp_srtc_status_flags
+ */
+uint32_t SNVS_LP_SRTC_GetStatusFlags(SNVS_Type *base);
+
+/*!
+ * @brief Clears the SNVS status flags.
+ *
+ * @param base SNVS peripheral base address
+ * @param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration :: _snvs_lp_srtc_status_flags
+ */
+static inline void SNVS_LP_SRTC_ClearStatusFlags(SNVS_Type *base, uint32_t mask)
+{
+ base->LPSR |= mask;
+}
+
+/*! @}*/
+
+/*!
+ * @name Timer Start and Stop
+ * @{
+ */
+
+/*!
+ * @brief Starts the SNVS SRTC time counter.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_LP_SRTC_StartTimer(SNVS_Type *base)
+{
+ base->LPCR |= SNVS_LPCR_SRTC_ENV_MASK;
+ while ((0U == (base->LPCR & SNVS_LPCR_SRTC_ENV_MASK)))
+ {
+ }
+}
+
+/*!
+ * @brief Stops the SNVS SRTC time counter.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_LP_SRTC_StopTimer(SNVS_Type *base)
+{
+ base->LPCR &= ~SNVS_LPCR_SRTC_ENV_MASK;
+ while ((base->LPCR & SNVS_LPCR_SRTC_ENV_MASK) != 0U)
+ {
+ }
+}
+
+/*! @}*/
+
+/*!
+ * @name External tampering
+ * @{
+ */
+
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)
+
+/*!
+ * @brief Enables the specified SNVS external tamper.
+ *
+ * @param base SNVS peripheral base address
+ * @param pin SNVS external tamper pin
+ * @param config Configuration structure of external passive tamper
+ */
+void SNVS_LP_EnablePassiveTamper(SNVS_Type *base, snvs_lp_external_tamper_t pin, snvs_lp_passive_tamper_t config);
+
+#endif /* defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0) */
+
+#if defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0)
+/*!
+ * @brief Enable active tamper tx external pad
+ *
+ * @param base SNVS peripheral base address
+ * @param pin SNVS active tamper pin
+ * @param config Configuration structure of external active tamper
+ */
+status_t SNVS_LP_EnableTxActiveTamper(SNVS_Type *base,
+ snvs_lp_active_tx_tamper_t pin,
+ tamper_active_tx_config_t config);
+
+/*!
+ * @brief Enable active tamper rx external pad
+ *
+ * @param base SNVS peripheral base address
+ * @param rx SNVS external RX tamper pin
+ * @param config SNVS RX tamper config structure
+ */
+status_t SNVS_LP_EnableRxActiveTamper(SNVS_Type *base, snvs_lp_external_tamper_t rx, tamper_active_rx_config_t config);
+
+/*!
+ * @brief Sets voltage tamper detect
+ *
+ * @param base SNVS peripheral base address
+ * @param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetVoltageTamper(SNVS_Type *base, bool enable);
+
+/*!
+ * @brief Sets temperature tamper detect
+ *
+ * @param base SNVS peripheral base address
+ * @param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetTemperatureTamper(SNVS_Type *base, bool enable);
+
+/*!
+ * @brief Sets clock tamper detect
+ *
+ * @param base SNVS peripheral base address
+ * @param enable True if enable false if disable
+ */
+status_t SNVS_LP_SetClockTamper(SNVS_Type *base, bool enable);
+
+/*!
+ * brief Check voltage tamper
+ *
+ * param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckVoltageTamper(SNVS_Type *base);
+
+/*!
+ * @brief Check temperature tamper
+ *
+ * @param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckTemperatureTamper(SNVS_Type *base);
+
+/*!
+ * brief Check clock tamper
+ *
+ * param base SNVS peripheral base address
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_CheckClockTamper(SNVS_Type *base);
+
+/*!
+ * @brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->clock = kSNVS_ActiveTamper16HZ;
+ * config->seed = 0U;
+ * config->polynomial = 0U;
+ * endcode
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_TamperPinTx_GetDefaultConfig(tamper_active_tx_config_t *config);
+
+/*!
+ * brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->filterenable = 0U;
+ * config->filter = 0U;
+ * config->tx = kSNVS_ActiveTamper1;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_TamperPinRx_GetDefaultConfig(tamper_active_rx_config_t *config);
+#endif /* defined(FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS) && (FSL_FEATURE_SNVS_HAS_ACTIVE_TAMPERS > 0) */
+
+/*!
+ * @brief Fills in the SNVS tamper pin config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->polarity = 0U;
+ * config->filterenable = 0U; if available on SoC
+ * config->filter = 0U; if available on SoC
+ * endcode
+ * @param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_PassiveTamperPin_GetDefaultConfig(snvs_lp_passive_tamper_t *config);
+
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0)
+
+/*!
+ * @brief Disables the specified SNVS external tamper.
+ *
+ * @param base SNVS peripheral base address
+ * @param pin SNVS external tamper pin
+ */
+void SNVS_LP_DisableExternalTamper(SNVS_Type *base, snvs_lp_external_tamper_t pin);
+
+/*!
+ * @brief Disable all external tamper.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_LP_DisableAllExternalTamper(SNVS_Type *base);
+
+/*!
+ * @brief Returns status of the specified external tamper.
+ *
+ * @param base SNVS peripheral base address
+ * @param pin SNVS external tamper pin
+ *
+ * @return The status flag. This is the enumeration :: _snvs_lp_external_tamper_status
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_GetExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin);
+
+/*!
+ * @brief Clears status of the specified external tamper.
+ *
+ * @param base SNVS peripheral base address
+ * @param pin SNVS external tamper pin
+ */
+void SNVS_LP_ClearExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin);
+
+/*!
+ * @brief Clears status of the all external tamper.
+ *
+ * @param base SNVS peripheral base address
+ */
+void SNVS_LP_ClearAllExternalTamperStatus(SNVS_Type *base);
+
+#endif /* defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 0) */
+
+/*! @}*/
+
+/*!
+ * @name Monotonic Counter (MC)
+ * @{
+ */
+
+/*!
+ * @brief Enable or disable the Monotonic Counter.
+ *
+ * @param base SNVS peripheral base address
+ * @param enable Pass true to enable, false to disable.
+ */
+static inline void SNVS_LP_EnableMonotonicCounter(SNVS_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LPCR |= SNVS_LPCR_MC_ENV_MASK;
+ }
+ else
+ {
+ base->LPCR &= (~SNVS_LPCR_MC_ENV_MASK);
+ }
+}
+
+/*!
+ * @brief Get the current Monotonic Counter.
+ *
+ * @param base SNVS peripheral base address
+ * @return Current Monotonic Counter value.
+ */
+uint64_t SNVS_LP_GetMonotonicCounter(SNVS_Type *base);
+
+/*!
+ * @brief Increase the Monotonic Counter.
+ *
+ * Increase the Monotonic Counter by 1.
+ *
+ * @param base SNVS peripheral base address
+ */
+static inline void SNVS_LP_IncreaseMonotonicCounter(SNVS_Type *base)
+{
+ /* Write to the LPSMCLR or LPSMCLR, the counter increases. */
+ *((volatile uint32_t *)(uint32_t)(&(base->LPSMCLR))) = 0xFFFFFFFFU;
+}
+
+/*! @}*/
+
+/*!
+ * @name Zeroizable Master Key (ZMK)
+ * @{
+ */
+
+/*!
+ * @brief Write Zeroizable Master Key (ZMK) to the SNVS registers.
+ *
+ * @param base SNVS peripheral base address
+ * @param ZMKey The ZMK write to the SNVS register.
+ */
+void SNVS_LP_WriteZeroizableMasterKey(SNVS_Type *base, uint32_t ZMKey[SNVS_ZMK_REG_COUNT]);
+
+/*!
+ * @brief Set Zeroizable Master Key valid.
+ *
+ * This API could only be called when using software programming mode. After writing
+ * ZMK using @ref SNVS_LP_WriteZeroizableMasterKey, call this API to make the ZMK
+ * valid.
+ *
+ * @param base SNVS peripheral base address
+ * @param valid Pass true to set valid, false to set invalid.
+ */
+static inline void SNVS_LP_SetZeroizableMasterKeyValid(SNVS_Type *base, bool valid)
+{
+ if (valid)
+ {
+ base->LPMKCR |= SNVS_LPMKCR_ZMK_VAL_MASK;
+ }
+ else
+ {
+ base->LPMKCR &= (~SNVS_LPMKCR_ZMK_VAL_MASK);
+ }
+}
+
+/*!
+ * @brief Get Zeroizable Master Key valid status.
+ *
+ * In hardware programming mode, call this API to check whether the ZMK is valid.
+ *
+ * @param base SNVS peripheral base address
+ * @return true if valid, false if invalid.
+ */
+static inline bool SNVS_LP_GetZeroizableMasterKeyValid(SNVS_Type *base)
+{
+ return (SNVS_LPMKCR_ZMK_VAL_MASK == (base->LPMKCR & SNVS_LPMKCR_ZMK_VAL_MASK));
+}
+
+/*!
+ * @brief Set Zeroizable Master Key programming mode.
+ *
+ * @param base SNVS peripheral base address
+ * @param mode ZMK programming mode.
+ */
+static inline void SNVS_LP_SetZeroizableMasterKeyProgramMode(SNVS_Type *base, snvs_lp_zmk_program_mode_t mode)
+{
+ if (kSNVS_ZMKSoftwareProgram == mode)
+ {
+ base->LPMKCR &= (~SNVS_LPMKCR_ZMK_HWP_MASK);
+ }
+ else
+ {
+ base->LPMKCR |= SNVS_LPMKCR_ZMK_HWP_MASK;
+ }
+}
+
+/*!
+ * @brief Enable or disable Zeroizable Master Key ECC.
+ *
+ * @param base SNVS peripheral base address
+ * @param enable Pass true to enable, false to disable.
+ */
+static inline void SNVS_LP_EnableZeroizableMasterKeyECC(SNVS_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LPMKCR |= SNVS_LPMKCR_ZMK_ECC_EN_MASK;
+ }
+ else
+ {
+ base->LPMKCR &= (~SNVS_LPMKCR_ZMK_ECC_EN_MASK);
+ }
+}
+
+/*!
+ * @brief Set SNVS Master Key mode.
+ *
+ * @param base SNVS peripheral base address
+ * @param mode Master Key mode.
+ * @note When @ref kSNVS_ZMK or @ref kSNVS_CMK used, the SNVS_HP must be configured
+ * to enable the master key selection.
+ */
+static inline void SNVS_LP_SetMasterKeyMode(SNVS_Type *base, snvs_lp_master_key_mode_t mode)
+{
+ uint32_t lpmkcr = base->LPMKCR;
+ lpmkcr = (lpmkcr & (~SNVS_LPMKCR_MASTER_KEY_SEL_MASK)) | SNVS_LPMKCR_MASTER_KEY_SEL(mode);
+ base->LPMKCR = lpmkcr;
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_STATE_TRANSITION) && (FSL_FEATURE_SNVS_HAS_STATE_TRANSITION > 0)
+/*!
+ * brief Transition SNVS SSM state to Trusted/Non-secure from Check state
+ *
+ * param base SNVS peripheral base address
+ *
+ * return kStatus_Success: Success in transitioning SSM State
+ * kStatus_Fail: SSM State transition failed
+ */
+status_t SNVS_LP_SSM_State_Transition(SNVS_Type *base);
+#endif /* FSL_FEATURE_SNVS_HAS_STATE_TRANSITION */
+
+/*! @}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_SNVS_LP_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c
new file mode 100644
index 0000000000..72f1c60563
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c
@@ -0,0 +1,849 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief spdif transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+ kSPDIF_Error /*!< Transfer error occurred. */
+};
+
+/*! @brief Typedef for spdif tx interrupt handler. */
+typedef void (*spdif_isr_t)(SPDIF_Type *base, spdif_handle_t *handle);
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static SPDIF_Type *const s_spdifBases[] = SPDIF_BASE_PTRS;
+/*! @brief SPDIF handle pointer */
+static spdif_handle_t *s_spdifHandle[ARRAY_SIZE(s_spdifBases)][2];
+/* IRQ number array */
+static const IRQn_Type s_spdifIRQ[] = SPDIF_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_spdifClock[] = SPDIF_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifTxIsr;
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifRxIsr;
+/*! @brief Used for spdif gain */
+static uint8_t s_spdif_gain[8] = {24U, 16U, 12U, 8U, 6U, 4U, 3U, 1U};
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t SPDIF_GetInstance(SPDIF_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_spdifBases); instance++)
+ {
+ if (s_spdifBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_spdifBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the SPDIF peripheral.
+ *
+ * Ungates the SPDIF clock, resets the module, and configures SPDIF with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SPDIF_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SPDIF driver. Otherwise, accessing the SPDIF module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SPDIF base pointer
+ * param config SPDIF configuration structure.
+ */
+void SPDIF_Init(SPDIF_Type *base, const spdif_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SPDIF clock */
+ CLOCK_EnableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the internal logic */
+ base->SCR |= SPDIF_SCR_SOFT_RESET_MASK;
+
+ /* Waiting for reset finish */
+ while ((base->SCR & SPDIF_SCR_SOFT_RESET_MASK) != 0x00U)
+ {
+ }
+
+ /* Setting the SPDIF settings */
+ base->SCR = SPDIF_SCR_RXFIFOFULL_SEL(config->rxFullSelect) | SPDIF_SCR_RXAUTOSYNC(config->isRxAutoSync) |
+ SPDIF_SCR_TXAUTOSYNC(config->isRxAutoSync) | SPDIF_SCR_TXFIFOEMPTY_SEL(config->txFullSelect) |
+ SPDIF_SCR_TXFIFO_CTRL(1U) | SPDIF_SCR_VALCTRL(config->validityConfig) |
+ SPDIF_SCR_TXSEL(config->txSource) | SPDIF_SCR_USRC_SEL(config->uChannelSrc);
+
+ /* Set DPLL clock source */
+ base->SRPC = SPDIF_SRPC_CLKSRC_SEL(config->DPLLClkSource) | SPDIF_SRPC_GAINSEL(config->gain);
+
+ /* Set SPDIF tx clock source */
+ val = base->STC & ~SPDIF_STC_TXCLK_SOURCE_MASK;
+ val |= SPDIF_STC_TXCLK_SOURCE(config->txClkSource);
+ base->STC = val;
+
+ /* clear and diable all the interrupt */
+ base->SIC = (uint32_t)kSPDIF_AllInterrupt;
+ base->SIE &= ~(uint32_t)kSPDIF_AllInterrupt;
+}
+
+/*!
+ * brief De-initializes the SPDIF peripheral.
+ *
+ * This API gates the SPDIF clock. The SPDIF module can't operate unless SPDIF_Init is called to enable the clock.
+ *
+ * param base SPDIF base pointer
+ */
+void SPDIF_Deinit(SPDIF_Type *base)
+{
+ SPDIF_TxEnable(base, false);
+ SPDIF_RxEnable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the SPDIF configuration structure to default values.
+ *
+ * This API initializes the configuration structure for use in SPDIF_Init.
+ * The initialized structure can remain unchanged in SPDIF_Init, or it can be modified
+ * before calling SPDIF_Init.
+ * This is an example.
+ code
+ spdif_config_t config;
+ SPDIF_GetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SPDIF_GetDefaultConfig(spdif_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->isTxAutoSync = true;
+ config->isRxAutoSync = true;
+ config->DPLLClkSource = 1;
+ config->txClkSource = 1;
+ config->rxFullSelect = kSPDIF_RxFull8Samples;
+ config->txFullSelect = kSPDIF_TxEmpty8Samples;
+ config->uChannelSrc = kSPDIF_UChannelFromTx;
+ config->txSource = kSPDIF_txNormal;
+ config->validityConfig = kSPDIF_validityFlagAlwaysClear;
+ config->gain = kSPDIF_GAIN_8;
+}
+
+/*!
+ * brief Enables/disables the SPDIF Tx.
+ *
+ * param base SPDIF base pointer
+ * param enable True means enable SPDIF Tx, false means disable.
+ */
+void SPDIF_TxEnable(SPDIF_Type *base, bool enable)
+{
+ uint32_t val = 0;
+
+ if (enable)
+ {
+ /* Open Tx FIFO */
+ val = base->SCR & (~SPDIF_SCR_TXFIFO_CTRL_MASK);
+ val |= SPDIF_SCR_TXFIFO_CTRL(1U);
+ base->SCR = val;
+ /* Enable transfer clock */
+ base->STC |= SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+ else
+ {
+ base->SCR &= ~(SPDIF_SCR_TXFIFO_CTRL_MASK | SPDIF_SCR_TXSEL_MASK);
+ /* Disable transfer clock */
+ base->STC &= ~SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Tx sample rate.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate.
+ *
+ * param base SPDIF base pointer.
+ * param sampleRate_Hz SPDIF sample rate frequency in Hz.
+ * param sourceClockFreq_Hz SPDIF tx clock source frequency in Hz.
+ */
+void SPDIF_TxSetSampleRate(SPDIF_Type *base, uint32_t sampleRate_Hz, uint32_t sourceClockFreq_Hz)
+{
+ uint32_t clkDiv = sourceClockFreq_Hz / (sampleRate_Hz * 64U);
+ uint32_t mod = sourceClockFreq_Hz % (sampleRate_Hz * 64U);
+ uint32_t val = 0;
+ uint8_t clockSource = (uint8_t)(((base->STC) & SPDIF_STC_TXCLK_SOURCE_MASK) >> SPDIF_STC_TXCLK_SOURCE_SHIFT);
+
+ /* Compute the nearest divider */
+ if (mod > ((sampleRate_Hz * 64U) / 2U))
+ {
+ clkDiv += 1U;
+ }
+
+ /* If use divided systeme clock */
+ if (clockSource == 5U)
+ {
+ if (clkDiv > 256U)
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF((clkDiv / 128U) - 1U) | SPDIF_STC_TXCLK_DF(127U);
+ base->STC = val;
+ }
+ else
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF(1U) | SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+ }
+ else
+ {
+ /* Other clock only uses txclk div */
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SPDIF base pointer.
+ * param clockSourceFreq_Hz SPDIF system clock frequency in hz.
+ */
+uint32_t SPDIF_GetRxSampleRate(SPDIF_Type *base, uint32_t clockSourceFreq_Hz)
+{
+ uint64_t gain = s_spdif_gain[((base->SRPC & SPDIF_SRPC_GAINSEL_MASK) >> SPDIF_SRPC_GAINSEL_SHIFT)];
+ uint32_t measure = 0;
+ uint32_t sampleRate = 0;
+ uint64_t temp = 0;
+
+ /* Wait the DPLL locked */
+ while ((base->SRPC & SPDIF_SRPC_LOCK_MASK) == 0U)
+ {
+ }
+
+ /* Get the measure value */
+ measure = base->SRFM;
+ temp = (uint64_t)measure * (uint64_t)clockSourceFreq_Hz;
+ temp /= 1024U * 1024U * 128U * gain;
+ sampleRate = (uint32_t)temp;
+
+ return sampleRate;
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SPDIF_WriteBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Receives data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SPDIF_ReadBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Write right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Initializes the SPDIF Tx handle.
+ *
+ * This function initializes the Tx handle for the SPDIF Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void SPDIF_TransferTxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifTxIsr = SPDIF_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx handle.
+ *
+ * This function initializes the Rx handle for the SPDIF Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void SPDIF_TransferRxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifRxIsr = SPDIF_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_TxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferSendNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = kSPDIF_Busy;
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ /* Enable Tx transfer */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferReceiveNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ uint32_t enableInterrupts = (uint32_t)kSPDIF_RxFIFOFull | (uint32_t)kSPDIF_RxControlChannelChange;
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].udata = xfer->udata;
+ handle->spdifQueue[handle->queueUser].qdata = xfer->qdata;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kSPDIF_Busy;
+
+ if (xfer->qdata != NULL)
+ {
+ enableInterrupts |= (uint32_t)kSPDIF_QChannelReceiveRegisterFull;
+ }
+
+ if (xfer->udata != NULL)
+ {
+ enableInterrupts |= (uint32_t)kSPDIF_UChannelReceiveRegisterFull;
+ }
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, enableInterrupts);
+
+ /* Enable Rx transfer */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetSendCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets a received byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetReceiveCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortSend(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Use FIFO request interrupt and fifo error */
+ SPDIF_DisableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortReceive(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt */
+ SPDIF_DisableInterrupts(base, (uint32_t)kSPDIF_UChannelReceiveRegisterFull |
+ (uint32_t)kSPDIF_QChannelReceiveRegisterFull | (uint32_t)kSPDIF_RxFIFOFull |
+ (uint32_t)kSPDIF_RxControlChannelChange);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferTxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->spdifQueue[handle->queueDriver].data;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Do Transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ while (i < dataSize)
+ {
+ data = 0;
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortSend(base, handle);
+ }
+ }
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferRxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = NULL;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Handle Cnew flag */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxControlChannelChange) != 0x00U)
+ {
+ /* Clear the interrupt flag */
+ SPDIF_ClearStatusFlags(base, SPDIF_SIE_CNEW_MASK);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxCnew, handle->userData);
+ }
+ }
+
+ /* Handle illegal symbol */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxIllegalSymbol) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxIllegalSymbol);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIllegalSymbol, handle->userData);
+ }
+ }
+
+ /* Handle Parity Bit Error */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxParityBitError) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxParityBitError);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxParityBitError, handle->userData);
+ }
+ }
+
+ /* Handle DPlocked */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxDPLLLocked) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxDPLLLocked);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxDPLLLocked, handle->userData);
+ }
+ }
+
+ /* Handle Q channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].qdata;
+ if (buffer != NULL)
+ {
+ data = SPDIF_ReadQChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+ }
+
+ /* Handle U channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].udata;
+ if (buffer != NULL)
+ {
+ data = SPDIF_ReadUChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+ }
+
+ /* Handle audio data transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ buffer = handle->spdifQueue[handle->queueDriver].data;
+ while (i < dataSize)
+ {
+ /* Read left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Read right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0x00U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortReceive(base, handle);
+ }
+ }
+}
+
+#if defined(SPDIF)
+void SPDIF_DriverIRQHandler(void);
+void SPDIF_DriverIRQHandler(void)
+{
+ if ((s_spdifHandle[0][0] != NULL) && (s_spdifTxIsr != NULL))
+ {
+ s_spdifTxIsr(SPDIF, s_spdifHandle[0][0]);
+ }
+
+ if ((s_spdifHandle[0][1] != NULL) && (s_spdifRxIsr != NULL))
+ {
+ s_spdifRxIsr(SPDIF, s_spdifHandle[0][1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h
new file mode 100644
index 0000000000..c1656c10a8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SPDIF_H_
+#define _FSL_SPDIF_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup spdif
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SPDIF_DRIVER_VERSION (MAKE_VERSION(2, 0, 6)) /*!< Version 2.0.6 */
+/*@}*/
+
+/*! @brief SPDIF return status*/
+enum
+{
+ kStatus_SPDIF_RxDPLLLocked = MAKE_STATUS(kStatusGroup_SPDIF, 0), /*!< SPDIF Rx PLL locked. */
+ kStatus_SPDIF_TxFIFOError = MAKE_STATUS(kStatusGroup_SPDIF, 1), /*!< SPDIF Tx FIFO error. */
+ kStatus_SPDIF_TxFIFOResync = MAKE_STATUS(kStatusGroup_SPDIF, 2), /*!< SPDIF Tx left and right FIFO resync. */
+ kStatus_SPDIF_RxCnew = MAKE_STATUS(kStatusGroup_SPDIF, 3), /*!< SPDIF Rx status channel value updated. */
+ kStatus_SPDIF_ValidatyNoGood = MAKE_STATUS(kStatusGroup_SPDIF, 4), /*!< SPDIF validaty flag not good. */
+ kStatus_SPDIF_RxIllegalSymbol = MAKE_STATUS(kStatusGroup_SPDIF, 5), /*!< SPDIF Rx receive illegal symbol. */
+ kStatus_SPDIF_RxParityBitError = MAKE_STATUS(kStatusGroup_SPDIF, 6), /*!< SPDIF Rx parity bit error. */
+ kStatus_SPDIF_UChannelOverrun = MAKE_STATUS(kStatusGroup_SPDIF, 7), /*!< SPDIF receive U channel overrun. */
+ kStatus_SPDIF_QChannelOverrun = MAKE_STATUS(kStatusGroup_SPDIF, 8), /*!< SPDIF receive Q channel overrun. */
+ kStatus_SPDIF_UQChannelSync = MAKE_STATUS(kStatusGroup_SPDIF, 9), /*!< SPDIF U/Q channel sync found. */
+ kStatus_SPDIF_UQChannelFrameError = MAKE_STATUS(kStatusGroup_SPDIF, 10), /*!< SPDIF U/Q channel frame error. */
+ kStatus_SPDIF_RxFIFOError = MAKE_STATUS(kStatusGroup_SPDIF, 11), /*!< SPDIF Rx FIFO error. */
+ kStatus_SPDIF_RxFIFOResync = MAKE_STATUS(kStatusGroup_SPDIF, 12), /*!< SPDIF Rx left and right FIFO resync. */
+ kStatus_SPDIF_LockLoss = MAKE_STATUS(kStatusGroup_SPDIF, 13), /*!< SPDIF Rx PLL clock lock loss. */
+ kStatus_SPDIF_TxIdle = MAKE_STATUS(kStatusGroup_SPDIF, 14), /*!< SPDIF Tx is idle */
+ kStatus_SPDIF_RxIdle = MAKE_STATUS(kStatusGroup_SPDIF, 15), /*!< SPDIF Rx is idle */
+ kStatus_SPDIF_QueueFull = MAKE_STATUS(kStatusGroup_SPDIF, 16) /*!< SPDIF queue full */
+};
+
+/*! @brief SPDIF Rx FIFO full falg select, it decides when assert the rx full flag */
+typedef enum _spdif_rxfull_select
+{
+ kSPDIF_RxFull1Sample = 0x0u, /*!< Rx full at least 1 sample in left and right FIFO */
+ kSPDIF_RxFull4Samples, /*!< Rx full at least 4 sample in left and right FIFO*/
+ kSPDIF_RxFull8Samples, /*!< Rx full at least 8 sample in left and right FIFO*/
+ kSPDIF_RxFull16Samples, /*!< Rx full at least 16 sample in left and right FIFO*/
+} spdif_rxfull_select_t;
+
+/*! @brief SPDIF tx FIFO EMPTY falg select, it decides when assert the tx empty flag */
+typedef enum _spdif_txempty_select
+{
+ kSPDIF_TxEmpty0Sample = 0x0u, /*!< Tx empty at most 0 sample in left and right FIFO */
+ kSPDIF_TxEmpty4Samples, /*!< Tx empty at most 4 sample in left and right FIFO*/
+ kSPDIF_TxEmpty8Samples, /*!< Tx empty at most 8 sample in left and right FIFO*/
+ kSPDIF_TxEmpty12Samples, /*!< Tx empty at most 12 sample in left and right FIFO*/
+} spdif_txempty_select_t;
+
+/*! @brief SPDIF U channel source */
+typedef enum _spdif_uchannel_source
+{
+ kSPDIF_NoUChannel = 0x0U, /*!< No embedded U channel */
+ kSPDIF_UChannelFromRx = 0x1U, /*!< U channel from receiver, it is CD mode */
+ kSPDIF_UChannelFromTx = 0x3U, /*!< U channel from on chip tx */
+} spdif_uchannel_source_t;
+
+/*! @brief SPDIF clock gain*/
+typedef enum _spdif_gain_select
+{
+ kSPDIF_GAIN_24 = 0x0U, /*!< Gain select is 24 */
+ kSPDIF_GAIN_16, /*!< Gain select is 16 */
+ kSPDIF_GAIN_12, /*!< Gain select is 12 */
+ kSPDIF_GAIN_8, /*!< Gain select is 8 */
+ kSPDIF_GAIN_6, /*!< Gain select is 6 */
+ kSPDIF_GAIN_4, /*!< Gain select is 4 */
+ kSPDIF_GAIN_3, /*!< Gain select is 3 */
+} spdif_gain_select_t;
+
+/*! @brief SPDIF tx data source */
+typedef enum _spdif_tx_source
+{
+ kSPDIF_txFromReceiver = 0x1U, /*!< Tx data directly through SPDIF receiver */
+ kSPDIF_txNormal = 0x5U, /*!< Normal operation, data from processor */
+} spdif_tx_source_t;
+
+/*! @brief SPDIF tx data source */
+typedef enum _spdif_validity_config
+{
+ kSPDIF_validityFlagAlwaysSet = 0x0U, /*!< Outgoing validity flags always set */
+ kSPDIF_validityFlagAlwaysClear, /*!< Outgoing validity flags always clear */
+} spdif_validity_config_t;
+
+/*! @brief The SPDIF interrupt enable flag */
+enum
+{
+ kSPDIF_RxDPLLLocked = SPDIF_SIE_LOCK_MASK, /*!< SPDIF DPLL locked */
+ kSPDIF_TxFIFOError = SPDIF_SIE_TXUNOV_MASK, /*!< Tx FIFO underrun or overrun */
+ kSPDIF_TxFIFOResync = SPDIF_SIE_TXRESYN_MASK, /*!< Tx FIFO left and right channel resync */
+ kSPDIF_RxControlChannelChange = SPDIF_SIE_CNEW_MASK, /*!< SPDIF Rx control channel value changed */
+ kSPDIF_ValidityFlagNoGood = SPDIF_SIE_VALNOGOOD_MASK, /*!< SPDIF validity flag no good */
+ kSPDIF_RxIllegalSymbol = SPDIF_SIE_SYMERR_MASK, /*!< SPDIF receiver found illegal symbol */
+ kSPDIF_RxParityBitError = SPDIF_SIE_BITERR_MASK, /*!< SPDIF receiver found parity bit error */
+ kSPDIF_UChannelReceiveRegisterFull = SPDIF_SIE_URXFUL_MASK, /*!< SPDIF U channel revceive register full */
+ kSPDIF_UChannelReceiveRegisterOverrun = SPDIF_SIE_URXOV_MASK, /*!< SPDIF U channel receive register overrun */
+ kSPDIF_QChannelReceiveRegisterFull = SPDIF_SIE_QRXFUL_MASK, /*!< SPDIF Q channel receive reigster full */
+ kSPDIF_QChannelReceiveRegisterOverrun = SPDIF_SIE_QRXOV_MASK, /*!< SPDIF Q channel receive register overrun */
+ kSPDIF_UQChannelSync = SPDIF_SIE_UQSYNC_MASK, /*!< SPDIF U/Q channel sync found */
+ kSPDIF_UQChannelFrameError = SPDIF_SIE_UQERR_MASK, /*!< SPDIF U/Q channel frame error */
+ kSPDIF_RxFIFOError = SPDIF_SIE_RXFIFOUNOV_MASK, /*!< SPDIF Rx FIFO underrun/overrun */
+ kSPDIF_RxFIFOResync = SPDIF_SIE_RXFIFORESYN_MASK, /*!< SPDIF Rx left and right FIFO resync */
+ kSPDIF_LockLoss = SPDIF_SIE_LOCKLOSS_MASK, /*!< SPDIF receiver loss of lock */
+ kSPDIF_TxFIFOEmpty = SPDIF_SIE_TXEM_MASK, /*!< SPDIF Tx FIFO empty */
+ kSPDIF_RxFIFOFull = SPDIF_SIE_RXFIFOFUL_MASK, /*!< SPDIF Rx FIFO full */
+ kSPDIF_AllInterrupt = kSPDIF_RxDPLLLocked | kSPDIF_TxFIFOError | kSPDIF_TxFIFOResync |
+ kSPDIF_RxControlChannelChange | kSPDIF_ValidityFlagNoGood | kSPDIF_RxIllegalSymbol |
+ kSPDIF_RxParityBitError | kSPDIF_UChannelReceiveRegisterFull |
+ kSPDIF_UChannelReceiveRegisterOverrun | kSPDIF_QChannelReceiveRegisterFull |
+ kSPDIF_QChannelReceiveRegisterOverrun | kSPDIF_UQChannelSync | kSPDIF_UQChannelFrameError |
+ kSPDIF_RxFIFOError | kSPDIF_RxFIFOResync | kSPDIF_LockLoss | kSPDIF_TxFIFOEmpty |
+ kSPDIF_RxFIFOFull, /*!< all interrupt */
+};
+
+/*! @brief The DMA request sources */
+enum
+{
+ kSPDIF_RxDMAEnable = SPDIF_SCR_DMA_RX_EN_MASK, /*!< Rx FIFO full */
+ kSPDIF_TxDMAEnable = SPDIF_SCR_DMA_TX_EN_MASK, /*!< Tx FIFO empty */
+};
+
+/*! @brief SPDIF user configuration structure */
+typedef struct _spdif_config
+{
+ bool isTxAutoSync; /*!< If auto sync mechanism open */
+ bool isRxAutoSync; /*!< If auto sync mechanism open */
+ uint8_t DPLLClkSource; /*!< SPDIF DPLL clock source, range from 0~15, meaning is chip-specific */
+ uint8_t txClkSource; /*!< SPDIF tx clock source, range from 0~7, meaning is chip-specific */
+ spdif_rxfull_select_t rxFullSelect; /*!< SPDIF rx buffer full select */
+ spdif_txempty_select_t txFullSelect; /*!< SPDIF tx buffer empty select */
+ spdif_uchannel_source_t uChannelSrc; /*!< U channel source */
+ spdif_tx_source_t txSource; /*!< SPDIF tx data source */
+ spdif_validity_config_t validityConfig; /*!< Validity flag config */
+ spdif_gain_select_t gain; /*!< Rx receive clock measure gain parameter. */
+} spdif_config_t;
+
+/*!@brief SPDIF transfer queue size, user can refine it according to use case. */
+#define SPDIF_XFER_QUEUE_SIZE (4U)
+
+/*! @brief SPDIF transfer structure */
+typedef struct _spdif_transfer
+{
+ uint8_t *data; /*!< Data start address to transfer. */
+ uint8_t *qdata; /*!< Data buffer for Q channel */
+ uint8_t *udata; /*!< Data buffer for C channel */
+ size_t dataSize; /*!< Transfer size. */
+} spdif_transfer_t;
+
+typedef struct _spdif_handle spdif_handle_t;
+
+/*! @brief SPDIF transfer callback prototype */
+typedef void (*spdif_transfer_callback_t)(SPDIF_Type *base, spdif_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SPDIF handle structure */
+struct _spdif_handle
+{
+ uint32_t state; /*!< Transfer status */
+ spdif_transfer_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+ spdif_transfer_t spdifQueue[SPDIF_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[SPDIF_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+ uint8_t watermark; /*!< Watermark value */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF peripheral.
+ *
+ * Ungates the SPDIF clock, resets the module, and configures SPDIF with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SPDIF_GetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the SPDIF driver. Otherwise, accessing the SPDIF module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base SPDIF base pointer
+ * @param config SPDIF configuration structure.
+ */
+void SPDIF_Init(SPDIF_Type *base, const spdif_config_t *config);
+
+/*!
+ * @brief Sets the SPDIF configuration structure to default values.
+ *
+ * This API initializes the configuration structure for use in SPDIF_Init.
+ * The initialized structure can remain unchanged in SPDIF_Init, or it can be modified
+ * before calling SPDIF_Init.
+ * This is an example.
+ @code
+ spdif_config_t config;
+ SPDIF_GetDefaultConfig(&config);
+ @endcode
+ *
+ * @param config pointer to master configuration structure
+ */
+void SPDIF_GetDefaultConfig(spdif_config_t *config);
+
+/*!
+ * @brief De-initializes the SPDIF peripheral.
+ *
+ * This API gates the SPDIF clock. The SPDIF module can't operate unless SPDIF_Init is called to enable the clock.
+ *
+ * @param base SPDIF base pointer
+ */
+void SPDIF_Deinit(SPDIF_Type *base);
+
+/*!
+ * @brief Get the instance number for SPDIF.
+ *
+ * @param base SPDIF base pointer.
+ */
+uint32_t SPDIF_GetInstance(SPDIF_Type *base);
+
+/*!
+ * @brief Resets the SPDIF Tx.
+ *
+ * This function makes Tx FIFO in reset mode.
+ *
+ * @param base SPDIF base pointer
+ */
+static inline void SPDIF_TxFIFOReset(SPDIF_Type *base)
+{
+ base->SCR |= SPDIF_SCR_RXFIFO_RST_MASK;
+}
+
+/*!
+ * @brief Resets the SPDIF Rx.
+ *
+ * This function enables the software reset and FIFO reset of SPDIF Rx. After reset, clear the reset bit.
+ *
+ * @param base SPDIF base pointer
+ */
+static inline void SPDIF_RxFIFOReset(SPDIF_Type *base)
+{
+ base->SCR |= SPDIF_SCR_RXFIFO_RST_MASK;
+}
+
+/*!
+ * @brief Enables/disables the SPDIF Tx.
+ *
+ * @param base SPDIF base pointer
+ * @param enable True means enable SPDIF Tx, false means disable.
+ */
+void SPDIF_TxEnable(SPDIF_Type *base, bool enable);
+
+/*!
+ * @brief Enables/disables the SPDIF Rx.
+ *
+ * @param base SPDIF base pointer
+ * @param enable True means enable SPDIF Rx, false means disable.
+ */
+static inline void SPDIF_RxEnable(SPDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* Open Rx FIFO */
+ base->SCR &= ~(SPDIF_SCR_RXFIFO_CTRL_MASK | SPDIF_SCR_RXFIFO_OFF_ON_MASK);
+ }
+ else
+ {
+ base->SCR |= SPDIF_SCR_RXFIFO_OFF_ON_MASK;
+ }
+}
+
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the SPDIF status flag state.
+ *
+ * @param base SPDIF base pointer
+ * @return SPDIF status flag value. Use the _spdif_interrupt_enable_t to get the status value needed.
+ */
+static inline uint32_t SPDIF_GetStatusFlag(SPDIF_Type *base)
+{
+ return base->SIS;
+}
+
+/*!
+ * @brief Clears the SPDIF status flag state.
+ *
+ * @param base SPDIF base pointer
+ * @param mask State mask. It can be a combination of the _spdif_interrupt_enable_t member. Notice these members
+ * cannot be included, as these flags cannot be cleared by writing 1 to these bits:
+ * @arg kSPDIF_UChannelReceiveRegisterFull
+ * @arg kSPDIF_QChannelReceiveRegisterFull
+ * @arg kSPDIF_TxFIFOEmpty
+ * @arg kSPDIF_RxFIFOFull
+ */
+static inline void SPDIF_ClearStatusFlags(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIC = mask;
+}
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the SPDIF Tx interrupt requests.
+ *
+ * @param base SPDIF base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSPDIF_WordStartInterruptEnable
+ * @arg kSPDIF_SyncErrorInterruptEnable
+ * @arg kSPDIF_FIFOWarningInterruptEnable
+ * @arg kSPDIF_FIFORequestInterruptEnable
+ * @arg kSPDIF_FIFOErrorInterruptEnable
+ */
+static inline void SPDIF_EnableInterrupts(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIE |= mask;
+}
+
+/*!
+ * @brief Disables the SPDIF Tx interrupt requests.
+ *
+ * @param base SPDIF base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSPDIF_WordStartInterruptEnable
+ * @arg kSPDIF_SyncErrorInterruptEnable
+ * @arg kSPDIF_FIFOWarningInterruptEnable
+ * @arg kSPDIF_FIFORequestInterruptEnable
+ * @arg kSPDIF_FIFOErrorInterruptEnable
+ */
+static inline void SPDIF_DisableInterrupts(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIE &= ~mask;
+}
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the SPDIF DMA requests.
+ * @param base SPDIF base pointer
+ * @param mask SPDIF DMA enable mask, The parameter can be a combination of the following sources if defined
+ * @arg kSPDIF_RxDMAEnable
+ * @arg kSPDIF_TxDMAEnable
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void SPDIF_EnableDMA(SPDIF_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->SCR |= mask;
+ }
+ else
+ {
+ base->SCR &= ~mask;
+ }
+}
+
+/*!
+ * @brief Gets the SPDIF Tx left data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_TxGetLeftDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->STL));
+}
+
+/*!
+ * @brief Gets the SPDIF Tx right data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_TxGetRightDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->STR));
+}
+
+/*!
+ * @brief Gets the SPDIF Rx left data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_RxGetLeftDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->SRL));
+}
+
+/*!
+ * @brief Gets the SPDIF Rx right data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_RxGetRightDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->SRR));
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Configures the SPDIF Tx sample rate.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate.
+ *
+ * @param base SPDIF base pointer.
+ * @param sampleRate_Hz SPDIF sample rate frequency in Hz.
+ * @param sourceClockFreq_Hz SPDIF tx clock source frequency in Hz.
+ */
+void SPDIF_TxSetSampleRate(SPDIF_Type *base, uint32_t sampleRate_Hz, uint32_t sourceClockFreq_Hz);
+
+/*!
+ * @brief Configures the SPDIF Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SPDIF base pointer.
+ * @param clockSourceFreq_Hz SPDIF system clock frequency in hz.
+ */
+uint32_t SPDIF_GetRxSampleRate(SPDIF_Type *base, uint32_t clockSourceFreq_Hz);
+
+/*!
+ * @brief Sends data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SPDIF base pointer.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+void SPDIF_WriteBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteLeftData(SPDIF_Type *base, uint32_t data)
+{
+ base->STL = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteRightData(SPDIF_Type *base, uint32_t data)
+{
+ base->STR = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteChannelStatusHigh(SPDIF_Type *base, uint32_t data)
+{
+ base->STCSCH = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteChannelStatusLow(SPDIF_Type *base, uint32_t data)
+{
+ base->STCSCL = data;
+}
+
+/*!
+ * @brief Receives data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SPDIF base pointer.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+void SPDIF_ReadBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadLeftData(SPDIF_Type *base)
+{
+ return base->SRL;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadRightData(SPDIF_Type *base)
+{
+ return base->SRR;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadChannelStatusHigh(SPDIF_Type *base)
+{
+ return base->SRCSH;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadChannelStatusLow(SPDIF_Type *base)
+{
+ return base->SRCSL;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadQChannel(SPDIF_Type *base)
+{
+ return base->SRQ;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadUChannel(SPDIF_Type *base)
+{
+ return base->SRU;
+}
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF Tx handle.
+ *
+ * This function initializes the Tx handle for the SPDIF Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function
+ */
+void SPDIF_TransferTxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Initializes the SPDIF Rx handle.
+ *
+ * This function initializes the Rx handle for the SPDIF Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function.
+ */
+void SPDIF_TransferRxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs an interrupt non-blocking send transfer on SPDIF.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the spdif_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SPDIF_TxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferSendNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on SPDIF.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * @param base SPDIF base pointer
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the spdif_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SPDIF_RxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferReceiveNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer);
+
+/*!
+ * @brief Gets a set byte count.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param count Bytes count sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetSendCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets a received byte count.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param count Bytes count received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetReceiveCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the current send.
+ *
+ * @note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortSend(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Aborts the current IRQ receive.
+ *
+ * @note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SPDIF base pointer
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortReceive(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferTxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferRxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_SPDIF_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c
new file mode 100644
index 0000000000..88b95bd195
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _spdif_edma_private_handle
+{
+ SPDIF_Type *base;
+ spdif_edma_handle_t *handle;
+} spdif_edma_private_handle_t;
+
+/*!
+ * @brief Used for conversion between `void*` and `uint32_t`.
+ */
+typedef union pvoid_to_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pvoid_to_u32_t;
+
+/*! @brief spdif edma transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static spdif_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_SPDIF_COUNT][2];
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Submit SPDIF tcds to EDMA.
+ *
+ * @param base SPDIF base pointer.
+ */
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle,
+ const edma_transfer_config_t *config,
+ uint32_t rightChannel);
+
+/*!
+ * @brief SPDIF EDMA callback for send.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SPDIF EDMA callback for receive.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_TxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortSendEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_RxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortReceiveEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
+{
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+ uint32_t primask;
+ uint16_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+ int8_t tcdUsed = handle->tcdUsed;
+ int8_t tcdSize = handle->tcdSize;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ if (tcdUsed >= tcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 0x01;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0x00;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = (currentTcd != 0x00) ? (currentTcd - 0x01) : (handle->tcdSize - 0x01);
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Set channel link */
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = (handle->tcdPool[previousTcd].CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD block in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+ {
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = (tcdRegs->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
+ link succeed.
+ */
+ if ((tcdRegs->CSR & DMA_CSR_ESG_MASK) != 0x00U)
+ {
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0x00U)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if ((handle->flags & 0x80U) != 0x00U)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the SPDIF eDMA handle.
+ *
+ * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel, only right channel finished, a transfer finished */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx eDMA handle.
+ *
+ * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count = s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF transfer using DMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_TxBusy SPDIF is busy sending data.
+ */
+status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t destAddr;
+ edma_transfer_config_t config = {0};
+ destAddr.u32 = SPDIF_TxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->leftData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ destAddr.u32 = SPDIF_TxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, xfer->rightData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, true);
+
+ /* Enable SPDIF Tx clock */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy SPDIF is busy receiving data.
+ */
+status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t srcAddr;
+ edma_transfer_config_t config = {0};
+ srcAddr.u32 = SPDIF_RxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->leftData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ /* Use specific submit function to enable channel link */
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ srcAddr.u32 = SPDIF_RxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->rightData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, true);
+
+ /* Enable SPDIF Rx clock */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a SPDIF transfer using eDMA.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Aborts a SPDIF receive using eDMA.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Gets byte count sent by SPDIF.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count sent by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets byte count received by SPDIF.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count received by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h
new file mode 100644
index 0000000000..964bf1e7ab
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_SPDIF_EDMA_H_
+#define _FSL_SPDIF_EDMA_H_
+
+#include "fsl_spdif.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup spdif_edma
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SPDIF_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 5)) /*!< Version 2.0.5 */
+/*@}*/
+
+typedef struct _spdif_edma_handle spdif_edma_handle_t;
+
+/*! @brief SPDIF eDMA transfer callback function for finish and error */
+typedef void (*spdif_edma_callback_t)(SPDIF_Type *base, spdif_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SPDIF transfer structure */
+typedef struct _spdif_edma_transfer
+{
+ uint8_t *leftData; /*!< Data start address to transfer. */
+ uint8_t *rightData; /*!< Data start address to transfer. */
+ size_t dataSize; /*!< Transfer size. */
+} spdif_edma_transfer_t;
+
+/*! @brief SPDIF DMA transfer handle, users should not touch the content of the handle.*/
+struct _spdif_edma_handle
+{
+ edma_handle_t *dmaLeftHandle; /*!< DMA handler for SPDIF left channel */
+ edma_handle_t *dmaRightHandle; /*!< DMA handler for SPDIF right channel */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for SPDIF eDMA transfer */
+ spdif_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ edma_tcd_t leftTcd[SPDIF_XFER_QUEUE_SIZE + 1U]; /*!< TCD pool for eDMA transfer. */
+ edma_tcd_t rightTcd[SPDIF_XFER_QUEUE_SIZE + 1U]; /*!< TCD pool for eDMA transfer. */
+ spdif_edma_transfer_t spdifQueue[SPDIF_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[SPDIF_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer, left and right are the same, so use
+ one */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF eDMA handle.
+ *
+ * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param base SPDIF peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * @param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle);
+
+/*!
+ * @brief Initializes the SPDIF Rx eDMA handle.
+ *
+ * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param base SPDIF peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * @param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle);
+
+/*!
+ * @brief Performs a non-blocking SPDIF transfer using DMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a SPDIF eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_TxBusy SPDIF is busy sending data.
+ */
+status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SPDIF receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a SPDIF eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy SPDIF is busy receiving data.
+ */
+status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a SPDIF transfer using eDMA.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SPDIF receive using eDMA.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count sent by SPDIF.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param count Bytes count sent by SPDIF.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets byte count received by SPDIF.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ * @param count Bytes count received by SPDIF.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.c b/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.c
new file mode 100644
index 0000000000..10af22893a
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_src.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.src"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Clear the status flags of SRC.
+ *
+ * param base SRC peripheral base address.
+ * param Mask value of status flags to be cleared, see to #_src_reset_status_flags.
+ */
+void SRC_ClearResetStatusFlags(SRC_Type *base, uint32_t flags)
+{
+ uint32_t tmp32 = base->SRSR;
+
+ if (0U != (SRC_SRSR_TSR_MASK & flags))
+ {
+ tmp32 &= ~SRC_SRSR_TSR_MASK; /* Write 0 to clear. */
+ }
+
+ if (0U != (SRC_SRSR_W1C_BITS_MASK & flags))
+ {
+ tmp32 |= (SRC_SRSR_W1C_BITS_MASK & flags); /* Write 1 to clear. */
+ }
+
+ base->SRSR = tmp32;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.h b/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.h
new file mode 100644
index 0000000000..33ebf14f14
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/src/fsl_src.h
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SRC_H_
+#define _FSL_SRC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup src
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief SRC driver version 2.0.1. */
+#define FSL_SRC_DRIVER_VERSION (MAKE_VERSION(2, 0, 1))
+/*@}*/
+
+/*!
+ * @brief SRC reset status flags.
+ */
+enum _src_reset_status_flags
+{
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_RESET_OUT) && FSL_FEATURE_SRC_HAS_SRSR_RESET_OUT)
+ kSRC_ResetOutputEnableFlag = SRC_SRSR_RESET_OUT_MASK, /*!< This bit indicates if RESET status is
+ driven out on PTE0 pin. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_RESET_OUT */
+#if !(defined(FSL_FEATURE_SRC_HAS_NO_SRSR_WBI) && FSL_FEATURE_SRC_HAS_NO_SRSR_WBI)
+ kSRC_WarmBootIndicationFlag = SRC_SRSR_WBI_MASK, /*!< WARM boot indication shows that WARM boot
+ was initiated by software. */
+#endif /* FSL_FEATURE_SRC_HAS_NO_SRSR_WBI */
+ kSRC_TemperatureSensorResetFlag = SRC_SRSR_TSR_MASK, /*!< Indicates whether the reset was the
+ result of software reset from on-chip
+ Temperature Sensor. Temperature Sensor
+ Interrupt needs to be served before this
+ bit can be cleaned.*/
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_WDOG3_RST_B) && FSL_FEATURE_SRC_HAS_SRSR_WDOG3_RST_B)
+ kSRC_Wdog3ResetFlag = SRC_SRSR_WDOG3_RST_B_MASK, /*!< IC Watchdog3 Time-out reset. Indicates
+ whether the reset was the result of the
+ watchdog3 time-out event. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_WDOG3_RST_B */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_SW) && FSL_FEATURE_SRC_HAS_SRSR_SW)
+ kSRC_SoftwareResetFlag = SRC_SRSR_SW_MASK, /*!< Indicates a reset has been caused by software
+ setting of SYSRESETREQ bit in Application
+ Interrupt and Reset Control Register in the
+ ARM core. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_SW */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_JTAG_SW_RST) && FSL_FEATURE_SRC_HAS_SRSR_JTAG_SW_RST)
+ kSRC_JTAGSystemResetFlag =
+ SRC_SRSR_JTAG_SW_RST_MASK, /*!< Indicates whether the reset was the result of software reset form JTAG */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_JTAG_SW_RST */
+ kSRC_JTAGSoftwareResetFlag = SRC_SRSR_SJC_MASK, /*!< Indicates whether the reset was the result of
+ setting SJC_GPCCR bit 31. */
+ kSRC_JTAGGeneratedResetFlag = SRC_SRSR_JTAG_MASK, /*!< Indicates a reset has been caused by JTAG
+ selection of certain IR codes: EXTEST or
+ HIGHZ. */
+ kSRC_WatchdogResetFlag = SRC_SRSR_WDOG_MASK, /*!< Indicates a reset has been caused by the
+ watchdog timer timing out. This reset source
+ can be blocked by disabling the watchdog. */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_IPP_USER_RESET_B) && FSL_FEATURE_SRC_HAS_SRSR_IPP_USER_RESET_B)
+ kSRC_IppUserResetFlag = SRC_SRSR_IPP_USER_RESET_B_MASK, /*!< Indicates whether the reset was the
+ result of the ipp_user_reset_b
+ qualified reset. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_IPP_USER_RESET_B */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_SNVS) && FSL_FEATURE_SRC_HAS_SRSR_SNVS)
+ kSRC_SNVSFailResetFlag = SRC_SRSR_SNVS_MASK, /*!< SNVS hardware failure will always cause a cold
+ reset. This flag indicates whether the reset
+ is a result of SNVS hardware failure. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_SNVS */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B) && FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B)
+ kSRC_CsuResetFlag = SRC_SRSR_CSU_RESET_B_MASK, /*!< Indicates whether the reset was the result
+ of the csu_reset_b input. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_LOCKUP) && FSL_FEATURE_SRC_HAS_SRSR_LOCKUP)
+ kSRC_CoreLockupResetFlag = SRC_SRSR_LOCKUP_MASK, /*!< Indicates a reset has been caused by the
+ ARM core indication of a LOCKUP event. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_LOCKUP */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_POR) && FSL_FEATURE_SRC_HAS_SRSR_POR)
+ kSRC_PowerOnResetFlag = SRC_SRSR_POR_MASK, /*!< Indicates a reset has been caused by the
+ power-on detection logic. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_POR */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ) && FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ)
+ kSRC_LockupSysResetFlag =
+ SRC_SRSR_LOCKUP_SYSRESETREQ_MASK, /*!< Indicates a reset has been caused by CPU lockup or software
+ setting of SYSRESETREQ bit in Application Interrupt and
+ Reset Control Register of the ARM core. */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ */
+#if (defined(FSL_FEATURE_SRC_HAS_SRSR_IPP_RESET_B) && FSL_FEATURE_SRC_HAS_SRSR_IPP_RESET_B)
+ kSRC_IppResetPinFlag = SRC_SRSR_IPP_RESET_B_MASK, /*!< Indicates whether reset was the result of
+ ipp_reset_b pin (Power-up sequence). */
+#endif /* FSL_FEATURE_SRC_HAS_SRSR_IPP_RESET_B */
+};
+
+#if (defined(FSL_FEATURE_SRC_HAS_SISR) && FSL_FEATURE_SRC_HAS_SISR)
+/*!
+ * @brief SRC interrupt status flag.
+ */
+enum _src_status_flags
+{
+ kSRC_Core0WdogResetReqFlag =
+ SRC_SISR_CORE0_WDOG_RST_REQ_MASK, /*!< WDOG reset request from core0. Read-only status bit. */
+};
+#endif /* FSL_FEATURE_SRC_HAS_SISR */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH) && FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH)
+/*!
+ * @brief Selection of SoC mix power reset stretch.
+ *
+ * This type defines the SoC mix (Audio, ENET, uSDHC, EIM, QSPI, OCRAM, MMDC, etc) power up reset
+ * stretch mix reset width with the optional count of cycles
+ */
+typedef enum _src_mix_reset_stretch_cycles
+{
+ kSRC_MixResetStretchCycleAlt0 = 0U, /*!< mix reset width is 1 x 88 ipg_cycle cycles. */
+ kSRC_MixResetStretchCycleAlt1 = 1U, /*!< mix reset width is 2 x 88 ipg_cycle cycles. */
+ kSRC_MixResetStretchCycleAlt2 = 2U, /*!< mix reset width is 3 x 88 ipg_cycle cycles. */
+ kSRC_MixResetStretchCycleAlt3 = 3U, /*!< mix reset width is 4 x 88 ipg_cycle cycles. */
+} src_mix_reset_stretch_cycles_t;
+#endif /* FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN) && FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN)
+/*!
+ * @brief Selection of WDOG3 reset option.
+ */
+typedef enum _src_wdog3_reset_option
+{
+ kSRC_Wdog3ResetOptionAlt0 = 0U, /*!< Wdog3_rst_b asserts M4 reset (default). */
+ kSRC_Wdog3ResetOptionAlt1 = 1U, /*!< Wdog3_rst_b asserts global reset. */
+} src_wdog3_reset_option_t;
+#endif /* FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN */
+
+/*!
+ * @brief Selection of WARM reset bypass count.
+ *
+ * This type defines the 32KHz clock cycles to count before bypassing the MMDC acknowledge for WARM
+ * reset. If the MMDC acknowledge is not asserted before this counter is elapsed, a COLD reset will
+ * be initiated.
+ */
+typedef enum _src_warm_reset_bypass_count
+{
+ kSRC_WarmResetWaitAlways = 0U, /*!< System will wait until MMDC acknowledge is asserted. */
+ kSRC_WarmResetWaitClk16 = 1U, /*!< Wait 16 32KHz clock cycles before switching the reset. */
+ kSRC_WarmResetWaitClk32 = 2U, /*!< Wait 32 32KHz clock cycles before switching the reset. */
+ kSRC_WarmResetWaitClk64 = 3U, /*!< Wait 64 32KHz clock cycles before switching the reset. */
+} src_warm_reset_bypass_count_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_MASK_WDOG3_RST) && FSL_FEATURE_SRC_HAS_SCR_MASK_WDOG3_RST)
+/*!
+ * @brief Enable the WDOG3 reset.
+ *
+ * The WDOG3 reset is enabled by default.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableWDOG3Reset(SRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MASK_WDOG3_RST_MASK) | SRC_SCR_MASK_WDOG3_RST(0xA);
+ }
+ else
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MASK_WDOG3_RST_MASK) | SRC_SCR_MASK_WDOG3_RST(0x5);
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_MASK_WDOG3_RST */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH) && FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH)
+/*!
+ * @brief Set the mix power up reset stretch mix reset width.
+ *
+ * @param base SRC peripheral base address.
+ * @param option Setting option, see to #src_mix_reset_stretch_cycles_t.
+ */
+static inline void SRC_SetMixResetStretchCycles(SRC_Type *base, src_mix_reset_stretch_cycles_t option)
+{
+ base->SCR = (base->SCR & ~SRC_SCR_MIX_RST_STRCH_MASK) | SRC_SCR_MIX_RST_STRCH(option);
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_MIX_RST_STRCH */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_DBG_RST_MSK_PG) && FSL_FEATURE_SRC_HAS_SCR_DBG_RST_MSK_PG)
+/*!
+ * @brief Debug reset would be asserted after power gating event.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableCoreDebugResetAfterPowerGate(SRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SCR &= ~SRC_SCR_DBG_RST_MSK_PG_MASK;
+ }
+ else
+ {
+ base->SCR |= SRC_SCR_DBG_RST_MSK_PG_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_DBG_RST_MSK_PG */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN) && FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN)
+/*!
+ * @brief Set the Wdog3_rst_b option.
+ *
+ * @param base SRC peripheral base address.
+ * @param option Setting option, see to #src_wdog3_reset_option_t.
+ */
+static inline void SRC_SetWdog3ResetOption(SRC_Type *base, src_wdog3_reset_option_t option)
+{
+ base->SCR = (base->SCR & ~SRC_SCR_WDOG3_RST_OPTN_MASK) | SRC_SCR_WDOG3_RST_OPTN(option);
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_WDOG3_RST_OPTN */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_CORES_DBG_RST) && FSL_FEATURE_SRC_HAS_SCR_CORES_DBG_RST)
+/*!
+ * @brief Software reset for debug of arm platform only.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline void SRC_DoSoftwareResetARMCoreDebug(SRC_Type *base)
+{
+ base->SCR |= SRC_SCR_CORES_DBG_RST_MASK;
+}
+
+/*!
+ * @brief Check if the software reset for debug of arm platform only is done.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline bool SRC_GetSoftwareResetARMCoreDebugDone(SRC_Type *base)
+{
+ return (0U == (base->SCR & SRC_SCR_CORES_DBG_RST_MASK));
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_CORES_DBG_RST */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_MTSR) && FSL_FEATURE_SRC_HAS_SCR_MTSR)
+/*!
+ * @brief Enable the temperature sensor reset.
+ *
+ * The temperature sersor reset is enabled by default. When the sensor reset happens, an flag bit
+ * would be asserted. This flag bit can be cleared only by the hardware reset.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableTemperatureSensorReset(SRC_Type *base, bool enable)
+{
+ if (enable) /* Temperature sensor reset is not masked. (default) */
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MTSR_MASK) | SRC_SCR_MTSR(0x2);
+ }
+ else /* The on-chip temperature sensor interrupt will not create a reset to the chip. */
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MTSR_MASK) | SRC_SCR_MTSR(0x5);
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_MTSR */
+
+#if (defined(FSL_FEATURE_SCR_HAS_SCR_CORE0_DBG_RST) && FSL_FEATURE_SCR_HAS_SCR_CORE0_DBG_RST)
+/*!
+ * @brief Do assert the core0 debug reset.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline void SRC_DoAssertCore0DebugReset(SRC_Type *base)
+{
+ base->SCR |= SRC_SCR_CORE0_DBG_RST_MASK;
+}
+
+/*!
+ * @brief Check if the core0 debug reset is done.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline bool SRC_GetAssertCore0DebugResetDone(SRC_Type *base)
+{
+ return (0U == (base->SCR & SRC_SCR_CORE0_DBG_RST_MASK));
+}
+#endif /* FSL_FEATURE_SCR_HAS_SCR_CORE0_DBG_RST */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_CORE0_RST) && FSL_FEATURE_SRC_HAS_SCR_CORE0_RST)
+/*!
+ * @brief Do software reset the ARM core0 only.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline void SRC_DoSoftwareResetARMCore0(SRC_Type *base)
+{
+ base->SCR |= SRC_SCR_CORE0_RST_MASK;
+}
+
+/*!
+ * @brief Check if the software for ARM core0 is done.
+ *
+ * @param base SRC peripheral base address.
+ * @return If the reset is done.
+ */
+static inline bool SRC_GetSoftwareResetARMCore0Done(SRC_Type *base)
+{
+ return (0U == (base->SCR & SRC_SCR_CORE0_RST_MASK));
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_CORE0_RST */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_SWRC) && FSL_FEATURE_SRC_HAS_SCR_SWRC)
+/*!
+ * @brief Do software reset for ARM core.
+ *
+ * This function can be used to assert the ARM core reset. Once it is called, the reset process will
+ * begin. After the reset process is finished, the command bit would be self cleared.
+ *
+ * @param base SRC peripheral base address.
+ */
+static inline void SRC_DoSoftwareResetARMCore(SRC_Type *base)
+{
+ base->SCR |= SRC_SCR_SWRC_MASK;
+}
+
+/*!
+ * @brief Check if the software for ARM core is done.
+ *
+ * @param base SRC peripheral base address.
+ * @return If the reset is done.
+ */
+static inline bool SRC_GetSoftwareResetARMCoreDone(SRC_Type *base)
+{
+ return (0U == (base->SCR & SRC_SCR_SWRC_MASK));
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_SWRC */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_EIM_RST) && FSL_FEATURE_SRC_HAS_SCR_EIM_RST)
+/*!
+ * @brief Assert the EIM reset.
+ *
+ * EIM reset is needed in order to reconfigure the EIM chip select.
+ * The software reset bit must de-asserted since this is not self-refresh.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Make the assertion or not.
+ */
+static inline void SRC_AssertEIMReset(SRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SCR |= SRC_SCR_EIM_RST_MASK;
+ }
+ else
+ {
+ base->SCR &= ~SRC_SCR_EIM_RST_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_EIM_RST */
+
+/*!
+ * @brief Enable the WDOG Reset in SRC.
+ *
+ * WDOG Reset is enabled in SRC by default. If the WDOG event to SRC is masked, it would not create
+ * a reset to the chip. During the time the WDOG event is masked, when the WDOG event flag is
+ * asserted, it would remain asserted regardless of servicing the WDOG module. The only way to clear
+ * that bit is the hardware reset.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableWDOGReset(SRC_Type *base, bool enable)
+{
+ if (enable) /* WDOG Reset is not masked in SRC (default). */
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MWDR_MASK) | SRC_SCR_MWDR(0xA);
+ }
+ else /* WDOG Reset is masked in SRC. */
+ {
+ base->SCR = (base->SCR & ~SRC_SCR_MWDR_MASK) | SRC_SCR_MWDR(0x5);
+ }
+}
+
+#if !(defined(FSL_FEATURE_SRC_HAS_NO_SCR_WRBC) && FSL_FEATURE_SRC_HAS_NO_SCR_WRBC)
+/*!
+ * @brief Set the delay count of waiting MMDC's acknowledge.
+ *
+ * This function would define the 32KHz clock cycles to count before bypassing the MMDC acknowledge
+ * for WARM reset. If the MMDC acknowledge is not asserted before this counter is elapsed, a COLD
+ * reset will be initiated.
+ *
+ * @param base SRC peripheral base address.
+ * @param option The option of setting mode, see to #src_warm_reset_bypass_count_t.
+ */
+static inline void SRC_SetWarmResetBypassCount(SRC_Type *base, src_warm_reset_bypass_count_t option)
+{
+ base->SCR = (base->SCR & ~SRC_SCR_WRBC_MASK) | SRC_SCR_WRBC(option);
+}
+#endif /* FSL_FEATURE_SRC_HAS_NO_SCR_WRBC */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_LOCKUP_RST) && FSL_FEATURE_SRC_HAS_SCR_LOCKUP_RST)
+/*!
+ * @brief Enable the lockup reset.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableLockupReset(SRC_Type *base, bool enable)
+{
+ if (enable) /* Enable lockup reset. */
+ {
+ base->SCR |= SRC_SCR_LOCKUP_RST_MASK;
+ }
+ else /* Disable lockup reset. */
+ {
+ base->SCR &= ~SRC_SCR_LOCKUP_RST_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_LOCKUP_RST */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SCR_LUEN) && FSL_FEATURE_SRC_HAS_SCR_LUEN)
+/*!
+ * @brief Enable the core lockup reset.
+ *
+ * When enable the core luckup reset, the system would be reset when core luckup event happens.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the reset or not.
+ */
+static inline void SRC_EnableCoreLockupReset(SRC_Type *base, bool enable)
+{
+ if (enable) /* Core lockup will cause system reset. */
+ {
+ base->SCR |= SRC_SCR_LUEN_MASK;
+ }
+ else /* Core lockup will not cause system reset. */
+ {
+ base->SCR &= ~SRC_SCR_LUEN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_SCR_LUEN */
+
+#if !(defined(FSL_FEATURE_SRC_HAS_NO_SCR_WRE) && FSL_FEATURE_SRC_HAS_NO_SCR_WRE)
+/*!
+ * @brief Enable the WARM reset.
+ *
+ * Only when the WARM reset is enabled, the WARM reset requests would be served by WARM reset.
+ * Otherwise, all the WARM reset sources would generate COLD reset.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Enable the WARM reset or not.
+ */
+static inline void SRC_EnableWarmReset(SRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SCR |= SRC_SCR_WRE_MASK;
+ }
+ else
+ {
+ base->SCR &= ~SRC_SCR_WRE_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_NO_SCR_WRE */
+
+#if (defined(FSL_FEATURE_SRC_HAS_SISR) && FSL_FEATURE_SRC_HAS_SISR)
+/*!
+ * @brief Get interrupt status flags.
+ *
+ * @param base SRC peripheral base address.
+ * @return Mask value of status flags. See to $_src_status_flags.
+ */
+static inline uint32_t SRC_GetStatusFlags(SRC_Type *base)
+{
+ return base->SISR;
+}
+#endif /* FSL_FEATURE_SRC_HAS_SISR */
+
+/*!
+ * @brief Get the boot mode register 1 value.
+ *
+ * The Boot Mode register contains bits that reflect the status of BOOT_CFGx pins of the chip.
+ * See to chip-specific document for detail information about value.
+ *
+ * @param base SRC peripheral base address.
+ * @return status of BOOT_CFGx pins of the chip.
+ */
+static inline uint32_t SRC_GetBootModeWord1(SRC_Type *base)
+{
+ return base->SBMR1;
+}
+
+/*!
+ * @brief Get the boot mode register 2 value.
+ *
+ * The Boot Mode register contains bits that reflect the status of BOOT_MODEx Pins and fuse values
+ * that controls boot of the chip. See to chip-specific document for detail information about value.
+ *
+ * @param base SRC peripheral base address.
+ * @return status of BOOT_MODEx Pins and fuse values that controls boot of the chip.
+ */
+static inline uint32_t SRC_GetBootModeWord2(SRC_Type *base)
+{
+ return base->SBMR2;
+}
+
+#if !(defined(FSL_FEATURE_SRC_HAS_NO_SRSR_WBI) && FSL_FEATURE_SRC_HAS_NO_SRSR_WBI)
+/*!
+ * @brief Set the warm boot indication flag.
+ *
+ * WARM boot indication shows that WARM boot was initiated by software. This indicates to the
+ * software that it saved the needed information in the memory before initiating the WARM reset.
+ * In this case, software will set this bit to '1', before initiating the WARM reset. The warm_boot
+ * bit should be used as indication only after a warm_reset sequence. Software should clear this bit
+ * after warm_reset to indicate that the next warm_reset is not performed with warm_boot.
+ *
+ * @param base SRC peripheral base address.
+ * @param enable Assert the flag or not.
+ */
+static inline void SRC_SetWarmBootIndication(SRC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SRSR = (base->SRSR & ~SRC_SRSR_W1C_BITS_MASK) | SRC_SRSR_WBI_MASK;
+ }
+ else
+ {
+ base->SRSR = (base->SRSR & ~SRC_SRSR_W1C_BITS_MASK) & ~SRC_SRSR_WBI_MASK;
+ }
+}
+#endif /* FSL_FEATURE_SRC_HAS_NO_SRSR_WBI */
+
+/*!
+ * @brief Get the status flags of SRC.
+ *
+ * @param base SRC peripheral base address.
+ * @return Mask value of status flags, see to #_src_reset_status_flags.
+ */
+static inline uint32_t SRC_GetResetStatusFlags(SRC_Type *base)
+{
+ return base->SRSR;
+}
+
+/*!
+ * @brief Clear the status flags of SRC.
+ *
+ * @param base SRC peripheral base address.
+ * @param flags value of status flags to be cleared, see to #_src_reset_status_flags.
+ */
+void SRC_ClearResetStatusFlags(SRC_Type *base, uint32_t flags);
+
+/*!
+ * @brief Set value to general purpose registers.
+ *
+ * General purpose registers (GPRx) would hold the value during reset process. Wakeup function could
+ * be kept in these register. For example, the GPR1 holds the entry function for waking-up from
+ * Partial SLEEP mode while the GPR2 holds the argument. Other GPRx register would store the
+ * arbitray values.
+ *
+ * @param base SRC peripheral base address.
+ * @param index The index of GPRx register array. Note index 0 reponses the GPR1 register.
+ * @param value Setting value for GPRx register.
+ */
+static inline void SRC_SetGeneralPurposeRegister(SRC_Type *base, uint32_t index, uint32_t value)
+{
+ assert(index < SRC_GPR_COUNT);
+
+ base->GPR[index] = value;
+}
+
+/*!
+ * @brief Get the value from general purpose registers.
+ *
+ * @param base SRC peripheral base address.
+ * @param index The index of GPRx register array. Note index 0 reponses the GPR1 register.
+ * @return The setting value for GPRx register.
+ */
+static inline uint32_t SRC_GetGeneralPurposeRegister(SRC_Type *base, uint32_t index)
+{
+ assert(index < SRC_GPR_COUNT);
+
+ return base->GPR[index];
+}
+
+#if defined(__cplusplus)
+}
+#endif
+/*!
+ * @}
+ */
+#endif /* _FSL_SRC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.c b/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.c
new file mode 100644
index 0000000000..fce7c4d458
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2020-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_ssarc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.ssarc"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static void SSARC_MapDescriptorsToGroup(SSARC_LP_Type *base, uint8_t groupID, uint32_t startIndex, uint32_t endIndex);
+static void SSARC_SetGroupRestoreOrder(SSARC_LP_Type *base, uint8_t groupID, ssarc_save_restore_order_t order);
+static void SSARC_SetGroupSaveOrder(SSARC_LP_Type *base, uint8_t groupID, ssarc_save_restore_order_t order);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief Maps the descriptors to the selected group.
+ *
+ * @note One descriptor can be mapped to different group, but please make sure
+ * one descriptor can only be mapped to one power domain.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ * @param startIndex The index of the first descriptor of the group.
+ * @param endIndex The index of the last descriptor of the group.
+ */
+static void SSARC_MapDescriptorsToGroup(SSARC_LP_Type *base, uint8_t groupID, uint32_t startIndex, uint32_t endIndex)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+ assert((startIndex < endIndex) || (startIndex == endIndex));
+
+ base->GROUPS[groupID].DESC_CTRL0 = SSARC_LP_DESC_CTRL0_START(startIndex) | SSARC_LP_DESC_CTRL0_END(endIndex);
+}
+
+/*!
+ * @brief Set the order of descriptors within the group are processed when restoring register values.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ * @param order The restore order.
+ */
+static void SSARC_SetGroupRestoreOrder(SSARC_LP_Type *base, uint8_t groupID, ssarc_save_restore_order_t order)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ if (order == kSSARC_ProcessFromStartToEnd)
+ {
+ base->GROUPS[groupID].DESC_CTRL0 &= ~SSARC_LP_DESC_CTRL0_RT_ORDER_MASK;
+ }
+ else
+ {
+ base->GROUPS[groupID].DESC_CTRL0 |= SSARC_LP_DESC_CTRL0_RT_ORDER_MASK;
+ }
+}
+
+/*!
+ * @brief Set the order of descriptors within the group are processed when saving register values.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ * @param order The save order.
+ */
+static void SSARC_SetGroupSaveOrder(SSARC_LP_Type *base, uint8_t groupID, ssarc_save_restore_order_t order)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ if (order == kSSARC_ProcessFromStartToEnd)
+ {
+ base->GROUPS[groupID].DESC_CTRL0 &= ~SSARC_LP_DESC_CTRL0_SV_ORDER_MASK;
+ }
+ else
+ {
+ base->GROUPS[groupID].DESC_CTRL0 |= SSARC_LP_DESC_CTRL0_SV_ORDER_MASK;
+ }
+}
+
+/*!
+ * brief Sets the configuration of the descriptor.
+ *
+ * param base SSARC_HP peripheral base address.
+ * param index The index of descriptor. Range from 0 to 1023.
+ * param config Pointer to the structure ssarc_descriptor_config_t. Please refer to @ref ssarc_descriptor_config_t for
+ * details.
+ */
+void SSARC_SetDescriptorConfig(SSARC_HP_Type *base, uint32_t index, const ssarc_descriptor_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t temp32 = 0UL;
+
+ /* Set the address of the register to be saved/restored. */
+ base->DESC[index].SRAM0 = config->address;
+
+ temp32 = SSARC_HP_SRAM2_TYPE(config->type) | SSARC_HP_SRAM2_SIZE(config->size);
+ temp32 |= (uint32_t)(config->operation);
+
+ base->DESC[index].SRAM2 = temp32;
+
+ /* Set the value of the register to be saved/restored. */
+ /* If the type is set as kSSARC_ReadValueWriteBack, the SRAM1 register will be
+ loaded with the value on save operation, and the data in SRAM1 register will be over-written, so
+ it is no need to set SRAM1 register in that type. */
+ if (config->type != kSSARC_ReadValueWriteBack)
+ {
+ base->DESC[index].SRAM1 = config->data;
+ }
+}
+
+/*!
+ * brief Init the selected group.
+ *
+ * note For the groups with the same save priority or restore priority,
+ * the save/restore operation runs in the group order.
+ *
+ * param base SSARC_LP peripheral base address.
+ * param groupID The index of the group. Range from 0 to 15.
+ * param config Pointer to the structure ssarc_group_config_t. Please refer to @ref ssarc_group_config_t for details.
+ */
+void SSARC_GroupInit(SSARC_LP_Type *base, uint8_t groupID, const ssarc_group_config_t *config)
+{
+ assert(config != NULL);
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ uint32_t temp32;
+
+ temp32 = SSARC_LP_DESC_CTRL1_POWER_DOMAIN(config->powerDomain) |
+ SSARC_LP_DESC_CTRL1_SV_PRIORITY(config->savePriority) |
+ SSARC_LP_DESC_CTRL1_RT_PRIORITY(config->restorePriority) | SSARC_LP_DESC_CTRL1_CPUD(config->cpuDomain);
+ base->GROUPS[groupID].DESC_CTRL1 = temp32;
+
+ SSARC_MapDescriptorsToGroup(base, groupID, config->startIndex, config->endIndex);
+ SSARC_SetGroupRestoreOrder(base, groupID, config->restoreOrder);
+ SSARC_SetGroupSaveOrder(base, groupID, config->saveOrder);
+
+ /* Config the highest address and the lowest address. */
+ base->GROUPS[groupID].DESC_ADDR_UP = config->highestAddress;
+ base->GROUPS[groupID].DESC_ADDR_DOWN = config->lowestAddress;
+
+ /* Enable the group. */
+ base->GROUPS[groupID].DESC_CTRL1 |= SSARC_LP_DESC_CTRL1_GP_EN_MASK;
+}
+
+/*!
+ * brief Triggers software request.
+ *
+ * note Each group allows software to trigger the save/restore operation without getting the request
+ * from basic power controller.
+ *
+ * param base SSARC_LP peripheral base address.
+ * param groupID The index of the group. Range from 0 to 15.
+ * param mode. Software trigger mode. Please refer to @ref ssarc_software_trigger_mode_t for details.
+ */
+void SSARC_TriggerSoftwareRequest(SSARC_LP_Type *base, uint8_t groupID, ssarc_software_trigger_mode_t mode)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ base->GROUPS[groupID].DESC_CTRL1 |= (uint32_t)mode;
+
+ while (((base->GROUPS[groupID].DESC_CTRL1) & (uint32_t)mode) != 0UL)
+ {
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.h b/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.h
new file mode 100644
index 0000000000..02f49efa43
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/ssarc/fsl_ssarc.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright 2020-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SSARC_H_
+#define _FSL_SSARC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup ssarc
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief SSARC driver version 2.1.0. */
+#define FSL_SSARC_DRIVER_VERSION (MAKE_VERSION(2, 1, 0))
+/*@}*/
+
+#define SSARC_INT_STATUS_ALL \
+ (SSARC_LP_INT_STATUS_ADDR_ERR_MASK | SSARC_LP_INT_STATUS_AHB_ERR_MASK | SSARC_LP_INT_STATUS_SW_REQ_DONE_MASK | \
+ SSARC_LP_INT_STATUS_TIMEOUT_MASK | SSARC_LP_INT_STATUS_GROUP_CONFLICT_MASK)
+
+/*!
+ * @brief The enumeration of ssarc status flags.
+ */
+enum _ssarc_interrupt_status_flags
+{
+ kSSARC_AddressErrorFlag = SSARC_LP_INT_STATUS_ADDR_ERR_MASK, /*!< If the descriptor is not in the range,
+ assert address error. */
+ kSSARC_AHBErrorFlag = SSARC_LP_INT_STATUS_AHB_ERR_MASK, /*!< If any AHB master access receives none-OKAY,
+ assert AHB error. */
+ kSSARC_SoftwareRequestDoneFlag = SSARC_LP_INT_STATUS_SW_REQ_DONE_MASK, /*!< If a software triggered save or restore
+ process is completed, assert sofware
+ request done . */
+ kSSARC_TimeoutFlag = SSARC_LP_INT_STATUS_TIMEOUT_MASK, /*!< If processing of a group has exceeded the
+ timeout value, assert timeout. */
+ kSSARC_GroupConflictFlag = SSARC_LP_INT_STATUS_GROUP_CONFLICT_MASK, /*!< Group conflict. */
+};
+
+/*!
+ * @brief The size of the register to be saved/restored.
+ */
+typedef enum _ssarc_descriptor_register_size
+{
+ kSSARC_DescriptorRegister8bitWidth = 0x0U, /*!< The register to be saved/restored is 8 bit width. */
+ kSSARC_DescriptorRegister16bitWidth = 0x1U, /*!< The register to be saved/restored is 16 bit width. */
+ kSSARC_DescriptorRegister32bitWidth = 0x2U, /*!< The register to be saved/restored is 32 bit width. */
+} ssarc_descriptor_register_size_t;
+
+/*!
+ * @brief The operation of the descriptor.
+ */
+typedef enum _ssarc_descriptor_operation
+{
+ kSSARC_SaveDisableRestoreDisable = 0x0U, /*!< Disable Save operation, disable restore operation. */
+ kSSARC_SaveEnableRestoreDisable = SSARC_HP_SRAM2_SV_EN_MASK, /*!< Enable Save operation,
+ disable restore operation. */
+ kSSARC_SaveDisableRestoreEnable = SSARC_HP_SRAM2_RT_EN_MASK, /*!< Disable Save operation,
+ enable restore operation. */
+ kSSARC_SaveEnableRestoreEnable = (SSARC_HP_SRAM2_RT_EN_MASK | SSARC_HP_SRAM2_SV_EN_MASK),
+ /*!< Enable Save operation, enable restore operation. */
+} ssarc_descriptor_operation_t;
+
+/*!
+ * @brief The type of operation.
+ */
+typedef enum _ssarc_descriptor_type
+{
+ kSSARC_ReadValueWriteBack = 0x00U, /*!< Read the register value on save operation
+ and write it back on restore operation */
+ kSSARC_WriteFixedValue = 0x01U, /*!< Always write a fixed value from DATA[31:0] */
+ kSSARC_RMWOr = 0x02U, /*!< Read register, OR with the DATA[31:0], and write it back */
+ kSSARC_RMWAnd = 0x03U, /*!< Read register, AND with the DATA[31:0], and write it back */
+ kSSARC_DelayCycles = 0x04U, /*!< Delay for number of cycles based on the DATA[31:0] */
+ kSSARC_Polling0 = 0x05U, /*!< Read the register until read_data[31:0] & DATA[31:0] == 0 */
+ kSSARC_Polling1 = 0x06U, /*!< Read the register until read_data[31:0] & DATA[31:0] != 0 */
+} ssarc_descriptor_type_t;
+
+/*!
+ * @brief The order of the restore/save operation.
+ */
+typedef enum _ssarc_save_restore_order
+{
+ kSSARC_ProcessFromStartToEnd = 0U, /*!< Descriptors within the group are processed from start to end. */
+ kSSARC_ProcessFromEndToStart = 1U, /*!< Descriptors within the group are processed from end to start. */
+} ssarc_save_restore_order_t;
+
+/*!
+ * @brief Software trigger mode.
+ */
+typedef enum _ssarc_software_trigger_mode
+{
+ kSSARC_TriggerSaveRequest = SSARC_LP_DESC_CTRL1_SW_TRIG_SV_MASK, /*!< Don't trigger restore operation, trigger the
+ save operation by software. */
+ kSSARC_TriggerRestoreRequest = SSARC_LP_DESC_CTRL1_SW_TRIG_RT_MASK, /*!< Trigger the restore operation, don't
+ trigger the save operation. */
+} ssarc_software_trigger_mode_t;
+
+/*!
+ * @brief The configuration of descriptor.
+ */
+typedef struct _ssarc_descriptor_config
+{
+ uint32_t address; /*!< The address of the register/memory to be saved/restored. */
+ uint32_t data; /*!< The value of the register/memory to be saved/restored, please note that if the type
+ is selected as kSSARC_ReadValueWriteBack, this data field is useless. */
+ ssarc_descriptor_register_size_t size; /*!< The size of register to be saved/restored. */
+ ssarc_descriptor_operation_t operation; /*!< The operation mode of descriptor. */
+ ssarc_descriptor_type_t type; /*!< The type of operation. */
+} ssarc_descriptor_config_t;
+
+/*!
+ * @brief The configuration of the group.
+ */
+typedef struct _ssarc_group_config
+{
+ ssarc_cpu_domain_name_t cpuDomain; /*!< CPU domain, define the ownership of this group. */
+ uint32_t startIndex; /*!< The index of the first descriptor of the group. */
+ uint32_t endIndex; /*!< The index of the last descriptor of the group. */
+ ssarc_save_restore_order_t restoreOrder; /*!< The restore order. */
+ ssarc_save_restore_order_t saveOrder; /*!< The save order. */
+ uint8_t restorePriority; /*!< Restore priority of current group.
+ 0 is the highest priority, 15 is the lowest priority */
+ uint8_t savePriority; /*!< Save priority of current group.
+ 0 is the highest priority, 15 is the lowest priority. */
+ ssarc_power_domain_name_t powerDomain; /*!< Power domain. */
+ uint32_t highestAddress; /*!< Highest address that can be accessed for the descriptors in the group. */
+ uint32_t lowestAddress; /*!< Lowest address that can be accessed for the descriptors in the group. */
+} ssarc_group_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Descriptor related APIs.
+ * @{
+ */
+
+/*!
+ * @brief Gets the address of the register to be saved/restored.
+ *
+ * @param base SSARC_HP peripheral base address.
+ * @param index The index of descriptor. Range from 0 to 1023.
+ * @return The address of the register.
+ */
+static inline uint32_t SSARC_GetDescriptorRegisterAddress(SSARC_HP_Type *base, uint32_t index)
+{
+ assert(index < SSARC_HP_SRAM0_COUNT);
+
+ return (base->DESC[index].SRAM0);
+}
+
+/*!
+ * @brief Gets the value of the register to be saved/restored.
+ *
+ * @param base SSARC_HP peripheral base address.
+ * @param index The index of descriptor. Range from 0 to 1023.
+ * @return The value of the register.
+ */
+static inline uint32_t SSARC_GetDescriptorRegisterData(SSARC_HP_Type *base, uint32_t index)
+{
+ assert(index < SSARC_HP_SRAM0_COUNT);
+
+ return (base->DESC[index].SRAM1);
+}
+
+/*!
+ * @brief Sets the configuration of the descriptor.
+ *
+ * @param base SSARC_HP peripheral base address.
+ * @param index The index of descriptor. Range from 0 to 1023.
+ * @param config Pointer to the structure ssarc_descriptor_config_t. Please refer to @ref ssarc_descriptor_config_t for
+ * details.
+ */
+void SSARC_SetDescriptorConfig(SSARC_HP_Type *base, uint32_t index, const ssarc_descriptor_config_t *config);
+
+/*!
+ * @}
+ */
+
+/*!
+ * @name Group Related APIs
+ * @{
+ */
+
+/*!
+ * @brief Inits the selected group.
+ *
+ * @note For the groups with the same save priority or restore priority,
+ * the save/restore operation runs in the group order.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ * @param config Pointer to the structure ssarc_group_config_t. Please refer to @ref ssarc_group_config_t for details.
+ */
+void SSARC_GroupInit(SSARC_LP_Type *base, uint8_t groupID, const ssarc_group_config_t *config);
+
+/*!
+ * @brief De-inits the selected group.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ */
+static inline void SSARC_GroupDeinit(SSARC_LP_Type *base, uint8_t groupID)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ base->GROUPS[groupID].DESC_CTRL1 &= ~SSARC_LP_DESC_CTRL1_GP_EN_MASK;
+}
+
+/*!
+ * @brief Locks the configuration of the domain.
+ *
+ * This function locks the configuration of the domain. Once locked, only the access from the same domain is allowed,
+ * access from other domains will be blocked. Once locked, it can only be unlocked by a hardware reset.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ */
+static inline void SSARC_LockGroupDomain(SSARC_LP_Type *base, uint8_t groupID)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ base->GROUPS[groupID].DESC_CTRL1 |= SSARC_LP_DESC_CTRL1_DL_MASK;
+}
+
+/*!
+ * @brief Locks the write access to the control registers and descriptors for the selected group.
+ *
+ * This function Locks the write access to the control registers and descriptors for the selected group.
+ * All writes are blocked. Once locked, it can only be unlocked by a hardware reset.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ */
+static inline void SSARC_LockGroupWrite(SSARC_LP_Type *base, uint8_t groupID)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ base->GROUPS[groupID].DESC_CTRL1 |= SSARC_LP_DESC_CTRL1_WL_MASK;
+}
+
+/*!
+ * @brief Locks the read access to the control registers and descriptors for the selected group.
+ *
+ * This function Locks the read access to the control registers and descriptors for the selected group.
+ * All reads are blocked. Once locked, it can only be unlocked by a hardware reset.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ */
+static inline void SSARC_LockGroupRead(SSARC_LP_Type *base, uint8_t groupID)
+{
+ assert(groupID < SSARC_LP_DESC_CTRL0_COUNT);
+
+ base->GROUPS[groupID].DESC_CTRL1 |= SSARC_LP_DESC_CTRL1_RL_MASK;
+}
+
+/*!
+ * @brief Triggers software request.
+ *
+ * @note Each group allows software to trigger the save/restore operation without getting the request
+ * from basic power controller.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param groupID The index of the group. Range from 0 to 15.
+ * @param mode Software trigger mode. Please refer to @ref ssarc_software_trigger_mode_t for details.
+ */
+void SSARC_TriggerSoftwareRequest(SSARC_LP_Type *base, uint8_t groupID, ssarc_software_trigger_mode_t mode);
+
+/*!
+ * @}
+ */
+
+/*!
+ * @name Global Setting Related APIs
+ */
+
+/*!
+ * @brief Resets the whole SSARC block by software.
+ *
+ * @note Only reset the SSARC registers, not include the DESC in SRAM.
+ *
+ * @param base SSARC_LP peripheral base address.
+ */
+static inline void SSARC_ResetWholeBlock(SSARC_LP_Type *base)
+{
+ base->CTRL |= SSARC_LP_CTRL_SW_RESET_MASK;
+ base->CTRL &= ~SSARC_LP_CTRL_SW_RESET_MASK;
+}
+
+/*!
+ * @brief Enables/Disables save/restore request from the PGMC module.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param enable Used to enable/disable save/restore hardware request.
+ * - \b true Enable GPC save/restore requests.
+ * - \b false Disable GPC save/restore requests.
+ */
+static inline void SSARC_EnableHardwareRequest(SSARC_LP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL &= ~SSARC_LP_CTRL_DIS_HW_REQ_MASK;
+ }
+ else
+ {
+ base->CTRL |= SSARC_LP_CTRL_DIS_HW_REQ_MASK;
+ }
+}
+
+/*!
+ * @}
+ */
+
+/*!
+ * @name Status Related APIs
+ * @{
+ */
+
+/*!
+ * @brief Gets status flags.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The value of status flags. See @ref _ssarc_interrupt_status_flags for details.
+ */
+static inline uint32_t SSARC_GetStatusFlags(SSARC_LP_Type *base)
+{
+ return ((base->INT_STATUS) & SSARC_INT_STATUS_ALL);
+}
+
+/*!
+ * @brief Clears status flags.
+ *
+ * @note Only @ref kSSARC_AddressErrorFlag, @ref kSSARC_AHBErrorFlag, @ref kSSARC_TimeoutFlag and
+ * @ref kSSARC_GroupConflictFlag can be cleared.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param mask The mask value for flags to be cleared. See @ref _ssarc_interrupt_status_flags for details.
+ */
+
+static inline void SSARC_ClearStatusFlags(SSARC_LP_Type *base, uint32_t mask)
+{
+ base->INT_STATUS = mask;
+}
+
+/*!
+ * @brief Gets the error index that indicates which descriptor will trigger the AHB_ERR or ADDR_ERR interrupt.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The error index.
+ */
+static inline uint32_t SSARC_GetErrorIndex(SSARC_LP_Type *base)
+{
+ return (base->INT_STATUS & SSARC_LP_INT_STATUS_ERR_INDEX_MASK);
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Time Out Related APIs
+ * @{
+ */
+
+/*!
+ * @brief Sets timeout value for the entire group to complete.
+ *
+ * This function sets timeout value for the entire group to complete. Setting timeout value
+ * to 0 will disable this feature.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @param value The timeout value, 0 means disable time out feature.
+ */
+static inline void SSARC_SetTimeoutValue(SSARC_LP_Type *base, uint32_t value)
+{
+ base->HP_TIMEOUT = value;
+}
+
+/*!
+ * @brief Gets timeout value for AHB clock.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The timeout value.
+ */
+static inline uint32_t SSARC_GetTimeoutValue(SSARC_LP_Type *base)
+{
+ return base->HP_TIMEOUT;
+}
+
+/*!
+ * @}
+ */
+
+/*!
+ * @name Pending Group Related APIs
+ */
+
+/*!
+ * @brief Gets the value that indicates which groups are pending for restore from hardware request.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The value of the pending groups.
+ */
+static inline uint16_t SSARC_GetHardwareRequestRestorePendingGroup(SSARC_LP_Type *base)
+{
+ return (uint16_t)(((base->HW_GROUP_PENDING) & SSARC_LP_HW_GROUP_PENDING_HW_RESTORE_PENDING_MASK) >>
+ SSARC_LP_HW_GROUP_PENDING_HW_RESTORE_PENDING_SHIFT);
+}
+
+/*!
+ * @brief Gets the value that indicates which groups are pending for save from hardware request.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The value of the pending groups.
+ */
+static inline uint16_t SSARC_GetHardwareRequestSavePendingGroup(SSARC_LP_Type *base)
+{
+ return (uint16_t)(((base->HW_GROUP_PENDING) & SSARC_LP_HW_GROUP_PENDING_HW_SAVE_PENDING_MASK) >>
+ SSARC_LP_HW_GROUP_PENDING_HW_SAVE_PENDING_SHIFT);
+}
+
+/*!
+ * @brief Gets the value that indicates which groups are pending for restore from software request.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The value of the pending groups.
+ */
+static inline uint16_t SSARC_GetSoftwareRequestRestorePendingGroup(SSARC_LP_Type *base)
+{
+ return (uint16_t)(((base->SW_GROUP_PENDING) & SSARC_LP_SW_GROUP_PENDING_SW_RESTORE_PENDING_MASK) >>
+ SSARC_LP_SW_GROUP_PENDING_SW_RESTORE_PENDING_SHIFT);
+}
+
+/*!
+ * @brief Gets the value that indicates which groups are pending for save from software request.
+ *
+ * @param base SSARC_LP peripheral base address.
+ * @return The value of the pending groups.
+ */
+static inline uint16_t SSARC_GetSoftwareRequestSavePendingGroup(SSARC_LP_Type *base)
+{
+ return (uint16_t)(((base->SW_GROUP_PENDING) & SSARC_LP_SW_GROUP_PENDING_SW_SAVE_PENDING_MASK) >>
+ SSARC_LP_SW_GROUP_PENDING_SW_SAVE_PENDING_SHIFT);
+}
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_SSARC_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.c b/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.c
new file mode 100644
index 0000000000..c0486bd6d7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2018-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_tempmon.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.tempmon"
+#endif
+
+/*! @brief TEMPMON calibration data mask. */
+#define TEMPMON_HOTTEMPMASK 0xFFU
+#define TEMPMON_HOTTEMPSHIFT 0x00U
+#define TEMPMON_HOTCOUNTMASK 0xFFF00U
+#define TEMPMON_HOTCOUNTSHIFT 0X08U
+#define TEMPMON_ROOMCOUNTMASK 0xFFF00000U
+#define TEMPMON_ROOMCOUNTSHIFT 0x14U
+
+/*! @brief the room temperature. */
+#define TEMPMON_ROOMTEMP 25.0f
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+static int32_t s_hotTemp; /*!< The value of TEMPMON_TEMPSENSE0[TEMP_VALUE] at room temperature .*/
+static int32_t s_hotCount; /*!< The value of TEMPMON_TEMPSENSE0[TEMP_VALUE] at the hot temperature.*/
+static float s_hotT_ROOM; /*!< The value of s_hotTemp minus room temperature(25 degrees celsius).*/
+static int32_t s_roomC_hotC; /*!< The value of s_roomCount minus s_hotCount.*/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Initializes the TEMPMON module.
+ *
+ * param base TEMPMON base pointer
+ * param config Pointer to configuration structure.
+ */
+void TEMPMON_Init(TEMPMON_Type *base, const tempmon_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t calibrationData;
+ uint32_t tmpU32;
+ int32_t roomCount;
+
+ /* Power on the temperature sensor*/
+ base->TEMPSENSE0 &= ~TEMPMON_TEMPSENSE0_POWER_DOWN_MASK;
+
+ /* Set temperature monitor frequency */
+ base->TEMPSENSE1 = TEMPMON_TEMPSENSE1_MEASURE_FREQ(config->frequency);
+
+ /* ready to read calibration data */
+ calibrationData = OCOTP->ANA1;
+ tmpU32 = (calibrationData & TEMPMON_HOTTEMPMASK) >> TEMPMON_HOTTEMPSHIFT;
+ s_hotTemp = (int32_t)tmpU32;
+
+ tmpU32 = (calibrationData & TEMPMON_HOTCOUNTMASK) >> TEMPMON_HOTCOUNTSHIFT;
+ s_hotCount = (int32_t)tmpU32;
+
+ tmpU32 = (calibrationData & TEMPMON_ROOMCOUNTMASK) >> TEMPMON_ROOMCOUNTSHIFT;
+ roomCount = (int32_t)tmpU32;
+
+ s_hotT_ROOM = (float)s_hotTemp - TEMPMON_ROOMTEMP;
+ s_roomC_hotC = roomCount - s_hotCount;
+
+ /* Set alarm temperature */
+ TEMPMON_SetTempAlarm(base, config->highAlarmTemp, kTEMPMON_HighAlarmMode);
+ TEMPMON_SetTempAlarm(base, config->panicAlarmTemp, kTEMPMON_PanicAlarmMode);
+ TEMPMON_SetTempAlarm(base, config->lowAlarmTemp, kTEMPMON_LowAlarmMode);
+}
+
+/*!
+ * brief Deinitializes the TEMPMON module.
+ *
+ * param base TEMPMON base pointer
+ */
+void TEMPMON_Deinit(TEMPMON_Type *base)
+{
+ base->TEMPSENSE0 |= TEMPMON_TEMPSENSE0_POWER_DOWN_MASK;
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the TEMPMON configuration structure to a default value. The default
+ * values are:
+ * tempmonConfig->frequency = 0x02U;
+ * tempmonConfig->highAlarmTemp = 44U;
+ * tempmonConfig->panicAlarmTemp = 90U;
+ * tempmonConfig->lowAlarmTemp = 39U;
+ *
+ * param config Pointer to a configuration structure.
+ */
+void TEMPMON_GetDefaultConfig(tempmon_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Default measure frequency */
+ config->frequency = 0x03U;
+ /* Default high alarm temperature */
+ config->highAlarmTemp = 40;
+ /* Default panic alarm temperature */
+ config->panicAlarmTemp = 90;
+ /* Default low alarm temperature */
+ config->lowAlarmTemp = 20;
+}
+
+/*!
+ * brief Get current temperature with the fused temperature calibration data.
+ *
+ * param base TEMPMON base pointer
+ * return current temperature with degrees Celsius.
+ */
+float TEMPMON_GetCurrentTemperature(TEMPMON_Type *base)
+{
+ /* Check arguments */
+ assert(NULL != base);
+
+ uint32_t nmeas;
+ float tmeas;
+
+ while (0U == (base->TEMPSENSE0 & TEMPMON_TEMPSENSE0_FINISHED_MASK))
+ {
+ }
+
+ /* ready to read temperature code value */
+ nmeas = (base->TEMPSENSE0 & TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >> TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT;
+
+ /* Calculate temperature */
+ tmeas = (float)s_hotTemp - (((float)nmeas - (float)s_hotCount) * (s_hotT_ROOM / (float)s_roomC_hotC));
+
+ return tmeas;
+}
+
+/*!
+ * brief Set the temperature count (raw sensor output) that will generate an alarm interrupt.
+ *
+ * param base TEMPMON base pointer
+ * param tempVal The alarm temperature with degrees Celsius
+ * param alarmMode The alarm mode.
+ */
+void TEMPMON_SetTempAlarm(TEMPMON_Type *base, int8_t tempVal, tempmon_alarm_mode alarmMode)
+{
+ /* Check arguments */
+ assert(NULL != base);
+ /* Different SOC has different qualified temperature level based on AEC-Q100 standard by default, such as Consumer(0
+ to +95 degrees celsius)/Industrial(-40 to +105 degrees celsius)/Automotive(-40 to +125 degrees celsius). */
+ assert(s_hotTemp >= tempVal);
+
+ int32_t tempCodeVal;
+ uint32_t tempRegVal;
+
+ /* Calculate alarm temperature code value */
+ tempCodeVal = s_hotCount + (s_hotTemp - (int32_t)tempVal) * s_roomC_hotC / (int32_t)s_hotT_ROOM;
+
+ switch (alarmMode)
+ {
+ case kTEMPMON_HighAlarmMode:
+ /* Clear alarm value and set a new high alarm temperature code value */
+ tempRegVal = base->TEMPSENSE0;
+ tempRegVal =
+ (tempRegVal & ~TEMPMON_TEMPSENSE0_ALARM_VALUE_MASK) | TEMPMON_TEMPSENSE0_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE0 = tempRegVal;
+ break;
+
+ case kTEMPMON_PanicAlarmMode:
+ /* Clear panic alarm value and set a new panic alarm temperature code value */
+ tempRegVal = base->TEMPSENSE2;
+ tempRegVal = (tempRegVal & ~TEMPMON_TEMPSENSE2_PANIC_ALARM_VALUE_MASK) |
+ TEMPMON_TEMPSENSE2_PANIC_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE2 = tempRegVal;
+ break;
+
+ case kTEMPMON_LowAlarmMode:
+ /* Clear low alarm value and set a new low alarm temperature code value */
+ tempRegVal = base->TEMPSENSE2;
+ tempRegVal = (tempRegVal & ~TEMPMON_TEMPSENSE2_LOW_ALARM_VALUE_MASK) |
+ TEMPMON_TEMPSENSE2_LOW_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE2 = tempRegVal;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.h b/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.h
new file mode 100644
index 0000000000..bb453de2a3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/tempmon/fsl_tempmon.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018-2021 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_TEMPMON_H_
+#define _FSL_TEMPMON_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup tempmon
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief TEMPMON driver version. */
+#define FSL_TEMPMON_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+
+/*! @brief TEMPMON temperature structure. */
+typedef struct _tempmon_config
+{
+ uint16_t frequency; /*!< The temperature measure frequency.*/
+ int8_t highAlarmTemp; /*!< The high alarm temperature.*/
+ int8_t panicAlarmTemp; /*!< The panic alarm temperature.*/
+ int8_t lowAlarmTemp; /*!< The low alarm temperature.*/
+} tempmon_config_t;
+
+/*! @brief TEMPMON alarm mode. */
+typedef enum _tempmon_alarm_mode
+{
+ kTEMPMON_HighAlarmMode = 0U, /*!< The high alarm temperature interrupt mode.*/
+ kTEMPMON_PanicAlarmMode = 1U, /*!< The panic alarm temperature interrupt mode.*/
+ kTEMPMON_LowAlarmMode = 2U, /*!< The low alarm temperature interrupt mode.*/
+} tempmon_alarm_mode;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the TEMPMON module.
+ *
+ * @param base TEMPMON base pointer
+ * @param config Pointer to configuration structure.
+ */
+void TEMPMON_Init(TEMPMON_Type *base, const tempmon_config_t *config);
+
+/*!
+ * @brief Deinitializes the TEMPMON module.
+ *
+ * @param base TEMPMON base pointer
+ */
+void TEMPMON_Deinit(TEMPMON_Type *base);
+
+/*!
+ * @brief Gets the default configuration structure.
+ *
+ * This function initializes the TEMPMON configuration structure to a default value. The default
+ * values are:
+ * tempmonConfig->frequency = 0x02U;
+ * tempmonConfig->highAlarmTemp = 44U;
+ * tempmonConfig->panicAlarmTemp = 90U;
+ * tempmonConfig->lowAlarmTemp = 39U;
+ *
+ * @param config Pointer to a configuration structure.
+ */
+void TEMPMON_GetDefaultConfig(tempmon_config_t *config);
+
+/*!
+ * @brief start the temperature measurement process.
+ *
+ * @param base TEMPMON base pointer.
+ */
+static inline void TEMPMON_StartMeasure(TEMPMON_Type *base)
+{
+ base->TEMPSENSE0 |= TEMPMON_TEMPSENSE0_MEASURE_TEMP_MASK;
+}
+
+/*!
+ * @brief stop the measurement process.
+ *
+ * @param base TEMPMON base pointer
+ */
+static inline void TEMPMON_StopMeasure(TEMPMON_Type *base)
+{
+ base->TEMPSENSE0 &= ~TEMPMON_TEMPSENSE0_MEASURE_TEMP_MASK;
+}
+
+/*!
+ * @brief Get current temperature with the fused temperature calibration data.
+ *
+ * @param base TEMPMON base pointer
+ * @return current temperature with degrees Celsius.
+ */
+float TEMPMON_GetCurrentTemperature(TEMPMON_Type *base);
+
+/*!
+ * @brief Set the temperature count (raw sensor output) that will generate an alarm interrupt.
+ *
+ * @param base TEMPMON base pointer
+ * @param tempVal The alarm temperature with degrees Celsius
+ * @param alarmMode The alarm mode.
+ */
+void TEMPMON_SetTempAlarm(TEMPMON_Type *base, int8_t tempVal, tempmon_alarm_mode alarmMode);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_TEMPMON_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.c b/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.c
new file mode 100644
index 0000000000..fa6a5cc0c4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_tempsensor.h"
+#include "math.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.tempsensor"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+static void TMPSNS_AIWriteAccess(uint32_t address, uint32_t data);
+static uint32_t TMPSNS_AIReadAccess(uint32_t address);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+const static float s_Ts20 = 133.6f;
+const static float s_Ts21 = -5.39f;
+const static float s_Ts21_2 = 29.0521f; /*!< It means (s_Ts21* s_Ts21) */
+const static float s_Ts22 = 0.002f;
+static float s_Ts25c;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Initializes the TMPSNS module.
+ *
+ * param base TMPSNS base pointer
+ * param config Pointer to configuration structure.
+ */
+
+void TMPSNS_Init(TMPSNS_Type *base, const tmpsns_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t controlVal = 0x00U;
+ uint32_t temp;
+
+ temp =
+ (ANADIG_TEMPSENSOR_TEMPSNS_OTP_TRIM_VALUE_TEMPSNS_TEMP_VAL_MASK & ANADIG_TEMPSENSOR->TEMPSNS_OTP_TRIM_VALUE) >>
+ 10;
+ s_Ts25c = (float)temp;
+
+ /* Select normal temperature measuring mode */
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ controlVal = TMPSNS_AIReadAccess((uint32_t) & (base->CTRL0));
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL0), controlVal & (~TMPSNS_CTRL0_V_SEL_MASK));
+#else
+ base->CTRL0 &= ~TMPSNS_CTRL0_V_SEL_MASK;
+#endif
+
+ if (config->measureMode == kTEMPSENSOR_SingleMode)
+ {
+ controlVal = TMPSNS_CTRL1_FREQ(0x00U);
+ }
+ else if (config->measureMode == kTEMPSENSOR_ContinuousMode)
+ {
+ controlVal = TMPSNS_CTRL1_FREQ(config->frequency);
+ }
+ else
+ {
+ ; /* Intentional empty for MISRA C-2012 rule 15.7*/
+ }
+
+ /* Enable finish interrupt status */
+ controlVal |= TMPSNS_CTRL1_FINISH_IE_MASK;
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ /* Power up the temperature sensor */
+ controlVal &= ~TMPSNS_CTRL1_PWD_MASK;
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), controlVal);
+#else
+ base->CTRL1 |= controlVal;
+ /* Power up the temperature sensor */
+ base->CTRL1 &= ~TMPSNS_CTRL1_PWD_MASK;
+#endif
+
+ /* Set alarm temperature */
+ TMPSNS_SetTempAlarm(base, config->highAlarmTemp, kTEMPMON_HighAlarmMode);
+ TMPSNS_SetTempAlarm(base, config->panicAlarmTemp, kTEMPMON_PanicAlarmMode);
+ TMPSNS_SetTempAlarm(base, config->lowAlarmTemp, kTEMPMON_LowAlarmMode);
+}
+
+/*!
+ * brief Deinitializes the TMPSNS module.
+ *
+ * param base TMPSNS base pointer
+ */
+void TMPSNS_Deinit(TMPSNS_Type *base)
+{
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), TMPSNS_CTRL1_PWD_MASK);
+#else
+ base->CTRL1 |= TMPSNS_CTRL1_PWD_MASK;
+#endif
+}
+
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+/*!
+ * brief AI interface write access.
+ *
+ * param base TMPSNS base pointer
+ */
+static void TMPSNS_AIWriteAccess(uint32_t address, uint32_t data)
+{
+ /* AI bridge setting: AIRWB and ADDR
+ Write: 0x00
+ Address: offset from base address
+ */
+ ANADIG_MISC->VDDLPSR_AI_CTRL = (0x00UL << 16) | (address & 0xFFFFU);
+ /* Write data into related register through AI bridge */
+ ANADIG_MISC->VDDLPSR_AI_WDATA = data;
+ /* AI toggle */
+ ANADIG_TEMPSENSOR->TEMPSENSOR ^= ANADIG_TEMPSENSOR_TEMPSENSOR_TEMPSNS_AI_TOGGLE_MASK;
+}
+
+/*!
+ * brief AI interface read access.
+ *
+ * param base TMPSNS base pointer
+ */
+static uint32_t TMPSNS_AIReadAccess(uint32_t address)
+{
+ uint32_t ret;
+
+ /* AI bridge setting: AIRWB and ADDR
+ Read: 0x01
+ Address: offset from base address
+ */
+ ANADIG_MISC->VDDLPSR_AI_CTRL = (0x01UL << 16) | (address & 0xFFFFU);
+ /* AI toggle */
+ ANADIG_TEMPSENSOR->TEMPSENSOR ^= ANADIG_TEMPSENSOR_TEMPSENSOR_TEMPSNS_AI_TOGGLE_MASK;
+ /* Read data from related register through AI bridge */
+ ret = ANADIG_MISC->VDDLPSR_AI_RDATA_TMPSNS;
+
+ return ret;
+}
+#endif /* FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE */
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the TMPSNS configuration structure to a default value. The default
+ * values are:
+ * tempmonConfig->frequency = 0x00U;
+ * tempmonConfig->highAlarmTemp = 25U;
+ * tempmonConfig->panicAlarmTemp = 80U;
+ * tempmonConfig->lowAlarmTemp = 20U;
+ *
+ * param config Pointer to a configuration structure.
+ */
+void TMPSNS_GetDefaultConfig(tmpsns_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Default measurement mode */
+ config->measureMode = kTEMPSENSOR_SingleMode;
+ /* Default measure frequency */
+ config->frequency = 0x00U;
+ /* Default high alarm temperature */
+ config->highAlarmTemp = 25;
+ /* Default panic alarm temperature */
+ config->panicAlarmTemp = 80;
+ /* Default low alarm temperature */
+ config->lowAlarmTemp = 5;
+}
+
+/*!
+ * @brief start the temperature measurement process.
+ *
+ * @param base TMPSNS base pointer.
+ */
+void TMPSNS_StartMeasure(TMPSNS_Type *base)
+{
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ uint32_t controlVal;
+ /* Read CTRL1 value*/
+ controlVal = TMPSNS_AIReadAccess((uint32_t) & (base->CTRL1));
+ /* Start measurement */
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), controlVal | TMPSNS_CTRL1_SET_START_MASK);
+#else
+ base->CTRL1 |= TMPSNS_CTRL1_SET_START_MASK;
+#endif
+}
+
+/*!
+ * @brief stop the measurement process.
+ *
+ * @param base TMPSNS base pointer
+ */
+void TMPSNS_StopMeasure(TMPSNS_Type *base)
+{
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ uint32_t controlVal;
+ /* Read CTRL1 value*/
+ controlVal = TMPSNS_AIReadAccess((uint32_t) & (base->CTRL1));
+ /* Start measurement */
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), controlVal & (~TMPSNS_CTRL1_SET_START_MASK));
+#else
+ base->CTRL1 &= ~TMPSNS_CTRL1_SET_START_MASK;
+#endif
+}
+
+/*!
+ * brief Get current temperature with the fused temperature calibration data.
+ *
+ * param base TMPSNS base pointer
+ * return current temperature with degrees Celsius.
+ */
+float TMPSNS_GetCurrentTemperature(TMPSNS_Type *base)
+{
+ uint32_t measureTempVal;
+ float actualTempVal;
+
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ /* Waiting for measurement finished */
+ while (0U == (TMPSNS_AIReadAccess((uint32_t) & (base->STATUS0)) & TMPSNS_STATUS0_FINISH_MASK))
+ {
+ }
+ /* Ready to read measured temperature value */
+ measureTempVal = (TMPSNS_AIReadAccess((uint32_t) & (base->STATUS0)) & TMPSNS_STATUS0_TEMP_VAL_MASK) >>
+ TMPSNS_STATUS0_TEMP_VAL_SHIFT;
+#else
+ /* Waiting for measurement finished */
+ while (0U == (base->STATUS0 & TMPSNS_STATUS0_FINISH_MASK))
+ {
+ }
+ /* Ready to read measured temperature value */
+ measureTempVal = (base->STATUS0 & TMPSNS_STATUS0_TEMP_VAL_MASK) >> TMPSNS_STATUS0_TEMP_VAL_SHIFT;
+#endif
+
+ /* Calculate actual temperature */
+ actualTempVal =
+ (-s_Ts21 - sqrtf(s_Ts21_2 - 4.0f * s_Ts22 * (s_Ts20 + s_Ts25c - (float)measureTempVal))) / (2.0f * s_Ts22);
+
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ uint32_t statusVal;
+ /* Read STATUS0 value */
+ statusVal = TMPSNS_AIReadAccess((uint32_t) & (base->STATUS0));
+ /* Clear the FINISH flag */
+ TMPSNS_AIWriteAccess((uint32_t) & (base->STATUS0), statusVal | TMPSNS_STATUS0_FINISH_MASK);
+#else
+ /* Clear the FINISH flag */
+ base->STATUS0 |= TMPSNS_STATUS0_FINISH_MASK;
+#endif
+
+ return actualTempVal;
+}
+
+/*!
+ * brief Set the temperature count (raw sensor output) that will generate an alarm interrupt.
+ *
+ * param base TMPSNS base pointer
+ * param tempVal The alarm temperature with degrees Celsius
+ * param alarmMode The alarm mode.
+ */
+void TMPSNS_SetTempAlarm(TMPSNS_Type *base, int32_t tempVal, tmpsns_alarm_mode_t alarmMode)
+{
+ float temp;
+ int32_t tempCodeVal;
+ uint32_t tempRegVal;
+
+ /* Calculate alarm temperature code value */;
+ temp = (-2.0f * s_Ts22 * (float)tempVal - s_Ts21) * (-2.0f * s_Ts22 * (float)tempVal - s_Ts21);
+ temp = (temp - (s_Ts21_2 - 4.0f * s_Ts22 * (s_Ts20 + s_Ts25c))) / (4.0f * s_Ts22);
+ tempCodeVal = (int32_t)temp;
+
+ switch (alarmMode)
+ {
+ case kTEMPMON_HighAlarmMode:
+ /* Clear alarm value and set a new high alarm temperature code value */
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ tempRegVal = TMPSNS_AIReadAccess((uint32_t) & (base->RANGE0));
+ tempRegVal = (tempRegVal & ~TMPSNS_RANGE0_HIGH_TEMP_VAL_MASK) | TMPSNS_RANGE0_HIGH_TEMP_VAL(tempCodeVal);
+ TMPSNS_AIWriteAccess((uint32_t) & (base->RANGE0), tempRegVal);
+#else
+ tempRegVal = (base->RANGE0 & ~TMPSNS_RANGE0_HIGH_TEMP_VAL_MASK) | TMPSNS_RANGE0_HIGH_TEMP_VAL(tempCodeVal);
+ base->RANGE0 = tempRegVal;
+#endif
+ /* Enable high temperature interrupt */
+ TMPSNS_EnableInterrupt(base, kTEMPSENSOR_HighTempInterruptStatusEnable);
+ break;
+
+ case kTEMPMON_PanicAlarmMode:
+ /* Clear panic alarm value and set a new panic alarm temperature code value */
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ tempRegVal = TMPSNS_AIReadAccess((uint32_t) & (base->RANGE1));
+ tempRegVal = (tempRegVal & ~TMPSNS_RANGE1_PANIC_TEMP_VAL_MASK) | TMPSNS_RANGE1_PANIC_TEMP_VAL(tempCodeVal);
+ TMPSNS_AIWriteAccess((uint32_t) & (base->RANGE1), tempRegVal);
+#else
+ tempRegVal =
+ (base->RANGE1 & ~TMPSNS_RANGE1_PANIC_TEMP_VAL_MASK) | TMPSNS_RANGE1_PANIC_TEMP_VAL(tempCodeVal);
+ base->RANGE1 = tempRegVal;
+#endif
+ /* Enable panic temperature interrupt */
+ TMPSNS_EnableInterrupt(base, kTEMPSENSOR_PanicTempInterruptStatusEnable);
+ break;
+
+ case kTEMPMON_LowAlarmMode:
+ /* Clear low alarm value and set a new low alarm temperature code value */
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ tempRegVal = TMPSNS_AIReadAccess((uint32_t) & (base->RANGE0));
+ tempRegVal = (tempRegVal & ~TMPSNS_RANGE0_LOW_TEMP_VAL_MASK) | TMPSNS_RANGE0_LOW_TEMP_VAL(tempCodeVal);
+ TMPSNS_AIWriteAccess((uint32_t) & (base->RANGE0_SET), tempRegVal);
+#else
+ tempRegVal = (base->RANGE0 & ~TMPSNS_RANGE0_LOW_TEMP_VAL_MASK) | TMPSNS_RANGE0_LOW_TEMP_VAL(tempCodeVal);
+ base->RANGE0 = tempRegVal;
+#endif
+ /* Enable low temperature interrupt */
+ TMPSNS_EnableInterrupt(base, kTEMPSENSOR_LowTempInterruptStatusEnable);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Enable interrupt status.
+ *
+ * param base TMPSNS base pointer
+ * param mask The interrupts to enable from tmpsns_interrupt_status_enable_t.
+ */
+void TMPSNS_EnableInterrupt(TMPSNS_Type *base, uint32_t mask)
+{
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ uint32_t tempRegVal;
+ tempRegVal = TMPSNS_AIReadAccess((uint32_t) & (base->CTRL1));
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), tempRegVal | mask);
+#else
+ base->CTRL1 |= mask;
+#endif
+}
+
+/*!
+ * brief Disable interrupt status.
+ *
+ * param base TMPSNS base pointer
+ * param mask The interrupts to disable from tmpsns_interrupt_status_enable_t.
+ */
+void TMPSNS_DisableInterrupt(TMPSNS_Type *base, uint32_t mask)
+{
+#if defined(FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE) && FSL_FEATURE_TMPSNS_HAS_AI_INTERFACE
+ uint32_t tempRegVal;
+ tempRegVal = TMPSNS_AIReadAccess((uint32_t) & (base->CTRL1));
+ TMPSNS_AIWriteAccess((uint32_t) & (base->CTRL1), tempRegVal & (~mask));
+#else
+ base->CTRL1 &= ~mask;
+#endif
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.h b/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.h
new file mode 100644
index 0000000000..3474685f41
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/tempsensor/fsl_tempsensor.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_TEMPMON_H_
+#define _FSL_TEMPMON_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup tempsensor
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_TMPSNS_DRIVER_VERSION (MAKE_VERSION(2, 1, 0))
+/*@}*/
+
+/*! @brief TMPSNS interrupt status enable type, tmpsns_interrupt_status_enable_t. */
+enum
+{
+ kTEMPSENSOR_HighTempInterruptStatusEnable =
+ TMPSNS_CTRL1_HIGH_TEMP_IE_MASK, /*!< High temperature interrupt status enable.*/
+ kTEMPSENSOR_LowTempInterruptStatusEnable =
+ TMPSNS_CTRL1_LOW_TEMP_IE_MASK, /*!< Low temperature interrupt status enable.*/
+ kTEMPSENSOR_PanicTempInterruptStatusEnable =
+ TMPSNS_CTRL1_PANIC_TEMP_IE_MASK, /*!< Panic temperature interrupt status enable.*/
+ kTEMPSENSOR_FinishInterruptStatusEnable = TMPSNS_CTRL1_FINISH_IE_MASK, /*!< Finish interrupt enable.*/
+};
+
+/*! @brief TMPSNS interrupt status type, tmpsns_interrupt_status_t. */
+enum
+{
+ kTEMPSENSOR_HighTempInterruptStatus = TMPSNS_STATUS0_HIGH_TEMP_MASK, /*!< High temperature interrupt status.*/
+ kTEMPSENSOR_LowTempInterruptStatus = TMPSNS_STATUS0_LOW_TEMP_MASK, /*!< Low temperature interrupt status.*/
+ kTEMPSENSOR_PanicTempInterruptStatus = TMPSNS_STATUS0_PANIC_TEMP_MASK, /*!< Panic temperature interrupt status.*/
+};
+
+/*! @brief TMPSNS measure mode, tempsensor_measure_mode. */
+typedef enum
+{
+ kTEMPSENSOR_SingleMode = 0U, /*!< Single measurement mode.*/
+ kTEMPSENSOR_ContinuousMode = 1U, /*!< Continuous measurement mode.*/
+} tmpsns_measure_mode_t;
+
+/*! @brief TMPSNS temperature structure. */
+typedef struct _tmpsns_config
+{
+ tmpsns_measure_mode_t measureMode; /*!< The temperature measure mode.*/
+ uint16_t frequency; /*!< The temperature measure frequency.*/
+ int32_t highAlarmTemp; /*!< The high alarm temperature.*/
+ int32_t panicAlarmTemp; /*!< The panic alarm temperature.*/
+ int32_t lowAlarmTemp; /*!< The low alarm temperature.*/
+} tmpsns_config_t;
+
+/*! @brief TMPSNS alarm mode. */
+typedef enum _tmpsns_alarm_mode
+{
+ kTEMPMON_HighAlarmMode = 0U, /*!< The high alarm temperature interrupt mode.*/
+ kTEMPMON_PanicAlarmMode = 1U, /*!< The panic alarm temperature interrupt mode.*/
+ kTEMPMON_LowAlarmMode = 2U, /*!< The low alarm temperature interrupt mode.*/
+} tmpsns_alarm_mode_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the TMPSNS module.
+ *
+ * @param base TMPSNS base pointer
+ * @param config Pointer to configuration structure.
+ */
+void TMPSNS_Init(TMPSNS_Type *base, const tmpsns_config_t *config);
+
+/*!
+ * @brief Deinitializes the TMPSNS module.
+ *
+ * @param base TMPSNS base pointer
+ */
+void TMPSNS_Deinit(TMPSNS_Type *base);
+
+/*!
+ * @brief Gets the default configuration structure.
+ *
+ * This function initializes the TMPSNS configuration structure to a default value. The default
+ * values are:
+ * tempmonConfig->frequency = 0x02U;
+ * tempmonConfig->highAlarmTemp = 44U;
+ * tempmonConfig->panicAlarmTemp = 90U;
+ * tempmonConfig->lowAlarmTemp = 39U;
+ *
+ * @param config Pointer to a configuration structure.
+ */
+void TMPSNS_GetDefaultConfig(tmpsns_config_t *config);
+
+/*!
+ * @brief start the temperature measurement process.
+ *
+ * @param base TMPSNS base pointer.
+ */
+void TMPSNS_StartMeasure(TMPSNS_Type *base);
+
+/*!
+ * @brief stop the measurement process.
+ *
+ * @param base TMPSNS base pointer
+ */
+void TMPSNS_StopMeasure(TMPSNS_Type *base);
+
+/*!
+ * @brief Get current temperature with the fused temperature calibration data.
+ *
+ * @param base TMPSNS base pointer
+ * @return current temperature with degrees Celsius.
+ */
+float TMPSNS_GetCurrentTemperature(TMPSNS_Type *base);
+
+/*!
+ * @brief Set the temperature count (raw sensor output) that will generate an alarm interrupt.
+ *
+ * @param base TMPSNS base pointer
+ * @param tempVal The alarm temperature with degrees Celsius
+ * @param alarmMode The alarm mode.
+ */
+void TMPSNS_SetTempAlarm(TMPSNS_Type *base, int32_t tempVal, tmpsns_alarm_mode_t alarmMode);
+
+/*!
+ * @brief Enable interrupt status.
+ *
+ * @param base TMPSNS base pointer
+ * @param mask The interrupts to enable from tmpsns_interrupt_status_enable_t.
+ */
+void TMPSNS_EnableInterrupt(TMPSNS_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disable interrupt status.
+ *
+ * @param base TMPSNS base pointer
+ * @param mask The interrupts to disable from tmpsns_interrupt_status_enable_t.
+ */
+void TMPSNS_DisableInterrupt(TMPSNS_Type *base, uint32_t mask);
+
+/*!
+ * @brief Get interrupt status flag.
+ *
+ * @param base TMPSNS base pointer
+ * @param mask The interrupts to disable from tmpsns_interrupt_status_t.
+ */
+static inline uint32_t TMPSNS_GetInterruptFlags(TMPSNS_Type *base)
+{
+ return base->STATUS0;
+}
+
+/*!
+ * @brief Clear interrupt status flag.
+ *
+ * @param base TMPSNS base pointer
+ * @param mask The interrupts to disable from tmpsns_interrupt_status_t.
+ */
+static inline void TMPSNS_ClearInterruptFlags(TMPSNS_Type *base, uint32_t mask)
+{
+ base->STATUS0 = mask;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_TEMPMON_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.c b/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.c
new file mode 100644
index 0000000000..186603742b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.c
@@ -0,0 +1,2009 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "fsl_trng.h"
+
+#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && FSL_FEATURE_SOC_TRNG_COUNT
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.trng"
+#endif
+
+/* Default values for user configuration structure.*/
+#if (defined(KW40Z4_SERIES) || defined(KW41Z4_SERIES) || defined(KW31Z4_SERIES) || defined(KW21Z4_SERIES) || \
+ defined(MCIMX7U5_M4_SERIES) || defined(KW36Z4_SERIES) || defined(KW37A4_SERIES) || defined(KW37Z4_SERIES) || \
+ defined(KW38A4_SERIES) || defined(KW38Z4_SERIES) || defined(KW39A4_SERIES) || defined(KW35Z4_SERIES) || \
+ defined(KW36A4_SERIES) || defined(KW35A4_SERIES) || defined(KW34A4_SERIES))
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv8
+#elif (defined(KV56F24_SERIES) || defined(KV58F24_SERIES) || defined(KL28Z7_SERIES) || defined(KL81Z7_SERIES) || \
+ defined(KL82Z7_SERIES) || defined(K32L2A41A_SERIES))
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv4
+#elif (defined(K81F25615_SERIES) || defined(K32L3A60_cm4_SERIES) || defined(K32L3A60_cm0plus_SERIES))
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv2
+#else
+/* Default value for the TRNG user configuration structure can be optionally
+ defined by device specific preprocessor macros. */
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_OSC_DIV) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_OSC_DIV > 0)
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_OSC_DIV_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv0
+#endif
+#endif
+
+#if (defined(RW610_SERIES) || defined(RW612_SERIES))
+
+/* RW610 specific settings for the TRNG */
+#define TRNG_USER_CONFIG_DEFAULT_LOCK 0
+#define TRNG_USER_CONFIG_DEFAULT_ENTROPY_DELAY 3200
+#define TRNG_USER_CONFIG_DEFAULT_SAMPLE_SIZE 256
+#define TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT 63
+#define TRNG_USER_CONFIG_DEFAULT_RETRY_COUNT 1
+#define TRNG_USER_CONFIG_DEFAULT_RUN_MAX_LIMIT 34
+
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM 171
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MINIMUM (TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM - 86)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM 63
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM - 56)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM 38
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM - 38)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM 26
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM - 26)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM 75
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM - 64)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM 47
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM - 46)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM 47
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM - 46)
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM 26912
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MINIMUM (TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM - 2467)
+
+#else
+
+#define TRNG_USER_CONFIG_DEFAULT_LOCK 0
+#define TRNG_USER_CONFIG_DEFAULT_ENTROPY_DELAY 3200
+#define TRNG_USER_CONFIG_DEFAULT_SAMPLE_SIZE 512
+#define TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT 63
+#define TRNG_USER_CONFIG_DEFAULT_RETRY_COUNT 1
+#define TRNG_USER_CONFIG_DEFAULT_RUN_MAX_LIMIT 32
+
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM 317
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MINIMUM (TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM - 122)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM 107
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM - 80)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM 62
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM - 55)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM 39
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM - 39)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM 26
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM - 26)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM 18
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM - 18)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM 17
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM - 17)
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM 1600
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MINIMUM (TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM - 570)
+
+#endif
+
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM > 0)
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM 30000
+#endif
+
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM > 0)
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM 1600
+#endif
+
+/*! @brief TRNG work mode */
+typedef enum _trng_work_mode
+{
+ kTRNG_WorkModeRun = 0U, /*!< Run Mode. */
+ kTRNG_WorkModeProgram = 1U /*!< Program Mode. */
+} trng_work_mode_t;
+
+/*! @brief TRNG statistical check type*/
+typedef enum _trng_statistical_check
+{
+ kTRNG_StatisticalCheckMonobit =
+ 1U, /*!< Statistical check of number of ones/zero detected during entropy generation. */
+ kTRNG_StatisticalCheckRunBit1, /*!< Statistical check of number of runs of length 1 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit2, /*!< Statistical check of number of runs of length 2 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit3, /*!< Statistical check of number of runs of length 3 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit4, /*!< Statistical check of number of runs of length 4 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit5, /*!< Statistical check of number of runs of length 5 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit6Plus, /*!< Statistical check of number of runs of length 6 or more detected during
+ entropy generation. */
+ kTRNG_StatisticalCheckPoker, /*!< Statistical check of "Poker Test". */
+ kTRNG_StatisticalCheckFrequencyCount /*!< Statistical check of entropy sample frequency count. */
+} trng_statistical_check_t;
+
+/*******************************************************************************
+ * TRNG_SCMISC - RNG Statistical Check Miscellaneous Register
+ ******************************************************************************/
+/*!
+ * @name Register TRNG_SCMISC, field RTY_CT[19:16] (RW)
+ *
+ * RETRY COUNT. If a statistical check fails during the TRNG Entropy Generation,
+ * the RTY_CT value indicates the number of times a retry should occur before
+ * generating an error. This field is writable only if MCTL[PRGM] bit is 1. This
+ * field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 1h by writing
+ * the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCMISC_RTY_CT field. */
+#define TRNG_RD_SCMISC_RTY_CT(base) ((TRNG_SCMISC_REG(base) & TRNG_SCMISC_RTY_CT_MASK) >> TRNG_SCMISC_RTY_CT_SHIFT)
+
+/*! @brief Set the RTY_CT field to a new value. */
+#define TRNG_WR_SCMISC_RTY_CT(base, value) (TRNG_RMW_SCMISC(base, TRNG_SCMISC_RTY_CT_MASK, TRNG_SCMISC_RTY_CT(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCML - RNG Statistical Check Monobit Limit Register
+ ******************************************************************************/
+/*!
+ * @brief TRNG_SCML - RNG Statistical Check Monobit Limit Register (RW)
+ *
+ * Reset value: 0x010C0568U
+ *
+ * The RNG Statistical Check Monobit Limit Register defines the allowable
+ * maximum and minimum number of ones/zero detected during entropy generation. To pass
+ * the test, the number of ones/zeroes generated must be less than the programmed
+ * maximum value, and the number of ones/zeroes generated must be greater than
+ * (maximum - range). If this test fails, the Retry Counter in SCMISC will be
+ * decremented, and a retry will occur if the Retry Count has not reached zero. If
+ * the Retry Count has reached zero, an error will be generated. Note that this
+ * offset (0xBASE_0620) is used as SCML only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0,
+ * this offset is used as SCMC readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCML register
+ */
+/*@{*/
+#define TRNG_SCML_REG(base) ((base)->SCML)
+#define TRNG_RD_SCML(base) (TRNG_SCML_REG(base))
+#define TRNG_WR_SCML(base, value) (TRNG_SCML_REG(base) = (value))
+#define TRNG_RMW_SCML(base, mask, value) (TRNG_WR_SCML(base, (TRNG_RD_SCML(base) & ~(mask)) | (value)))
+/*@}*/
+/*!
+ * @name Register TRNG_SCML, field MONO_MAX[15:0] (RW)
+ *
+ * Monobit Maximum Limit. Defines the maximum allowable count taken during
+ * entropy generation. The number of ones/zeroes detected during entropy generation
+ * must be less than MONO_MAX, else a retry or error will occur. This register is
+ * cleared to 00056Bh (decimal 1387) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCML_MONO_MAX field. */
+#define TRNG_RD_SCML_MONO_MAX(base) ((TRNG_SCML_REG(base) & TRNG_SCML_MONO_MAX_MASK) >> TRNG_SCML_MONO_MAX_SHIFT)
+
+/*! @brief Set the MONO_MAX field to a new value. */
+#define TRNG_WR_SCML_MONO_MAX(base, value) (TRNG_RMW_SCML(base, TRNG_SCML_MONO_MAX_MASK, TRNG_SCML_MONO_MAX(value)))
+/*@}*/
+/*!
+ * @name Register TRNG_SCML, field MONO_RNG[31:16] (RW)
+ *
+ * Monobit Range. The number of ones/zeroes detected during entropy generation
+ * must be greater than MONO_MAX - MONO_RNG, else a retry or error will occur.
+ * This register is cleared to 000112h (decimal 274) by writing the MCTL[RST_DEF]
+ * bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCML_MONO_RNG field. */
+#define TRNG_RD_SCML_MONO_RNG(base) ((TRNG_SCML_REG(base) & TRNG_SCML_MONO_RNG_MASK) >> TRNG_SCML_MONO_RNG_SHIFT)
+
+/*! @brief Set the MONO_RNG field to a new value. */
+#define TRNG_WR_SCML_MONO_RNG(base, value) (TRNG_RMW_SCML(base, TRNG_SCML_MONO_RNG_MASK, TRNG_SCML_MONO_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR1L - RNG Statistical Check Run Length 1 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR1L - RNG Statistical Check Run Length 1 Limit Register (RW)
+ *
+ * Reset value: 0x00B20195U
+ *
+ * The RNG Statistical Check Run Length 1 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 1 detected during entropy
+ * generation. To pass the test, the number of runs of length 1 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 1 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0624) is used as SCR1L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR1C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR1L register
+ */
+/*@{*/
+#define TRNG_SCR1L_REG(base) ((base)->SCR1L)
+#define TRNG_RD_SCR1L(base) (TRNG_SCR1L_REG(base))
+#define TRNG_WR_SCR1L(base, value) (TRNG_SCR1L_REG(base) = (value))
+#define TRNG_RMW_SCR1L(base, mask, value) (TRNG_WR_SCR1L(base, (TRNG_RD_SCR1L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR1L, field RUN1_MAX[14:0] (RW)
+ *
+ * Run Length 1 Maximum Limit. Defines the maximum allowable runs of length 1
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 1 detected during entropy generation must be less than RUN1_MAX, else a
+ * retry or error will occur. This register is cleared to 01E5h (decimal 485) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR1L_RUN1_MAX field. */
+#define TRNG_RD_SCR1L_RUN1_MAX(base) ((TRNG_SCR1L_REG(base) & TRNG_SCR1L_RUN1_MAX_MASK) >> TRNG_SCR1L_RUN1_MAX_SHIFT)
+
+/*! @brief Set the RUN1_MAX field to a new value. */
+#define TRNG_WR_SCR1L_RUN1_MAX(base, value) (TRNG_RMW_SCR1L(base, TRNG_SCR1L_RUN1_MAX_MASK, TRNG_SCR1L_RUN1_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR1L, field RUN1_RNG[30:16] (RW)
+ *
+ * Run Length 1 Range. The number of runs of length 1 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN1_MAX - RUN1_RNG, else a
+ * retry or error will occur. This register is cleared to 0102h (decimal 258) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR1L_RUN1_RNG field. */
+#define TRNG_RD_SCR1L_RUN1_RNG(base) ((TRNG_SCR1L_REG(base) & TRNG_SCR1L_RUN1_RNG_MASK) >> TRNG_SCR1L_RUN1_RNG_SHIFT)
+
+/*! @brief Set the RUN1_RNG field to a new value. */
+#define TRNG_WR_SCR1L_RUN1_RNG(base, value) (TRNG_RMW_SCR1L(base, TRNG_SCR1L_RUN1_RNG_MASK, TRNG_SCR1L_RUN1_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR2L - RNG Statistical Check Run Length 2 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR2L - RNG Statistical Check Run Length 2 Limit Register (RW)
+ *
+ * Reset value: 0x007A00DCU
+ *
+ * The RNG Statistical Check Run Length 2 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 2 detected during entropy
+ * generation. To pass the test, the number of runs of length 2 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 2 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0628) is used as SCR2L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR2C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR2L register
+ */
+/*@{*/
+#define TRNG_SCR2L_REG(base) ((base)->SCR2L)
+#define TRNG_RD_SCR2L(base) (TRNG_SCR2L_REG(base))
+#define TRNG_WR_SCR2L(base, value) (TRNG_SCR2L_REG(base) = (value))
+#define TRNG_RMW_SCR2L(base, mask, value) (TRNG_WR_SCR2L(base, (TRNG_RD_SCR2L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR2L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR2L, field RUN2_MAX[13:0] (RW)
+ *
+ * Run Length 2 Maximum Limit. Defines the maximum allowable runs of length 2
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 2 detected during entropy generation must be less than RUN2_MAX, else a
+ * retry or error will occur. This register is cleared to 00DCh (decimal 220) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR2L_RUN2_MAX field. */
+#define TRNG_RD_SCR2L_RUN2_MAX(base) ((TRNG_SCR2L_REG(base) & TRNG_SCR2L_RUN2_MAX_MASK) >> TRNG_SCR2L_RUN2_MAX_SHIFT)
+
+/*! @brief Set the RUN2_MAX field to a new value. */
+#define TRNG_WR_SCR2L_RUN2_MAX(base, value) (TRNG_RMW_SCR2L(base, TRNG_SCR2L_RUN2_MAX_MASK, TRNG_SCR2L_RUN2_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR2L, field RUN2_RNG[29:16] (RW)
+ *
+ * Run Length 2 Range. The number of runs of length 2 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN2_MAX - RUN2_RNG, else a
+ * retry or error will occur. This register is cleared to 007Ah (decimal 122) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR2L_RUN2_RNG field. */
+#define TRNG_RD_SCR2L_RUN2_RNG(base) ((TRNG_SCR2L_REG(base) & TRNG_SCR2L_RUN2_RNG_MASK) >> TRNG_SCR2L_RUN2_RNG_SHIFT)
+
+/*! @brief Set the RUN2_RNG field to a new value. */
+#define TRNG_WR_SCR2L_RUN2_RNG(base, value) (TRNG_RMW_SCR2L(base, TRNG_SCR2L_RUN2_RNG_MASK, TRNG_SCR2L_RUN2_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR3L - RNG Statistical Check Run Length 3 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR3L - RNG Statistical Check Run Length 3 Limit Register (RW)
+ *
+ * Reset value: 0x0058007DU
+ *
+ * The RNG Statistical Check Run Length 3 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 3 detected during entropy
+ * generation. To pass the test, the number of runs of length 3 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 3 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_062C) is used as SCR3L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR3C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR3L register
+ */
+/*@{*/
+#define TRNG_SCR3L_REG(base) ((base)->SCR3L)
+#define TRNG_RD_SCR3L(base) (TRNG_SCR3L_REG(base))
+#define TRNG_WR_SCR3L(base, value) (TRNG_SCR3L_REG(base) = (value))
+#define TRNG_RMW_SCR3L(base, mask, value) (TRNG_WR_SCR3L(base, (TRNG_RD_SCR3L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR3L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR3L, field RUN3_MAX[12:0] (RW)
+ *
+ * Run Length 3 Maximum Limit. Defines the maximum allowable runs of length 3
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 3 detected during entropy generation must be less than RUN3_MAX, else a
+ * retry or error will occur. This register is cleared to 007Dh (decimal 125) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR3L_RUN3_MAX field. */
+#define TRNG_RD_SCR3L_RUN3_MAX(base) ((TRNG_SCR3L_REG(base) & TRNG_SCR3L_RUN3_MAX_MASK) >> TRNG_SCR3L_RUN3_MAX_SHIFT)
+
+/*! @brief Set the RUN3_MAX field to a new value. */
+#define TRNG_WR_SCR3L_RUN3_MAX(base, value) (TRNG_RMW_SCR3L(base, TRNG_SCR3L_RUN3_MAX_MASK, TRNG_SCR3L_RUN3_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR3L, field RUN3_RNG[28:16] (RW)
+ *
+ * Run Length 3 Range. The number of runs of length 3 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN3_MAX - RUN3_RNG, else a
+ * retry or error will occur. This register is cleared to 0058h (decimal 88) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR3L_RUN3_RNG field. */
+#define TRNG_RD_SCR3L_RUN3_RNG(base) ((TRNG_SCR3L_REG(base) & TRNG_SCR3L_RUN3_RNG_MASK) >> TRNG_SCR3L_RUN3_RNG_SHIFT)
+
+/*! @brief Set the RUN3_RNG field to a new value. */
+#define TRNG_WR_SCR3L_RUN3_RNG(base, value) (TRNG_RMW_SCR3L(base, TRNG_SCR3L_RUN3_RNG_MASK, TRNG_SCR3L_RUN3_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR4L - RNG Statistical Check Run Length 4 Limit Register
+ ******************************************************************************/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L)
+/*!
+ * @brief TRNG_SCR4L - RNG Statistical Check Run Length 4 Limit Register (RW)
+ *
+ * Reset value: 0x0040004BU
+ *
+ * The RNG Statistical Check Run Length 4 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 4 detected during entropy
+ * generation. To pass the test, the number of runs of length 4 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 4 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0630) is used as SCR4L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR4C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR4L register
+ */
+/*@{*/
+#define TRNG_SCR4L_REG(base) ((base)->SCR4L)
+#define TRNG_RD_SCR4L(base) (TRNG_SCR4L_REG(base))
+#define TRNG_WR_SCR4L(base, value) (TRNG_SCR4L_REG(base) = (value))
+#define TRNG_RMW_SCR4L(base, mask, value) (TRNG_WR_SCR4L(base, (TRNG_RD_SCR4L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR4L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR4L, field RUN4_MAX[11:0] (RW)
+ *
+ * Run Length 4 Maximum Limit. Defines the maximum allowable runs of length 4
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 4 detected during entropy generation must be less than RUN4_MAX, else a
+ * retry or error will occur. This register is cleared to 004Bh (decimal 75) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR4L_RUN4_MAX field. */
+#define TRNG_RD_SCR4L_RUN4_MAX(base) ((TRNG_SCR4L_REG(base) & TRNG_SCR4L_RUN4_MAX_MASK) >> TRNG_SCR4L_RUN4_MAX_SHIFT)
+
+/*! @brief Set the RUN4_MAX field to a new value. */
+#define TRNG_WR_SCR4L_RUN4_MAX(base, value) (TRNG_RMW_SCR4L(base, TRNG_SCR4L_RUN4_MAX_MASK, TRNG_SCR4L_RUN4_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR4L, field RUN4_RNG[27:16] (RW)
+ *
+ * Run Length 4 Range. The number of runs of length 4 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN4_MAX - RUN4_RNG, else a
+ * retry or error will occur. This register is cleared to 0040h (decimal 64) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR4L_RUN4_RNG field. */
+#define TRNG_RD_SCR4L_RUN4_RNG(base) ((TRNG_SCR4L_REG(base) & TRNG_SCR4L_RUN4_RNG_MASK) >> TRNG_SCR4L_RUN4_RNG_SHIFT)
+
+/*! @brief Set the RUN4_RNG field to a new value. */
+#define TRNG_WR_SCR4L_RUN4_RNG(base, value) (TRNG_RMW_SCR4L(base, TRNG_SCR4L_RUN4_RNG_MASK, TRNG_SCR4L_RUN4_RNG(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L */
+
+/*******************************************************************************
+ * TRNG_SCR5L - RNG Statistical Check Run Length 5 Limit Register
+ ******************************************************************************/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L)
+/*!
+ * @brief TRNG_SCR5L - RNG Statistical Check Run Length 5 Limit Register (RW)
+ *
+ * Reset value: 0x002E002FU
+ *
+ * The RNG Statistical Check Run Length 5 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 5 detected during entropy
+ * generation. To pass the test, the number of runs of length 5 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 5 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0634) is used as SCR5L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR5C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR5L register
+ */
+/*@{*/
+#define TRNG_SCR5L_REG(base) ((base)->SCR5L)
+#define TRNG_RD_SCR5L(base) (TRNG_SCR5L_REG(base))
+#define TRNG_WR_SCR5L(base, value) (TRNG_SCR5L_REG(base) = (value))
+#define TRNG_RMW_SCR5L(base, mask, value) (TRNG_WR_SCR5L(base, (TRNG_RD_SCR5L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR5L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR5L, field RUN5_MAX[10:0] (RW)
+ *
+ * Run Length 5 Maximum Limit. Defines the maximum allowable runs of length 5
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 5 detected during entropy generation must be less than RUN5_MAX, else a
+ * retry or error will occur. This register is cleared to 002Fh (decimal 47) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR5L_RUN5_MAX field. */
+#define TRNG_RD_SCR5L_RUN5_MAX(base) ((TRNG_SCR5L_REG(base) & TRNG_SCR5L_RUN5_MAX_MASK) >> TRNG_SCR5L_RUN5_MAX_SHIFT)
+
+/*! @brief Set the RUN5_MAX field to a new value. */
+#define TRNG_WR_SCR5L_RUN5_MAX(base, value) (TRNG_RMW_SCR5L(base, TRNG_SCR5L_RUN5_MAX_MASK, TRNG_SCR5L_RUN5_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR5L, field RUN5_RNG[26:16] (RW)
+ *
+ * Run Length 5 Range. The number of runs of length 5 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN5_MAX - RUN5_RNG, else a
+ * retry or error will occur. This register is cleared to 002Eh (decimal 46) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR5L_RUN5_RNG field. */
+#define TRNG_RD_SCR5L_RUN5_RNG(base) ((TRNG_SCR5L_REG(base) & TRNG_SCR5L_RUN5_RNG_MASK) >> TRNG_SCR5L_RUN5_RNG_SHIFT)
+
+/*! @brief Set the RUN5_RNG field to a new value. */
+#define TRNG_WR_SCR5L_RUN5_RNG(base, value) (TRNG_RMW_SCR5L(base, TRNG_SCR5L_RUN5_RNG_MASK, TRNG_SCR5L_RUN5_RNG(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L */
+
+/*******************************************************************************
+ * TRNG_SCR6PL - RNG Statistical Check Run Length 6+ Limit Register
+ ******************************************************************************/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L)
+/*!
+ * @brief TRNG_SCR6PL - RNG Statistical Check Run Length 6+ Limit Register (RW)
+ *
+ * Reset value: 0x002E002FU
+ *
+ * The RNG Statistical Check Run Length 6+ Limit Register defines the allowable
+ * maximum and minimum number of runs of length 6 or more detected during entropy
+ * generation. To pass the test, the number of runs of length 6 or more (for
+ * samples of both 0 and 1) must be less than the programmed maximum value, and the
+ * number of runs of length 6 or more must be greater than (maximum - range). If
+ * this test fails, the Retry Counter in SCMISC will be decremented, and a retry
+ * will occur if the Retry Count has not reached zero. If the Retry Count has
+ * reached zero, an error will be generated. Note that this offset (0xBASE_0638) is
+ * used as SCR6PL only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this offset is
+ * used as SCR6PC readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR6PL register
+ */
+/*@{*/
+#define TRNG_SCR6PL_REG(base) ((base)->SCR6PL)
+#define TRNG_RD_SCR6PL(base) (TRNG_SCR6PL_REG(base))
+#define TRNG_WR_SCR6PL(base, value) (TRNG_SCR6PL_REG(base) = (value))
+#define TRNG_RMW_SCR6PL(base, mask, value) (TRNG_WR_SCR6PL(base, (TRNG_RD_SCR6PL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR6PL bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR6PL, field RUN6P_MAX[10:0] (RW)
+ *
+ * Run Length 6+ Maximum Limit. Defines the maximum allowable runs of length 6
+ * or more (for both 0 and 1) detected during entropy generation. The number of
+ * runs of length 6 or more detected during entropy generation must be less than
+ * RUN6P_MAX, else a retry or error will occur. This register is cleared to 002Fh
+ * (decimal 47) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR6PL_RUN6P_MAX field. */
+#define TRNG_RD_SCR6PL_RUN6P_MAX(base) \
+ ((TRNG_SCR6PL_REG(base) & TRNG_SCR6PL_RUN6P_MAX_MASK) >> TRNG_SCR6PL_RUN6P_MAX_SHIFT)
+
+/*! @brief Set the RUN6P_MAX field to a new value. */
+#define TRNG_WR_SCR6PL_RUN6P_MAX(base, value) \
+ (TRNG_RMW_SCR6PL(base, TRNG_SCR6PL_RUN6P_MAX_MASK, TRNG_SCR6PL_RUN6P_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR6PL, field RUN6P_RNG[26:16] (RW)
+ *
+ * Run Length 6+ Range. The number of runs of length 6 or more (for both 0 and
+ * 1) detected during entropy generation must be greater than RUN6P_MAX -
+ * RUN6P_RNG, else a retry or error will occur. This register is cleared to 002Eh
+ * (decimal 46) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR6PL_RUN6P_RNG field. */
+#define TRNG_RD_SCR6PL_RUN6P_RNG(base) \
+ ((TRNG_SCR6PL_REG(base) & TRNG_SCR6PL_RUN6P_RNG_MASK) >> TRNG_SCR6PL_RUN6P_RNG_SHIFT)
+
+/*! @brief Set the RUN6P_RNG field to a new value. */
+#define TRNG_WR_SCR6PL_RUN6P_RNG(base, value) \
+ (TRNG_RMW_SCR6PL(base, TRNG_SCR6PL_RUN6P_RNG_MASK, TRNG_SCR6PL_RUN6P_RNG(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L */
+
+/*******************************************************************************
+ * TRNG_PKRMAX - RNG Poker Maximum Limit Register
+ ******************************************************************************/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX) && FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX)
+/*!
+ * @brief TRNG_PKRMAX - RNG Poker Maximum Limit Register (RW)
+ *
+ * Reset value: 0x00006920U
+ *
+ * The RNG Poker Maximum Limit Register defines Maximum Limit allowable during
+ * the TRNG Statistical Check Poker Test. Note that this offset (0xBASE_060C) is
+ * used as PKRMAX only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this offset is used
+ * as the PKRSQ readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_PKRMAX register
+ */
+/*@{*/
+#define TRNG_PKRMAX_REG(base) ((base)->PKRMAX)
+#define TRNG_RD_PKRMAX(base) (TRNG_PKRMAX_REG(base))
+#define TRNG_WR_PKRMAX(base, value) (TRNG_PKRMAX_REG(base) = (value))
+#define TRNG_RMW_PKRMAX(base, mask, value) (TRNG_WR_PKRMAX(base, (TRNG_RD_PKRMAX(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_PKRMAX bitfields
+ */
+
+/*!
+ * @name Register TRNG_PKRMAX, field PKR_MAX[23:0] (RW)
+ *
+ * Poker Maximum Limit. During the TRNG Statistical Checks, a "Poker Test" is
+ * run which requires a maximum and minimum limit. The maximum allowable result is
+ * programmed in the PKRMAX[PKR_MAX] register. This field is writable only if
+ * MCTL[PRGM] bit is 1. This register is cleared to 006920h (decimal 26912) by
+ * writing the MCTL[RST_DEF] bit to 1. Note that the PKRMAX and PKRRNG registers
+ * combined are used to define the minimum allowable Poker result, which is PKR_MAX -
+ * PKR_RNG + 1. Note that if MCTL[PRGM] bit is 0, this register address is used
+ * to read the Poker Test Square Calculation result in register PKRSQ, as defined
+ * in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_PKRMAX_PKR_MAX field. */
+#define TRNG_RD_PKRMAX_PKR_MAX(base) ((TRNG_PKRMAX_REG(base) & TRNG_PKRMAX_PKR_MAX_MASK) >> TRNG_PKRMAX_PKR_MAX_SHIFT)
+
+/*! @brief Set the PKR_MAX field to a new value. */
+#define TRNG_WR_PKRMAX_PKR_MAX(base, value) \
+ (TRNG_RMW_PKRMAX(base, TRNG_PKRMAX_PKR_MAX_MASK, TRNG_PKRMAX_PKR_MAX(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX */
+
+/*******************************************************************************
+ * TRNG_PKRRNG - RNG Poker Range Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_PKRRNG - RNG Poker Range Register (RW)
+ *
+ * Reset value: 0x000009A3U
+ *
+ * The RNG Poker Range Register defines the difference between the TRNG Poker
+ * Maximum Limit and the minimum limit. These limits are used during the TRNG
+ * Statistical Check Poker Test.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_PKRRNG register
+ */
+/*@{*/
+#define TRNG_PKRRNG_REG(base) ((base)->PKRRNG)
+#define TRNG_RD_PKRRNG(base) (TRNG_PKRRNG_REG(base))
+#define TRNG_WR_PKRRNG(base, value) (TRNG_PKRRNG_REG(base) = (value))
+#define TRNG_RMW_PKRRNG(base, mask, value) (TRNG_WR_PKRRNG(base, (TRNG_RD_PKRRNG(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_PKRRNG bitfields
+ */
+
+/*!
+ * @name Register TRNG_PKRRNG, field PKR_RNG[15:0] (RW)
+ *
+ * Poker Range. During the TRNG Statistical Checks, a "Poker Test" is run which
+ * requires a maximum and minimum limit. The maximum is programmed in the
+ * RTPKRMAX[PKR_MAX] register, and the minimum is derived by subtracting the PKR_RNG
+ * value from the programmed maximum value. This field is writable only if
+ * MCTL[PRGM] bit is 1. This field will read zeroes if MCTL[PRGM] = 0. This field is
+ * cleared to 09A3h (decimal 2467) by writing the MCTL[RST_DEF] bit to 1. Note that
+ * the minimum allowable Poker result is PKR_MAX - PKR_RNG + 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_PKRRNG_PKR_RNG field. */
+#define TRNG_RD_PKRRNG_PKR_RNG(base) ((TRNG_PKRRNG_REG(base) & TRNG_PKRRNG_PKR_RNG_MASK) >> TRNG_PKRRNG_PKR_RNG_SHIFT)
+
+/*! @brief Set the PKR_RNG field to a new value. */
+#define TRNG_WR_PKRRNG_PKR_RNG(base, value) \
+ (TRNG_RMW_PKRRNG(base, TRNG_PKRRNG_PKR_RNG_MASK, TRNG_PKRRNG_PKR_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_FRQMAX - RNG Frequency Count Maximum Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_FRQMAX - RNG Frequency Count Maximum Limit Register (RW)
+ *
+ * Reset value: 0x00006400U
+ *
+ * The RNG Frequency Count Maximum Limit Register defines the maximum allowable
+ * count taken by the Entropy sample counter during each Entropy sample. During
+ * any sample period, if the count is greater than this programmed maximum, a
+ * Frequency Count Fail is flagged in MCTL[FCT_FAIL] and an error is generated. Note
+ * that this address (061C) is used as FRQMAX only if MCTL[PRGM] is 1. If
+ * MCTL[PRGM] is 0, this address is used as FRQCNT readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_FRQMAX register
+ */
+/*@{*/
+#define TRNG_FRQMAX_REG(base) ((base)->FRQMAX)
+#define TRNG_RD_FRQMAX(base) (TRNG_FRQMAX_REG(base))
+#define TRNG_WR_FRQMAX(base, value) (TRNG_FRQMAX_REG(base) = (value))
+#define TRNG_RMW_FRQMAX(base, mask, value) (TRNG_WR_FRQMAX(base, (TRNG_RD_FRQMAX(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_FRQMAX bitfields
+ */
+
+/*!
+ * @name Register TRNG_FRQMAX, field FRQ_MAX[21:0] (RW)
+ *
+ * Frequency Counter Maximum Limit. Defines the maximum allowable count taken
+ * during each entropy sample. This field is writable only if MCTL[PRGM] bit is 1.
+ * This register is cleared to 000640h by writing the MCTL[RST_DEF] bit to 1.
+ * Note that if MCTL[PRGM] bit is 0, this register address is used to read the
+ * Frequency Count result in register FRQCNT, as defined in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_FRQMAX_FRQ_MAX field. */
+#define TRNG_RD_FRQMAX_FRQ_MAX(base) ((TRNG_FRQMAX_REG(base) & TRNG_FRQMAX_FRQ_MAX_MASK) >> TRNG_FRQMAX_FRQ_MAX_SHIFT)
+
+/*! @brief Set the FRQ_MAX field to a new value. */
+#define TRNG_WR_FRQMAX_FRQ_MAX(base, value) \
+ (TRNG_RMW_FRQMAX(base, TRNG_FRQMAX_FRQ_MAX_MASK, TRNG_FRQMAX_FRQ_MAX(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_FRQMIN - RNG Frequency Count Minimum Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_FRQMIN - RNG Frequency Count Minimum Limit Register (RW)
+ *
+ * Reset value: 0x00000640U
+ *
+ * The RNG Frequency Count Minimum Limit Register defines the minimum allowable
+ * count taken by the Entropy sample counter during each Entropy sample. During
+ * any sample period, if the count is less than this programmed minimum, a
+ * Frequency Count Fail is flagged in MCTL[FCT_FAIL] and an error is generated.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_FRQMIN register
+ */
+/*@{*/
+#define TRNG_FRQMIN_REG(base) ((base)->FRQMIN)
+#define TRNG_RD_FRQMIN(base) (TRNG_FRQMIN_REG(base))
+#define TRNG_WR_FRQMIN(base, value) (TRNG_FRQMIN_REG(base) = (value))
+#define TRNG_RMW_FRQMIN(base, mask, value) (TRNG_WR_FRQMIN(base, (TRNG_RD_FRQMIN(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_FRQMIN bitfields
+ */
+
+/*!
+ * @name Register TRNG_FRQMIN, field FRQ_MIN[21:0] (RW)
+ *
+ * Frequency Count Minimum Limit. Defines the minimum allowable count taken
+ * during each entropy sample. This field is writable only if MCTL[PRGM] bit is 1.
+ * This field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 0000h64
+ * by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_FRQMIN_FRQ_MIN field. */
+#define TRNG_RD_FRQMIN_FRQ_MIN(base) ((TRNG_FRQMIN_REG(base) & TRNG_FRQMIN_FRQ_MIN_MASK) >> TRNG_FRQMIN_FRQ_MIN_SHIFT)
+
+/*! @brief Set the FRQ_MIN field to a new value. */
+#define TRNG_WR_FRQMIN_FRQ_MIN(base, value) \
+ (TRNG_RMW_FRQMIN(base, TRNG_FRQMIN_FRQ_MIN_MASK, TRNG_FRQMIN_FRQ_MIN(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_MCTL - RNG Miscellaneous Control Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_MCTL - RNG Miscellaneous Control Register (RW)
+ *
+ * Reset value: 0x00012001U
+ *
+ * This register is intended to be used for programming, configuring and testing
+ * the RNG. It is the main register to read/write, in order to enable Entropy
+ * generation, to stop entropy generation and to block access to entropy registers.
+ * This is done via the special TRNG_ACC and PRGM bits below. The RNG
+ * Miscellaneous Control Register is a read/write register used to control the RNG's True
+ * Random Number Generator (TRNG) access, operation and test. Note that in many
+ * cases two RNG registers share the same address, and a particular register at the
+ * shared address is selected based upon the value in the PRGM field of the MCTL
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_MCTL register
+ */
+/*@{*/
+#define TRNG_MCTL_REG(base) ((base)->MCTL)
+#define TRNG_RD_MCTL(base) (TRNG_MCTL_REG(base))
+#define TRNG_WR_MCTL(base, value) (TRNG_MCTL_REG(base) = (value))
+#define TRNG_RMW_MCTL(base, mask, value) (TRNG_WR_MCTL(base, (TRNG_RD_MCTL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field FOR_SCLK[7] (RW)
+ *
+ * Force System Clock. If set, the system clock is used to operate the TRNG,
+ * instead of the ring oscillator. This is for test use only, and indeterminate
+ * results may occur. This bit is writable only if PRGM bit is 1, or PRGM bit is
+ * being written to 1 simultaneously to writing this bit. This bit is cleared by
+ * writing the RST_DEF bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_FOR_SCLK field. */
+#define TRNG_RD_MCTL_FOR_SCLK(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_FOR_SCLK_MASK) >> TRNG_MCTL_FOR_SCLK_SHIFT)
+
+/*! @brief Set the FOR_SCLK field to a new value. */
+#define TRNG_WR_MCTL_FOR_SCLK(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_FOR_SCLK_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_FOR_SCLK(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field OSC_DIV[3:2] (RW)
+ *
+ * Oscillator Divide. Determines the amount of dividing done to the ring
+ * oscillator before it is used by the TRNG.This field is writable only if PRGM bit is
+ * 1, or PRGM bit is being written to 1 simultaneously to writing this field. This
+ * field is cleared to 00 by writing the RST_DEF bit to 1.
+ *
+ * Values:
+ * - 0b00 - use ring oscillator with no divide
+ * - 0b01 - use ring oscillator divided-by-2
+ * - 0b10 - use ring oscillator divided-by-4
+ * - 0b11 - use ring oscillator divided-by-8
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_OSC_DIV field. */
+#define TRNG_RD_MCTL_OSC_DIV(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_OSC_DIV_MASK) >> TRNG_MCTL_OSC_DIV_SHIFT)
+
+/*! @brief Set the OSC_DIV field to a new value. */
+#define TRNG_WR_MCTL_OSC_DIV(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_OSC_DIV_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_OSC_DIV(value)))
+/*@}*/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE) && FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE)
+/*!
+ * @name Register TRNG_MCTL, field SAMP_MODE[1:0] (RW)
+ *
+ * Sample Mode. Determines the method of sampling the ring oscillator while
+ * generating the Entropy value:This field is writable only if PRGM bit is 1, or PRGM
+ * bit is being written to 1 simultaneously with writing this field. This field
+ * is cleared to 01 by writing the RST_DEF bit to 1.
+ *
+ * Values:
+ * - 0b00 - use Von Neumann data into both Entropy shifter and Statistical
+ * Checker
+ * - 0b01 - use raw data into both Entropy shifter and Statistical Checker
+ * - 0b10 - use Von Neumann data into Entropy shifter. Use raw data into
+ * Statistical Checker
+ * - 0b11 - reserved.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_SAMP_MODE field. */
+#define TRNG_RD_MCTL_SAMP_MODE(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_SAMP_MODE_MASK) >> TRNG_MCTL_SAMP_MODE_SHIFT)
+
+/*! @brief Set the SAMP_MODE field to a new value. */
+#define TRNG_WR_MCTL_SAMP_MODE(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_SAMP_MODE_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_SAMP_MODE(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE */
+
+/*!
+ * @name Register TRNG_MCTL, field PRGM[16] (RW)
+ *
+ * Programming Mode Select. When this bit is 1, the TRNG is in Program Mode,
+ * otherwise it is in Run Mode. No Entropy value will be generated while the TRNG is
+ * in Program Mode. Note that different RNG registers are accessible at the same
+ * address depending on whether PRGM is set to 1 or 0. This is noted in the RNG
+ * register descriptions.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_PRGM field. */
+#define TRNG_RD_MCTL_PRGM(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_PRGM_MASK) >> TRNG_MCTL_PRGM_SHIFT)
+
+/*! @brief Set the PRGM field to a new value. */
+#define TRNG_WR_MCTL_PRGM(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_PRGM(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field RST_DEF[6] (WO)
+ *
+ * Reset Defaults. Writing a 1 to this bit clears various TRNG registers, and
+ * bits within registers, to their default state. This bit is writable only if PRGM
+ * bit is 1, or PRGM bit is being written to 1 simultaneously to writing this
+ * bit. Reading this bit always produces a 0.
+ */
+/*@{*/
+/*! @brief Set the RST_DEF field to a new value. */
+#define TRNG_WR_MCTL_RST_DEF(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_RST_DEF_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_RST_DEF(value)))
+/*@}*/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC > 0))
+/*!
+ * @name Register TRNG_MCTL, field TRNG_ACC[5] (RW)
+ *
+ * TRNG Access Mode. If this bit is set to 1, the TRNG will generate an Entropy
+ * value that can be read via the ENT0-ENT15 registers. The Entropy value may be
+ * read once the ENT VAL bit is asserted. Also see ENTa register descriptions
+ * (For a = 0 to 15).
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_TRNG_ACC field. */
+#define TRNG_RD_MCTL_TRNG_ACC(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_TRNG_ACC_MASK) >> TRNG_MCTL_TRNG_ACC_SHIFT)
+
+/*! @brief Set the TRNG_ACC field to a new value. */
+#define TRNG_WR_MCTL_TRNG_ACC(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_TRNG_ACC_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_TRNG_ACC(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC */
+
+/*!
+ * @name Register TRNG_MCTL, field TSTOP_OK[13] (RO)
+ *
+ * TRNG_OK_TO_STOP. Software should check that this bit is a 1 before
+ * transitioning RNG to low power mode (RNG clock stopped). RNG turns on the TRNG
+ * free-running ring oscillator whenever new entropy is being generated and turns off the
+ * ring oscillator when entropy generation is complete. If the RNG clock is
+ * stopped while the TRNG ring oscillator is running, the oscillator will continue
+ * running even though the RNG clock is stopped. TSTOP_OK is asserted when the TRNG
+ * ring oscillator is not running. and therefore it is ok to stop the RNG clock.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_TSTOP_OK field. */
+#define TRNG_RD_MCTL_TSTOP_OK(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_TSTOP_OK_MASK) >> TRNG_MCTL_TSTOP_OK_SHIFT)
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field ENT_VAL[10] (RO)
+ *
+ * Read only: Entropy Valid. Will assert only if TRNG ACC bit is set, and then
+ * after an entropy value is generated. Will be cleared when ENT15 is read. (ENT0
+ * through ENT14 should be read before reading ENT15).
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_ENT_VAL field. */
+#define TRNG_RD_MCTL_ENT_VAL(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_ENT_VAL_MASK) >> TRNG_MCTL_ENT_VAL_SHIFT)
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field ERR[12] (W1C)
+ *
+ * Read: Error status. 1 = error detected. 0 = no error.Write: Write 1 to clear
+ * errors. Writing 0 has no effect.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_ERR field. */
+#define TRNG_RD_MCTL_ERR(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_ERR_MASK) >> TRNG_MCTL_ERR_SHIFT)
+
+/*! @brief Set the ERR field to a new value. */
+#define TRNG_WR_MCTL_ERR(base, value) (TRNG_RMW_MCTL(base, TRNG_MCTL_ERR_MASK, TRNG_MCTL_ERR(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SDCTL - RNG Seed Control Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SDCTL - RNG Seed Control Register (RW)
+ *
+ * Reset value: 0x0C8009C4U
+ *
+ * The RNG Seed Control Register contains two fields. One field defines the
+ * length (in system clocks) of each Entropy sample (ENT_DLY), and the other field
+ * indicates the number of samples that will taken during each TRNG Entropy
+ * generation (SAMP_SIZE).
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SDCTL register
+ */
+/*@{*/
+#define TRNG_SDCTL_REG(base) ((base)->SDCTL)
+#define TRNG_RD_SDCTL(base) (TRNG_SDCTL_REG(base))
+#define TRNG_WR_SDCTL(base, value) (TRNG_SDCTL_REG(base) = (value))
+#define TRNG_RMW_SDCTL(base, mask, value) (TRNG_WR_SDCTL(base, (TRNG_RD_SDCTL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SDCTL bitfields
+ */
+
+/*!
+ * @name Register TRNG_SDCTL, field SAMP_SIZE[15:0] (RW)
+ *
+ * Sample Size. Defines the total number of Entropy samples that will be taken
+ * during Entropy generation. This field is writable only if MCTL[PRGM] bit is 1.
+ * This field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 09C4h
+ * (decimal 2500) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SDCTL_SAMP_SIZE field. */
+#define TRNG_RD_SDCTL_SAMP_SIZE(base) ((TRNG_SDCTL_REG(base) & TRNG_SDCTL_SAMP_SIZE_MASK) >> TRNG_SDCTL_SAMP_SIZE_SHIFT)
+
+/*! @brief Set the SAMP_SIZE field to a new value. */
+#define TRNG_WR_SDCTL_SAMP_SIZE(base, value) \
+ (TRNG_RMW_SDCTL(base, TRNG_SDCTL_SAMP_SIZE_MASK, TRNG_SDCTL_SAMP_SIZE(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SDCTL, field ENT_DLY[31:16] (RW)
+ *
+ * Entropy Delay. Defines the length (in system clocks) of each Entropy sample
+ * taken. This field is writable only if MCTL[PRGM] bit is 1. This field will read
+ * zeroes if MCTL[PRGM] = 0. This field is cleared to 0C80h (decimal 3200) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SDCTL_ENT_DLY field. */
+#define TRNG_RD_SDCTL_ENT_DLY(base) ((TRNG_SDCTL_REG(base) & TRNG_SDCTL_ENT_DLY_MASK) >> TRNG_SDCTL_ENT_DLY_SHIFT)
+
+/*! @brief Set the ENT_DLY field to a new value. */
+#define TRNG_WR_SDCTL_ENT_DLY(base, value) (TRNG_RMW_SDCTL(base, TRNG_SDCTL_ENT_DLY_MASK, TRNG_SDCTL_ENT_DLY(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SBLIM - RNG Sparse Bit Limit Register
+ ******************************************************************************/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM > 0))
+/*!
+ * @brief TRNG_SBLIM - RNG Sparse Bit Limit Register (RW)
+ *
+ * Reset value: 0x0000003FU
+ *
+ * The RNG Sparse Bit Limit Register is used when Von Neumann sampling is
+ * selected during Entropy Generation. It defines the maximum number of consecutive Von
+ * Neumann samples which may be discarded before an error is generated. Note
+ * that this address (0xBASE_0614) is used as SBLIM only if MCTL[PRGM] is 1. If
+ * MCTL[PRGM] is 0, this address is used as TOTSAM readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SBLIM register
+ */
+/*@{*/
+#define TRNG_SBLIM_REG(base) ((base)->SBLIM)
+#define TRNG_RD_SBLIM(base) (TRNG_SBLIM_REG(base))
+#define TRNG_WR_SBLIM(base, value) (TRNG_SBLIM_REG(base) = (value))
+#define TRNG_RMW_SBLIM(base, mask, value) (TRNG_WR_SBLIM(base, (TRNG_RD_SBLIM(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SBLIM bitfields
+ */
+
+/*!
+ * @name Register TRNG_SBLIM, field SB_LIM[9:0] (RW)
+ *
+ * Sparse Bit Limit. During Von Neumann sampling (if enabled by MCTL[SAMP_MODE],
+ * samples are discarded if two consecutive raw samples are both 0 or both 1. If
+ * this discarding occurs for a long period of time, it indicates that there is
+ * insufficient Entropy. The Sparse Bit Limit defines the maximum number of
+ * consecutive samples that may be discarded before an error is generated. This field
+ * is writable only if MCTL[PRGM] bit is 1. This register is cleared to 03hF by
+ * writing the MCTL[RST_DEF] bit to 1. Note that if MCTL[PRGM] bit is 0, this
+ * register address is used to read the Total Samples count in register TOTSAM, as
+ * defined in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SBLIM_SB_LIM field. */
+#define TRNG_RD_SBLIM_SB_LIM(base) ((TRNG_SBLIM_REG(base) & TRNG_SBLIM_SB_LIM_MASK) >> TRNG_SBLIM_SB_LIM_SHIFT)
+
+/*! @brief Set the SB_LIM field to a new value. */
+#define TRNG_WR_SBLIM_SB_LIM(base, value) (TRNG_RMW_SBLIM(base, TRNG_SBLIM_SB_LIM_MASK, TRNG_SBLIM_SB_LIM(value)))
+/*@}*/
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM */
+
+/*******************************************************************************
+ * TRNG_SCMISC - RNG Statistical Check Miscellaneous Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCMISC - RNG Statistical Check Miscellaneous Register (RW)
+ *
+ * Reset value: 0x0001001FU
+ *
+ * The RNG Statistical Check Miscellaneous Register contains the Long Run
+ * Maximum Limit value and the Retry Count value. This register is accessible only when
+ * the MCTL[PRGM] bit is 1, otherwise this register will read zeroes, and cannot
+ * be written.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCMISC register
+ */
+/*@{*/
+#define TRNG_SCMISC_REG(base) ((base)->SCMISC)
+#define TRNG_RD_SCMISC(base) (TRNG_SCMISC_REG(base))
+#define TRNG_WR_SCMISC(base, value) (TRNG_SCMISC_REG(base) = (value))
+#define TRNG_RMW_SCMISC(base, mask, value) (TRNG_WR_SCMISC(base, (TRNG_RD_SCMISC(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCMISC bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCMISC, field LRUN_MAX[7:0] (RW)
+ *
+ * LONG RUN MAX LIMIT. This value is the largest allowable number of consecutive
+ * samples of all 1, or all 0, that is allowed during the Entropy generation.
+ * This field is writable only if MCTL[PRGM] bit is 1. This field will read zeroes
+ * if MCTL[PRGM] = 0. This field is cleared to 22h by writing the MCTL[RST_DEF]
+ * bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCMISC_LRUN_MAX field. */
+#define TRNG_RD_SCMISC_LRUN_MAX(base) \
+ ((TRNG_SCMISC_REG(base) & TRNG_SCMISC_LRUN_MAX_MASK) >> TRNG_SCMISC_LRUN_MAX_SHIFT)
+
+/*! @brief Set the LRUN_MAX field to a new value. */
+#define TRNG_WR_SCMISC_LRUN_MAX(base, value) \
+ (TRNG_RMW_SCMISC(base, TRNG_SCMISC_LRUN_MAX_MASK, TRNG_SCMISC_LRUN_MAX(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_ENT - RNG TRNG Entropy Read Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_ENT - RNG TRNG Entropy Read Register (RO)
+ *
+ * Reset value: 0x00000000U
+ *
+ * The RNG TRNG can be programmed to generate an entropy value that is readable
+ * via the SkyBlue bus. To do this, set the MCTL[TRNG_ACC] bit to 1. Once the
+ * entropy value has been generated, the MCTL[ENT_VAL] bit will be set to 1. At this
+ * point, ENT0 through ENT15 may be read to retrieve the 512-bit entropy value.
+ * Note that once ENT15 is read, the entropy value will be cleared and a new
+ * value will begin generation, so it is important that ENT15 be read last. These
+ * registers are readable only when MCTL[PRGM] = 0 (Run Mode), MCTL[TRNG_ACC] = 1
+ * (TRNG access mode) and MCTL[ENT_VAL] = 1, otherwise zeroes will be read.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_ENT register
+ */
+/*@{*/
+#define TRNG_ENT_REG(base, index) ((base)->ENT[index])
+#define TRNG_RD_ENT(base, index) (TRNG_ENT_REG(base, index))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SEC_CFG - RNG Security Configuration Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SEC_CFG - RNG Security Configuration Register (RW)
+ *
+ * Reset value: 0x00000000U
+ *
+ * The RNG Security Configuration Register is a read/write register used to
+ * control the test mode, programmability and state modes of the RNG. Many bits are
+ * place holders for this version. More configurability will be added here. Clears
+ * on asynchronous reset. For SA-TRNG releases before 2014/July/01, offsets 0xA0
+ * to 0xAC used to be 0xB0 to 0xBC respectively. So, update newer tests that use
+ * these registers, if hard coded.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SEC_CFG register
+ */
+/*@{*/
+#define TRNG_SEC_CFG_REG(base) ((base)->SEC_CFG)
+#define TRNG_RD_SEC_CFG(base) (TRNG_SEC_CFG_REG(base))
+#define TRNG_WR_SEC_CFG(base, value) (TRNG_SEC_CFG_REG(base) = (value))
+#define TRNG_RMW_SEC_CFG(base, mask, value) (TRNG_WR_SEC_CFG(base, (TRNG_RD_SEC_CFG(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SEC_CFG, field NO_PRGM[1] (RW)
+ *
+ * If set the TRNG registers cannot be programmed. That is, regardless of the
+ * TRNG access mode in the SA-TRNG Miscellaneous Control Register.
+ *
+ * Values:
+ * - 0b0 - Programability of registers controlled only by the RNG Miscellaneous
+ * Control Register's access mode bit.
+ * - 0b1 - Overides RNG Miscellaneous Control Register access mode and prevents
+ * TRNG register programming.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SEC_CFG_NO_PRGM field. */
+#define TRNG_RD_SEC_CFG_NO_PRGM(base) \
+ ((TRNG_SEC_CFG_REG(base) & TRNG_SEC_CFG_NO_PRGM_MASK) >> TRNG_SEC_CFG_NO_PRGM_SHIFT)
+
+/*! @brief Set the NO_PRGM field to a new value. */
+#define TRNG_WR_SEC_CFG_NO_PRGM(base, value) \
+ (TRNG_RMW_SEC_CFG(base, TRNG_SEC_CFG_NO_PRGM_MASK, TRNG_SEC_CFG_NO_PRGM(value)))
+/*@}*/
+
+/*! @brief Array to map TRNG instance number to base pointer. */
+static TRNG_Type *const s_trngBases[] = TRNG_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Clock array name */
+static const clock_ip_name_t s_trngClock[] = TRNG_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_TRNG_HAS_RSTCTL) && (FSL_FEATURE_TRNG_HAS_RSTCTL > 0)
+static const reset_ip_name_t trng_reset = TRNG_RSTS;
+#endif /* FSL_FEATURE_TRNG_HAS_RSTCTL */
+
+/*******************************************************************************
+ * Prototypes
+ *******************************************************************************/
+static status_t trng_ApplyUserConfig(TRNG_Type *base, const trng_config_t *userConfig);
+static status_t trng_SetRetryCount(TRNG_Type *base, uint8_t retry_count);
+static status_t trng_SetMonobitLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit1Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit2Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit3Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit4Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit5Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit6Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetPokerMaxLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetFrequencyCountMaxLimit(TRNG_Type *base, uint32_t limit_minimum, uint32_t limit_maximum);
+static status_t trng_SetStatisticalCheckLimit(TRNG_Type *base,
+ trng_statistical_check_t statistical_check,
+ const trng_statistical_check_limit_t *limit);
+static uint32_t trng_ReadEntropy(TRNG_Type *base, uint32_t index);
+static uint32_t trng_GetInstance(TRNG_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t trng_GetInstance(TRNG_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_trngBases); instance++)
+ {
+ if (s_trngBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_trngBases));
+
+ return instance;
+}
+
+/*FUNCTION*********************************************************************
+ *
+ * Function Name : TRNG_InitUserConfigDefault
+ * Description : Initializes user configuration structure to default settings.
+ *
+ *END*************************************************************************/
+/*!
+ * brief Initializes the user configuration structure to default values.
+ *
+ * This function initializes the configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * userConfig->lock = 0;
+ * userConfig->clockMode = kTRNG_ClockModeRingOscillator;
+ * userConfig->ringOscDiv = kTRNG_RingOscDiv0; Or to other kTRNG_RingOscDiv[2|8] depending on the platform.
+ * userConfig->sampleMode = kTRNG_SampleModeRaw;
+ * userConfig->entropyDelay = 3200;
+ * userConfig->sampleSize = 2500;
+ * userConfig->sparseBitLimit = TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT;
+ * userConfig->retryCount = 63;
+ * userConfig->longRunMaxLimit = 34;
+ * userConfig->monobitLimit.maximum = 1384;
+ * userConfig->monobitLimit.minimum = 1116;
+ * userConfig->runBit1Limit.maximum = 405;
+ * userConfig->runBit1Limit.minimum = 227;
+ * userConfig->runBit2Limit.maximum = 220;
+ * userConfig->runBit2Limit.minimum = 98;
+ * userConfig->runBit3Limit.maximum = 125;
+ * userConfig->runBit3Limit.minimum = 37;
+ * userConfig->runBit4Limit.maximum = 75;
+ * userConfig->runBit4Limit.minimum = 11;
+ * userConfig->runBit5Limit.maximum = 47;
+ * userConfig->runBit5Limit.minimum = 1;
+ * userConfig->runBit6PlusLimit.maximum = 47;
+ * userConfig->runBit6PlusLimit.minimum = 1;
+ * userConfig->pokerLimit.maximum = 26912;
+ * userConfig->pokerLimit.minimum = 24445;
+ * userConfig->frequencyCountLimit.maximum = 25600;
+ * userConfig->frequencyCountLimit.minimum = 1600;
+ * endcode
+ *
+ * param userConfig User configuration structure.
+ * return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_GetDefaultConfig(trng_config_t *userConfig)
+{
+ status_t result;
+
+ if (userConfig != NULL)
+ {
+ /* Initializes the configuration structure to default values. */
+
+ /* Lock programmability of TRNG registers. */
+ userConfig->lock = (bool)TRNG_USER_CONFIG_DEFAULT_LOCK;
+ /* Clock settings */
+ userConfig->clockMode = kTRNG_ClockModeRingOscillator;
+ userConfig->ringOscDiv = TRNG_USER_CONFIG_DEFAULT_OSC_DIV;
+ userConfig->sampleMode = kTRNG_SampleModeRaw;
+ /* Seed control*/
+ userConfig->entropyDelay = TRNG_USER_CONFIG_DEFAULT_ENTROPY_DELAY;
+ userConfig->sampleSize = TRNG_USER_CONFIG_DEFAULT_SAMPLE_SIZE;
+ userConfig->sparseBitLimit = TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT;
+
+ /* Statistical Check Parameters.*/
+ userConfig->retryCount = TRNG_USER_CONFIG_DEFAULT_RETRY_COUNT;
+ userConfig->longRunMaxLimit = TRNG_USER_CONFIG_DEFAULT_RUN_MAX_LIMIT;
+
+ userConfig->monobitLimit.maximum = TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM;
+ userConfig->monobitLimit.minimum = TRNG_USER_CONFIG_DEFAULT_MONOBIT_MINIMUM;
+ userConfig->runBit1Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM;
+ userConfig->runBit1Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MINIMUM;
+ userConfig->runBit2Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM;
+ userConfig->runBit2Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MINIMUM;
+ userConfig->runBit3Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM;
+ userConfig->runBit3Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MINIMUM;
+ userConfig->runBit4Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM;
+ userConfig->runBit4Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MINIMUM;
+ userConfig->runBit5Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM;
+ userConfig->runBit5Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MINIMUM;
+ userConfig->runBit6PlusLimit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM;
+ userConfig->runBit6PlusLimit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MINIMUM;
+ /* Limits for statistical check of "Poker Test". */
+ userConfig->pokerLimit.maximum = TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM;
+ userConfig->pokerLimit.minimum = TRNG_USER_CONFIG_DEFAULT_POKER_MINIMUM;
+ /* Limits for statistical check of entropy sample frequency count. */
+ userConfig->frequencyCountLimit.maximum = TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM;
+ userConfig->frequencyCountLimit.minimum = TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM;
+
+ result = kStatus_Success;
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Sets the TRNG retry count.
+ *
+ * This function sets the retry counter which defines the number of times a
+ * statistical check may fails during the TRNG Entropy Generation before
+ * generating an error.
+ */
+static status_t trng_SetRetryCount(TRNG_Type *base, uint8_t retry_count)
+{
+ status_t status;
+
+ if ((retry_count >= 1u) && (retry_count <= 15u))
+ {
+ /* Set retry count.*/
+ TRNG_WR_SCMISC_RTY_CT(base, retry_count);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Check Monobit Limit Register .
+ *
+ * This function set register TRNG_SCML - Statistical Check Monobit Limit Register
+ */
+static status_t trng_SetMonobitLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xffffu) && (limit_maximum <= 0xffffu))
+
+ {
+ /* Set TRNG_SCML register */
+ TRNG_WR_SCML_MONO_MAX(base, limit_maximum);
+ TRNG_WR_SCML_MONO_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 1 Limit Register .
+ *
+ * This function set register TRNG_SCR1L - Statistical Check Run Length 1 Limit Register
+ */
+static status_t trng_SetRunBit1Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7fffu) && (limit_maximum <= 0x7fffu))
+ {
+ /* Set TRNG_SCR1L register */
+ TRNG_WR_SCR1L_RUN1_MAX(base, limit_maximum);
+ TRNG_WR_SCR1L_RUN1_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 2 Limit Register .
+ *
+ * This function set register TRNG_SCR2L - Statistical Check Run Length 2 Limit Register
+ */
+static status_t trng_SetRunBit2Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x3fffu) && (limit_maximum <= 0x3fffu))
+ {
+ /* Set TRNG_SCR2L register */
+ TRNG_WR_SCR2L_RUN2_MAX(base, limit_maximum);
+ TRNG_WR_SCR2L_RUN2_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 3 Limit Register .
+ *
+ * This function set register TRNG_SCR3L - Statistical Check Run Length 3 Limit Register
+ */
+static status_t trng_SetRunBit3Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x1fffu) && (limit_maximum <= 0x1fffu))
+ {
+ /* Set TRNG_SCR3L register */
+ TRNG_WR_SCR3L_RUN3_MAX(base, limit_maximum);
+ TRNG_WR_SCR3L_RUN3_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 4 Limit Register .
+ * This function set register TRNG_SCR4L - Statistical Check Run Length 4 Limit Register
+ */
+static status_t trng_SetRunBit4Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xfffu) && (limit_maximum <= 0xfffu))
+ {
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L)
+ /* Set TRNG_SCR4L register */
+ TRNG_WR_SCR4L_RUN4_MAX(base, limit_maximum);
+ TRNG_WR_SCR4L_RUN4_RNG(base, range);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR4L */
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 5 Limit Register .
+ * This function set register TRNG_SCR5L - Statistical Check Run Length 5 Limit Register
+ */
+static status_t trng_SetRunBit5Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7ffu) && (limit_maximum <= 0x7ffu))
+ {
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L)
+ /* Set TRNG_SCR5L register */
+ TRNG_WR_SCR5L_RUN5_MAX(base, limit_maximum);
+ TRNG_WR_SCR5L_RUN5_RNG(base, range);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR5L */
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 6 Limit Register .
+ * This function set register TRNG_SCR6L - Statistical Check Run Length 6 Limit Register
+ */
+static status_t trng_SetRunBit6Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7ffu) && (limit_maximum <= 0x7ffu))
+ {
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L) && FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L)
+ /* Set TRNG_SCR6L register */
+ TRNG_WR_SCR6PL_RUN6P_MAX(base, limit_maximum);
+ TRNG_WR_SCR6PL_RUN6P_RNG(base, range);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SCR6L */
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Poker Maximum Limit Register.
+ * This function set register TRNG_PKRMAX - Poker Maximum Limit Register
+ */
+static status_t trng_SetPokerMaxLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xffffu) && (limit_maximum <= 0xffffffu))
+ {
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX) && FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX)
+ /* Set TRNG_PKRMAX register */
+ TRNG_WR_PKRMAX_PKR_MAX(base, limit_maximum);
+ TRNG_WR_PKRRNG_PKR_RNG(base, range);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_PKRMAX */
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Frequency Count Maximum Limit Register.
+ * This function set register TRNG_FRQMAX - Frequency Count Maximum Limit Register
+ */
+static status_t trng_SetFrequencyCountMaxLimit(TRNG_Type *base, uint32_t limit_minimum, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((limit_minimum <= 0x3fffffu) && (limit_maximum <= 0x3fffffu))
+ {
+ /* Set FRQMAX register */
+ TRNG_WR_FRQMAX_FRQ_MAX(base, limit_maximum);
+ TRNG_WR_FRQMIN_FRQ_MIN(base, limit_minimum);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical check limits.
+ *
+ * This function is used to set minimum and maximum limits of statistical checks.
+ *
+ */
+static status_t trng_SetStatisticalCheckLimit(TRNG_Type *base,
+ trng_statistical_check_t statistical_check,
+ const trng_statistical_check_limit_t *limit)
+{
+ uint32_t range;
+ status_t status = kStatus_Success;
+
+ if ((NULL != limit) && (limit->maximum > limit->minimum))
+ {
+ range = limit->maximum - limit->minimum; /* Registers use range instead of minimum value.*/
+
+ if (statistical_check == kTRNG_StatisticalCheckMonobit) /* Allowable maximum and minimum number of ones/zero
+ detected during entropy generation. */
+ {
+ status = trng_SetMonobitLimit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit1) /* Allowable maximum and minimum number of runs of
+ length 1 detected during entropy generation. */
+ {
+ status = trng_SetRunBit1Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit2) /* Allowable maximum and minimum number of runs of
+ length 2 detected during entropy generation. */
+ {
+ status = trng_SetRunBit2Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit3) /* Allowable maximum and minimum number of runs of
+ length 3 detected during entropy generation. */
+ {
+ status = trng_SetRunBit3Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit4) /* Allowable maximum and minimum number of runs of
+ length 4 detected during entropy generation. */
+ {
+ status = trng_SetRunBit4Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit5) /* Allowable maximum and minimum number of runs of
+ length 5 detected during entropy generation. */
+ {
+ status = trng_SetRunBit5Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit6Plus) /* Allowable maximum and minimum number of
+ length 6 or more detected during entropy
+ generation */
+ {
+ status = trng_SetRunBit6Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckPoker) /* Allowable maximum and minimum limit of "Poker
+ Test" detected during entropy generation . */
+ {
+ status = trng_SetPokerMaxLimit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckFrequencyCount) /* Allowable maximum and minimum limit of
+ entropy sample frquency count during
+ entropy generation . */
+ {
+ status = trng_SetFrequencyCountMaxLimit(base, limit->minimum, limit->maximum);
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ }
+
+ return status;
+}
+
+/*FUNCTION*********************************************************************
+ *
+ * Function Name : trng_ApplyUserConfig
+ * Description : Apply user configuration settings to TRNG module.
+ *
+ *END*************************************************************************/
+static status_t trng_ApplyUserConfig(TRNG_Type *base, const trng_config_t *userConfig)
+{
+ status_t status;
+
+ /* Set retry count */
+ status = trng_SetRetryCount(base, userConfig->retryCount);
+
+ /* Set statistical check limit */
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckMonobit, &userConfig->monobitLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit1, &userConfig->runBit1Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit2, &userConfig->runBit2Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit3, &userConfig->runBit3Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit4, &userConfig->runBit4Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit5, &userConfig->runBit5Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit6Plus, &userConfig->runBit6PlusLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckPoker, &userConfig->pokerLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status =
+ trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckFrequencyCount, &userConfig->frequencyCountLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ /* Set clock mode used to operate TRNG */
+ TRNG_WR_MCTL_FOR_SCLK(base, userConfig->clockMode);
+ /* Set ring oscillator divider used by TRNG */
+ TRNG_WR_MCTL_OSC_DIV(base, userConfig->ringOscDiv);
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE) && FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE)
+ /* Set sample mode of the TRNG ring oscillator. */
+ TRNG_WR_MCTL_SAMP_MODE(base, userConfig->sampleMode);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_MCTL_SAMP_MODE */
+ /* Set length of each Entropy sample taken */
+ TRNG_WR_SDCTL_ENT_DLY(base, userConfig->entropyDelay);
+ /* Set number of entropy samples that will be taken during Entropy generation */
+ TRNG_WR_SDCTL_SAMP_SIZE(base, userConfig->sampleSize);
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM > 0))
+ /* Set Sparse Bit Limit */
+ TRNG_WR_SBLIM_SB_LIM(base, userConfig->sparseBitLimit);
+#endif /* FSL_FEATURE_TRNG_HAS_NO_TRNG_SBLIM */
+ TRNG_WR_SCMISC_LRUN_MAX(base, userConfig->longRunMaxLimit);
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Gets a entry data from the TRNG.
+ *
+ * This function gets an entropy data from TRNG.
+ * Entropy data is spread over TRNG_ENT_COUNT registers.
+ * Read register number is defined by index parameter.
+ */
+static uint32_t trng_ReadEntropy(TRNG_Type *base, uint32_t index)
+{
+ uint32_t data;
+
+ index = index % TRNG_ENT_COUNT; /* This way we can use incremental index without limit control from application.*/
+
+ data = TRNG_RD_ENT(base, index);
+
+ if (index == (TRNG_ENT_COUNT - 1u))
+ {
+ /* Dummy read. Defect workaround.
+ * TRNG could not clear ENT_VAL flag automatically, application
+ * had to do a dummy reading operation for anyone TRNG register
+ * to clear it firstly, then to read the RTENT0 to RTENT15 again */
+ index = TRNG_RD_ENT(base, 0);
+ }
+
+ return data;
+}
+
+/*!
+ * brief Initializes the TRNG.
+ *
+ * This function initializes the TRNG.
+ * When called, the TRNG entropy generation starts immediately.
+ *
+ * param base TRNG base address
+ * param userConfig Pointer to the initialization configuration structure.
+ * return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_Init(TRNG_Type *base, const trng_config_t *userConfig)
+{
+ status_t result;
+
+ /* Check input parameters.*/
+ if ((base != NULL) && (userConfig != NULL))
+ {
+#if defined(FSL_FEATURE_TRNG_HAS_RSTCTL) && (FSL_FEATURE_TRNG_HAS_RSTCTL > 0)
+ /* Reset TRNG peripheral */
+ SYSCTL2->TRNG_PIN_CTRL |= SYSCTL2_TRNG_PIN_CTRL_ENABLE_MASK;
+ RESET_PeripheralReset(trng_reset);
+#endif /* FSL_FEATURE_TRNG_HAS_RSTCTL */
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock gate. */
+ CLOCK_EnableClock(s_trngClock[trng_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Clear pending errors, set program mode and reset the registers to default values.*/
+ /* MCTL[PRGM] = 1 (kTRNG_WorkModeProgram); MCTL[ERR] = 1; MCTL[RST_DEF] = 1 */
+ TRNG_RMW_MCTL(base, (TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK | TRNG_MCTL_RST_DEF_MASK),
+ TRNG_MCTL_PRGM(kTRNG_WorkModeProgram) | TRNG_MCTL_ERR(1) | TRNG_MCTL_RST_DEF(1));
+
+ /* Set configuration.*/
+ if ((result = trng_ApplyUserConfig(base, userConfig)) == kStatus_Success)
+ {
+ /* Start entropy generation.*/
+ /* Set to Run mode.*/
+ TRNG_WR_MCTL_PRGM(base, kTRNG_WorkModeRun);
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC > 0))
+ /* Enable TRNG Access Mode. To generate an Entropy
+ * value that can be read via the true0-true15 registers.*/
+ TRNG_WR_MCTL_TRNG_ACC(base, 1);
+#endif /* !FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC */
+
+ (void)trng_ReadEntropy(base, (TRNG_ENT_COUNT - 1u));
+
+ if (true == userConfig->lock) /* Disable programmability of TRNG registers. */
+ {
+ TRNG_WR_SEC_CFG_NO_PRGM(base, 1);
+ }
+
+ result = kStatus_Success;
+ }
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Shuts down the TRNG.
+ *
+ * This function shuts down the TRNG.
+ *
+ * param base TRNG base address.
+ */
+void TRNG_Deinit(TRNG_Type *base)
+{
+ /* Check input parameters.*/
+ if (NULL != base)
+ {
+ /* Move to program mode. Stop entropy generation.*/
+ TRNG_WR_MCTL_PRGM(base, kTRNG_WorkModeProgram);
+
+ /* Check before clock stop.
+ TRNG turns on the TRNG free-running ring oscillator whenever new entropy
+ is being generated and turns off the ring oscillator when entropy generation
+ is complete. If the TRNG clock is stopped while the TRNG ring oscillator
+ is running, the oscillator continues running though the RNG clock.
+ is stopped. */
+ while (TRNG_RD_MCTL_TSTOP_OK(base) == 0u)
+ {
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable Clock*/
+ CLOCK_DisableClock(s_trngClock[trng_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ }
+}
+
+/*!
+ * brief Gets random data.
+ *
+ * This function gets random data from the TRNG.
+ *
+ * param base TRNG base address.
+ * param data Pointer address used to store random data.
+ * param dataSize Size of the buffer pointed by the data parameter.
+ * return random data
+ */
+status_t TRNG_GetRandomData(TRNG_Type *base, void *data, size_t dataSize)
+{
+ status_t result = kStatus_Success;
+ uint32_t random_32;
+ uint8_t *random_p;
+ uint32_t random_size;
+ uint8_t *data_p = (uint8_t *)data;
+ uint32_t i;
+ uint32_t tmpValidFlag;
+ uint32_t tmpErrorFlag;
+
+ int index = 0;
+
+ /* Check input parameters.*/
+ if ((NULL != base) && (NULL != data) && (0U != dataSize))
+ {
+ /* After a deepsleep exit some errors bits are set in MCTL and must be cleared before processing further.
+ Also, trigger new 512 bits entropy generation to be sure we will have fresh bits.*/
+ if (0U != TRNG_RD_MCTL_ERR(base))
+ {
+ /* clear errors bits */
+ TRNG_WR_MCTL_ERR(base, 1);
+ /* restart new entropy generation */
+ (void)trng_ReadEntropy(base, (TRNG_ENT_COUNT - 1u));
+ }
+
+ do
+ {
+ /* Wait for Valid or Error flag*/
+ tmpValidFlag = TRNG_RD_MCTL_ENT_VAL(base);
+ tmpErrorFlag = TRNG_RD_MCTL_ERR(base);
+ while ((tmpValidFlag == 0u) && (tmpErrorFlag == 0u))
+ {
+ tmpValidFlag = TRNG_RD_MCTL_ENT_VAL(base);
+ tmpErrorFlag = TRNG_RD_MCTL_ERR(base);
+ }
+
+ /* Check HW error.*/
+ if (0U != TRNG_RD_MCTL_ERR(base))
+ {
+ result = kStatus_Fail; /* TRNG module error occurred */
+ /* Clear error.*/
+ TRNG_WR_MCTL_ERR(base, 1);
+ break; /* No sense stay here.*/
+ }
+
+ /* Read Entropy.*/
+ random_32 = trng_ReadEntropy(base, (uint32_t)index++);
+
+ random_p = (uint8_t *)&random_32;
+
+ if (dataSize < sizeof(random_32))
+ {
+ random_size = dataSize;
+ }
+ else
+ {
+ random_size = sizeof(random_32);
+ }
+
+ for (i = 0U; i < random_size; i++)
+ {
+ *data_p++ = *random_p++;
+ }
+
+ dataSize -= random_size;
+ } while (dataSize > 0u);
+
+ /* Start a new entropy generation.
+ It is done by reading of the last entropy register.*/
+ if (((unsigned)index % TRNG_ENT_COUNT) != 0U)
+ {
+ (void)trng_ReadEntropy(base, (TRNG_ENT_COUNT - 1u));
+ }
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+#endif /* FSL_FEATURE_SOC_TRNG_COUNT */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.h b/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.h
new file mode 100644
index 0000000000..a8f995f05f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/trng/fsl_trng.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2018, 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_TRNG_DRIVER_H_
+#define _FSL_TRNG_DRIVER_H_
+
+#include "fsl_common.h"
+
+#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && FSL_FEATURE_SOC_TRNG_COUNT
+
+/*!
+ * @addtogroup trng
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief TRNG driver version 2.0.15.
+ *
+ * Current version: 2.0.15
+ *
+
+ * Change log:
+ * - version 2.0.15
+ * - Changed TRNG_USER_CONFIG_DEFAULT_XXX values according to latest reccomended by design team.
+ * - version 2.0.14
+ * - add support for RW610 and RW612
+ * - version 2.0.13
+ * - After deepsleep it might return error, added clearing bits in TRNG_GetRandomData() and generating new entropy.
+ * - Modified reloading entropy in TRNG_GetRandomData(), for some data length it doesn't reloading entropy correctly.
+ * - version 2.0.12
+ * - For KW34A4_SERIES, KW35A4_SERIES, KW36A4_SERIES set TRNG_USER_CONFIG_DEFAULT_OSC_DIV to kTRNG_RingOscDiv8.
+ * - version 2.0.11
+ * - Add clearing pending errors in TRNG_Init().
+ * - version 2.0.10
+ * - Fixed doxygen issues.
+ * - version 2.0.9
+ * - Fix HIS_CCM metrics issues.
+ * - version 2.0.8
+ * - For K32L2A41A_SERIES set TRNG_USER_CONFIG_DEFAULT_OSC_DIV to kTRNG_RingOscDiv4.
+ * - version 2.0.7
+ * - Fix MISRA 2004 issue rule 12.5.
+ * - version 2.0.6
+ * - For KW35Z4_SERIES set TRNG_USER_CONFIG_DEFAULT_OSC_DIV to kTRNG_RingOscDiv8.
+ * - version 2.0.5
+ * - Add possibility to define default TRNG configuration by device specific preprocessor macros
+ * for FRQMIN, FRQMAX and OSCDIV.
+ * - version 2.0.4
+ * - Fix MISRA-2012 issues.
+ * - Version 2.0.3
+ * - update TRNG_Init to restart entropy generation
+ * - Version 2.0.2
+ * - fix MISRA issues
+ * - Version 2.0.1
+ * - add support for KL8x and KL28Z
+ * - update default OSCDIV for K81 to divide by 2
+ */
+#define FSL_TRNG_DRIVER_VERSION (MAKE_VERSION(2, 0, 15))
+/*@}*/
+
+/*! @brief TRNG sample mode. Used by trng_config_t. */
+typedef enum _trng_sample_mode
+{
+ kTRNG_SampleModeVonNeumann = 0U, /*!< Use von Neumann data in both Entropy shifter and Statistical Checker. */
+ kTRNG_SampleModeRaw = 1U, /*!< Use raw data into both Entropy shifter and Statistical Checker. */
+ kTRNG_SampleModeVonNeumannRaw =
+ 2U /*!< Use von Neumann data in Entropy shifter. Use raw data into Statistical Checker. */
+} trng_sample_mode_t;
+
+/*! @brief TRNG clock mode. Used by trng_config_t. */
+typedef enum _trng_clock_mode
+{
+ kTRNG_ClockModeRingOscillator = 0U, /*!< Ring oscillator is used to operate the TRNG (default). */
+ kTRNG_ClockModeSystem = 1U /*!< System clock is used to operate the TRNG. This is for test use only, and
+ indeterminate results may occur. */
+} trng_clock_mode_t;
+
+/*! @brief TRNG ring oscillator divide. Used by trng_config_t. */
+typedef enum _trng_ring_osc_div
+{
+ kTRNG_RingOscDiv0 = 0U, /*!< Ring oscillator with no divide */
+ kTRNG_RingOscDiv2 = 1U, /*!< Ring oscillator divided-by-2. */
+ kTRNG_RingOscDiv4 = 2U, /*!< Ring oscillator divided-by-4. */
+ kTRNG_RingOscDiv8 = 3U /*!< Ring oscillator divided-by-8. */
+} trng_ring_osc_div_t;
+
+/*! @brief Data structure for definition of statistical check limits. Used by trng_config_t. */
+typedef struct _trng_statistical_check_limit
+{
+ uint32_t maximum; /*!< Maximum limit.*/
+ uint32_t minimum; /*!< Minimum limit.*/
+} trng_statistical_check_limit_t;
+
+/*!
+ * @brief Data structure for the TRNG initialization
+ *
+ * This structure initializes the TRNG by calling the TRNG_Init() function.
+ * It contains all TRNG configurations.
+ */
+typedef struct _trng_user_config
+{
+ bool lock; /*!< @brief Disable programmability of TRNG registers. */
+ trng_clock_mode_t clockMode; /*!< @brief Clock mode used to operate TRNG.*/
+ trng_ring_osc_div_t ringOscDiv; /*!< @brief Ring oscillator divide used by TRNG. */
+ trng_sample_mode_t sampleMode; /*!< @brief Sample mode of the TRNG ring oscillator. */
+ /* Seed Control*/
+ uint16_t
+ entropyDelay; /*!< @brief Entropy Delay. Defines the length (in system clocks) of each Entropy sample taken. */
+ uint16_t sampleSize; /*!< @brief Sample Size. Defines the total number of Entropy samples that will be taken during
+ Entropy generation. */
+ uint16_t sparseBitLimit; /*!< @brief Sparse Bit Limit which defines the maximum number of
+ * consecutive samples that may be discarded before an error is generated.
+ * This limit is used only for during von Neumann sampling (enabled by
+ * TRNG_HAL_SetSampleMode()). Samples are discarded if two consecutive raw samples are both
+ * 0 or both 1. If this discarding occurs for a long period of time, it indicates that
+ * there is insufficient Entropy. */
+ /* Statistical Check Parameters.*/
+ uint8_t retryCount; /*!< @brief Retry count. It defines the number of times a statistical check may fails
+ * during the TRNG Entropy Generation before generating an error. */
+ uint8_t longRunMaxLimit; /*!< @brief Largest allowable number of consecutive samples of all 1, or all 0,
+ * that is allowed during the Entropy generation. */
+ trng_statistical_check_limit_t monobitLimit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of ones/zero detected during entropy generation. */
+ trng_statistical_check_limit_t runBit1Limit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of runs of length 1 detected during entropy generation. */
+ trng_statistical_check_limit_t runBit2Limit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of runs of length 2 detected during entropy generation. */
+ trng_statistical_check_limit_t runBit3Limit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of runs of length 3 detected during entropy generation. */
+ trng_statistical_check_limit_t runBit4Limit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of runs of length 4 detected during entropy generation. */
+ trng_statistical_check_limit_t runBit5Limit; /*!< @brief Maximum and minimum limits for statistical check of number
+ of runs of length 5 detected during entropy generation. */
+ trng_statistical_check_limit_t runBit6PlusLimit; /*!< @brief Maximum and minimum limits for statistical check of
+ number of runs of length 6 or more detected during entropy
+ generation. */
+ trng_statistical_check_limit_t
+ pokerLimit; /*!< @brief Maximum and minimum limits for statistical check of "Poker Test". */
+ trng_statistical_check_limit_t frequencyCountLimit; /*!< @brief Maximum and minimum limits for statistical check of
+ entropy sample frequency count. */
+} trng_config_t;
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the user configuration structure to default values.
+ *
+ * This function initializes the configuration structure to default values. The default
+ * values are as follows.
+ * @code
+ * userConfig->lock = 0;
+ * userConfig->clockMode = kTRNG_ClockModeRingOscillator;
+ * userConfig->ringOscDiv = kTRNG_RingOscDiv0; Or to other kTRNG_RingOscDiv[2|8] depending on the platform.
+ * userConfig->sampleMode = kTRNG_SampleModeRaw;
+ * userConfig->entropyDelay = 3200;
+ * userConfig->sampleSize = 2500;
+ * userConfig->sparseBitLimit = 63;
+ * userConfig->retryCount = 1;
+ * userConfig->longRunMaxLimit = 32;
+ * userConfig->monobitLimit.maximum = 317;
+ * userConfig->monobitLimit.minimum = 195;
+ * userConfig->runBit1Limit.maximum = 107;
+ * userConfig->runBit1Limit.minimum = 27;
+ * userConfig->runBit2Limit.maximum = 62;
+ * userConfig->runBit2Limit.minimum = 7;
+ * userConfig->runBit3Limit.maximum = 39;
+ * userConfig->runBit3Limit.minimum = 0;
+ * userConfig->runBit4Limit.maximum = 26;
+ * userConfig->runBit4Limit.minimum = 0;
+ * userConfig->runBit5Limit.maximum = 18;
+ * userConfig->runBit5Limit.minimum = 0;
+ * userConfig->runBit6PlusLimit.maximum = 17;
+ * userConfig->runBit6PlusLimit.minimum = 0;
+ * userConfig->pokerLimit.maximum = 1600;
+ * userConfig->pokerLimit.minimum = 1030;
+ * userConfig->frequencyCountLimit.maximum = 30000;
+ * userConfig->frequencyCountLimit.minimum = 1600;
+ * @endcode
+ *
+ * @param userConfig User configuration structure.
+ * @return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_GetDefaultConfig(trng_config_t *userConfig);
+
+/*!
+ * @brief Initializes the TRNG.
+ *
+ * This function initializes the TRNG.
+ * When called, the TRNG entropy generation starts immediately.
+ *
+ * @param base TRNG base address
+ * @param userConfig Pointer to the initialization configuration structure.
+ * @return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_Init(TRNG_Type *base, const trng_config_t *userConfig);
+
+/*!
+ * @brief Shuts down the TRNG.
+ *
+ * This function shuts down the TRNG.
+ *
+ * @param base TRNG base address.
+ */
+void TRNG_Deinit(TRNG_Type *base);
+
+/*!
+ * @brief Gets random data.
+ *
+ * This function gets random data from the TRNG.
+ *
+ * @param base TRNG base address.
+ * @param data Pointer address used to store random data.
+ * @param dataSize Size of the buffer pointed by the data parameter.
+ * @return random data
+ */
+status_t TRNG_GetRandomData(TRNG_Type *base, void *data, size_t dataSize);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* FSL_FEATURE_SOC_TRNG_COUNT */
+#endif /*_FSL_TRNG_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.c b/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.c
new file mode 100644
index 0000000000..f2c82d8cde
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.c
@@ -0,0 +1,2480 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_usdhc.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 */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#include "fsl_memory.h"
+#endif
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.usdhc"
+#endif
+
+/*! @brief Clock setting */
+/* Max SD clock divisor from base clock */
+#define USDHC_MAX_DVS ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
+#define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
+#define USDHC_PREV_DVS(x) ((x) -= 1U)
+#define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
+/*! @brief USDHC ADMA table address align size */
+#define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U)
+
+/* Typedef for interrupt handler. */
+typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
+/*! @brief check flag avalibility */
+#define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
+
+/*! @brief usdhc transfer flags */
+enum _usdhc_transfer_flags
+{
+ kUSDHC_CommandOnly = 1U, /*!< transfer command only */
+ kUSDHC_CommandAndTxData = 2U, /*!< transfer command and transmit data */
+ kUSDHC_CommandAndRxData = 4U, /*!< transfer command and receive data */
+ kUSDHC_DataWithAutoCmd12 = 8U, /*!< transfer data with auto cmd12 enabled */
+ kUSDHC_DataWithAutoCmd23 = 16U, /*!< transfer data with auto cmd23 enabled */
+ kUSDHC_BootData = 32U, /*!< transfer boot data */
+ kUSDHC_BootDataContinuous = 64U, /*!< transfer boot data continuous */
+};
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+#define USDHC_ADDR_CPU_2_DMA(addr) (MEMORY_ConvertMemoryMapAddress((addr), kMEMORY_Local2DMA))
+#else
+#define USDHC_ADDR_CPU_2_DMA(addr) (addr)
+#endif
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Instance number.
+ */
+static uint32_t USDHC_GetInstance(USDHC_Type *base);
+
+/*!
+ * @brief Start transfer according to current transfer state
+ *
+ * @param base USDHC peripheral base address.
+ * @param transferFlags transfer flags, @ref _usdhc_transfer_flags.
+ * @param blockSize block size.
+ * @param blockCount block count.
+ */
+static status_t USDHC_SetTransferConfig(USDHC_Type *base,
+ uint32_t transferFlags,
+ size_t blockSize,
+ uint32_t blockCount);
+
+/*!
+ * @brief Receive command response
+ *
+ * @param base USDHC peripheral base address.
+ * @param command Command to be sent.
+ */
+static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command);
+
+/*!
+ * @brief Read DATAPORT when buffer enable bit is set.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time transaction.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Read data by using DATAPORT polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @retval kStatus_Fail Read DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
+
+/*!
+ * @brief Write DATAPORT when buffer enable bit is set.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Write data by using DATAPORT polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Write DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @param use DMA flag.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_InvalidArgument Argument is invalid.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
+
+/*!
+ * @brief wait command done
+ *
+ * @param base USDHC peripheral base address.
+ * @param command configuration
+ * @param pollingCmdDone polling command done flag
+ */
+static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
+
+/*!
+ * @brief Handle card detect interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Card detect related interrupt flags.
+ */
+static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle command interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Command related interrupt flags.
+ */
+static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle data interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Data related interrupt flags.
+ */
+static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle SDIO card interrupt signal.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ */
+static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
+
+/*!
+ * @brief Handle SDIO block gap event.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ */
+static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+/*!
+ * @brief Handle retuning
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interrupt flags
+ */
+static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+#endif
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief USDHC base pointer array */
+static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
+
+/*! @brief USDHC internal handle pointer array */
+static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {0};
+
+/*! @brief USDHC IRQ name array */
+static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief USDHC clock array name */
+static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
+/*! @brief Pointers to USDHC resets for each instance. */
+static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS;
+#endif
+
+/* USDHC ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR;
+#else
+static usdhc_isr_t s_usdhcIsr;
+#endif
+/*! @brief Dummy data buffer for mmc boot mode */
+AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t USDHC_GetInstance(USDHC_Type *base)
+{
+ uint8_t instance = 0;
+
+ while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
+ {
+ instance++;
+ }
+
+ assert(instance < ARRAY_SIZE(s_usdhcBase));
+
+ return instance;
+}
+
+static status_t USDHC_SetTransferConfig(USDHC_Type *base, uint32_t transferFlags, size_t blockSize, uint32_t blockCount)
+{
+ uint32_t mixCtrl = base->MIX_CTRL;
+
+ if (((uint32_t)kUSDHC_CommandOnly & transferFlags) != 0U)
+ {
+ /* clear data flags */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
+ USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK);
+
+ if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
+ {
+ return kStatus_USDHC_BusyTransferring;
+ }
+ }
+ else
+ {
+ /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
+ if ((transferFlags & (uint32_t)kUSDHC_BootDataContinuous) != 0U)
+ {
+ /* clear stop at block gap request */
+ base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
+ /* continous transfer data */
+ base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
+ return kStatus_Success;
+ }
+
+ /* check data inhibit flag */
+ if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag))
+ {
+ return kStatus_USDHC_BusyTransferring;
+ }
+ /* check transfer block count */
+ if ((blockCount > USDHC_MAX_BLOCK_COUNT))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* config mix parameter */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
+ USDHC_MIX_CTRL_AC12EN_MASK);
+
+ if ((transferFlags & (uint32_t)kUSDHC_CommandAndRxData) != 0U)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
+ }
+
+ if (blockCount > 1U)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
+ /* auto command 12 */
+ if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd12) != 0U)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
+ }
+ }
+
+ /* auto command 23, auto send set block count cmd before multiple read/write */
+ if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd23) != 0U)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
+ /* config the block count to DS_ADDR */
+ base->DS_ADDR = blockCount;
+ }
+ else
+ {
+ mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
+ }
+
+ /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
+ if ((transferFlags & (uint32_t)kUSDHC_BootData) == 0U)
+ {
+ /* config data block size/block count */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
+ }
+ else
+ {
+ mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
+ base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
+ }
+ }
+ /* config the mix parameter */
+ base->MIX_CTRL = mixCtrl;
+
+ return kStatus_Success;
+}
+
+void USDHC_SetDataConfig(USDHC_Type *base,
+ usdhc_transfer_direction_t dataDirection,
+ uint32_t blockCount,
+ uint32_t blockSize)
+{
+ assert(blockCount <= USDHC_MAX_BLOCK_COUNT);
+
+ uint32_t mixCtrl = base->MIX_CTRL;
+
+ /* block attribute configuration */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
+
+ /* config mix parameter */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK);
+
+ mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U);
+
+ base->MIX_CTRL = mixCtrl;
+}
+
+static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
+{
+ assert(command != NULL);
+
+ uint32_t response0 = base->CMD_RSP0;
+ uint32_t response1 = base->CMD_RSP1;
+ uint32_t response2 = base->CMD_RSP2;
+
+ if (command->responseType != kCARD_ResponseTypeNone)
+ {
+ command->response[0U] = response0;
+ if (command->responseType == kCARD_ResponseTypeR2)
+ {
+ /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
+ after removed internal CRC7 and end bit. */
+ command->response[0U] <<= 8U;
+ command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
+ command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
+ command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U);
+ }
+ }
+
+ /* check response error flag */
+ if ((command->responseErrorFlags != 0U) &&
+ ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
+ (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
+ {
+ if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
+ {
+ return kStatus_USDHC_SendCommandFailed;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeRead; /* The words can be read at this time. */
+ uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
+
+ /* If DMA is enable, do not need to polling data port */
+ if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
+ {
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
+ if (readWatermark >= totalWords)
+ {
+ wordsCanBeRead = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
+ transfers watermark level words. */
+ else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
+ {
+ wordsCanBeRead = readWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
+ left
+ words. */
+ else
+ {
+ wordsCanBeRead = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeRead)
+ {
+ data->rxData[transferredWords++] = USDHC_ReadData(base);
+ i++;
+ }
+ }
+
+ return transferredWords;
+}
+
+static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
+{
+ uint32_t totalWords;
+ uint32_t transferredWords = 0U, interruptStatus = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (
+ !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag |
+ (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ /* during std tuning process, software do not need to read data, but wait BRR is enough */
+ if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) &&
+ (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag)))
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
+
+ return kStatus_Success;
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
+ /* if tuning error occur ,return directly */
+ error = kStatus_USDHC_TuningError;
+ }
+#endif
+ else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ /* clear data error flag */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (error == kStatus_Success)
+ {
+ transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
+ /* clear buffer read ready */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
+ interruptStatus = 0U;
+ }
+ }
+
+ /* Clear data complete flag after the last read operation. */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
+
+ return error;
+}
+
+static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
+ uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
+
+ /* If DMA is enable, do not need to polling data port */
+ if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
+ {
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
+ if (writeWatermark >= totalWords)
+ {
+ wordsCanBeWrote = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
+ transfers watermark level words. */
+ else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
+ {
+ wordsCanBeWrote = writeWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
+ words. */
+ else
+ {
+ wordsCanBeWrote = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeWrote)
+ {
+ USDHC_WriteData(base, data->txData[transferredWords++]);
+ i++;
+ }
+ }
+
+ return transferredWords;
+}
+
+static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
+{
+ uint32_t totalWords;
+
+ uint32_t transferredWords = 0U, interruptStatus = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag |
+ (uint32_t)kUSDHC_DataErrorFlag |
+ (uint32_t)kUSDHC_TuningErrorFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
+ /* if tuning error occur ,return directly */
+ return kStatus_USDHC_TuningError;
+ }
+ else
+#endif
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ /* clear data error flag */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (error == kStatus_Success)
+ {
+ transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
+ /* clear buffer write ready */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
+ interruptStatus = 0U;
+ }
+ }
+
+ /* Wait write data complete or data transfer error after the last writing operation. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL)
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+ USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag));
+
+ return error;
+}
+
+/*!
+ * brief send command function
+ *
+ * param base USDHC peripheral base address.
+ * param command configuration
+ */
+void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
+{
+ assert(NULL != command);
+
+ uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
+
+ if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
+ {
+ if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) ||
+ (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
+ (uint32_t)kUSDHC_EnableIndexCheckFlag);
+ }
+ else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
+ (uint32_t)kUSDHC_EnableIndexCheckFlag);
+ }
+ else if (command->responseType == kCARD_ResponseTypeR2)
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag);
+ }
+ else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48Flag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (command->type == kCARD_CommandTypeAbort)
+ {
+ flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag;
+ }
+
+ /* config cmd index */
+ xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
+ USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
+
+ xferType |=
+ (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
+ ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
+ USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
+
+ /* config the command xfertype and argument */
+ base->CMD_ARG = command->argument;
+ base->CMD_XFR_TYP = xferType;
+ }
+
+ if (command->type == kCARD_CommandTypeEmpty)
+ {
+ /* disable CMD done interrupt for empty command */
+ base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
+ }
+}
+
+static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
+{
+ assert(NULL != command);
+
+ status_t error = kStatus_Success;
+ uint32_t interruptStatus = 0U;
+ /* check if need polling command done or not */
+ if (pollingCmdDone)
+ {
+ /* Wait command complete or USDHC encounters error. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL)
+ {
+ error = kStatus_Fail;
+ }
+
+ /* Receive response when command completes successfully. */
+ if (error == kStatus_Success)
+ {
+ error = USDHC_ReceiveCommandResponse(base, command);
+ }
+
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
+ }
+
+ return error;
+}
+
+static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
+{
+ status_t error = kStatus_Success;
+ uint32_t interruptStatus = 0U;
+
+ if (enDMA)
+ {
+ /* Wait data complete or USDHC encounters error. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ error = kStatus_USDHC_TuningError;
+ }
+ else
+#endif
+ if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
+ {
+ if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag)))
+ {
+ error = kStatus_USDHC_TransferDataFailed;
+ }
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ /* load dummy data */
+ if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
+ {
+ *(data->rxData) = s_usdhcBootDummy;
+ }
+
+ USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag));
+ }
+ else
+ {
+ if (data->rxData != NULL)
+ {
+ error = USDHC_ReadByDataPortBlocking(base, data);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+ }
+ else
+ {
+ error = USDHC_WriteByDataPortBlocking(base, data);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+/*!
+ * brief USDHC module initialization function.
+ *
+ * Configures the USDHC according to the user configuration.
+ *
+ * Example:
+ code
+ usdhc_config_t config;
+ config.cardDetectDat3 = false;
+ config.endianMode = kUSDHC_EndianModeLittle;
+ config.dmaMode = kUSDHC_DmaModeAdma2;
+ config.readWatermarkLevel = 128U;
+ config.writeWatermarkLevel = 128U;
+ USDHC_Init(USDHC, &config);
+ endcode
+ *
+ * param base USDHC peripheral base address.
+ * param config USDHC configuration information.
+ * retval kStatus_Success Operate successfully.
+ */
+void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
+{
+ assert(config != NULL);
+ assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
+ assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
+#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ assert(config->writeBurstLen <= 16U);
+#endif
+ uint32_t proctl, sysctl, wml;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable USDHC clock. */
+ CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
+#endif
+
+#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
+ /* Reset the USDHC module */
+ RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]);
+#endif
+
+ /* Reset ALL USDHC. */
+ base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK;
+
+ proctl = base->PROT_CTRL;
+ wml = base->WTMK_LVL;
+ sysctl = base->SYS_CTRL;
+
+ proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
+ /* Endian mode*/
+ proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
+
+#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ /* Watermark level */
+ wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK);
+ wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel));
+#else
+ /* Watermark level */
+ wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
+ USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
+ wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
+ USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
+#endif
+
+ /* config the data timeout value */
+ sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
+ sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
+
+ base->SYS_CTRL = sysctl;
+ base->WTMK_LVL = wml;
+ base->PROT_CTRL = proctl;
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ /* disable external DMA */
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+#endif
+ /* disable internal DMA and DDR mode */
+ base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
+ /* disable interrupt, enable all the interrupt status, clear status. */
+ base->INT_STATUS_EN = kUSDHC_AllInterruptFlags;
+ base->INT_SIGNAL_EN = 0UL;
+ base->INT_STATUS = kUSDHC_AllInterruptFlags;
+}
+
+/*!
+ * brief Deinitializes the USDHC.
+ *
+ * param base USDHC peripheral base address.
+ */
+void USDHC_Deinit(USDHC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable clock. */
+ CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
+#endif
+}
+
+/*!
+ * brief Resets the USDHC.
+ *
+ * param base USDHC peripheral base address.
+ * param mask The reset type mask(_usdhc_reset).
+ * param timeout Timeout for reset.
+ * retval true Reset successfully.
+ * retval false Reset failed.
+ */
+bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
+{
+ base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ | USDHC_SYS_CTRL_RSTT_MASK
+#endif
+ ));
+ /* Delay some time to wait reset success. */
+ while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask))
+ {
+ if (timeout == 0UL)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((0UL == timeout) ? false : true);
+}
+
+/*!
+ * brief Gets the capability information.
+ *
+ * param base USDHC peripheral base address.
+ * param capability Structure to save capability information.
+ */
+void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
+{
+ assert(capability != NULL);
+
+ uint32_t htCapability;
+ uint32_t maxBlockLength;
+
+ htCapability = base->HOST_CTRL_CAP;
+
+ /* Get the capability of USDHC. */
+ maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
+ capability->maxBlockLength = (512UL << maxBlockLength);
+ /* Other attributes not in HTCAPBLT register. */
+ capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
+ capability->flags =
+ (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK |
+ USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK));
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK;
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
+#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
+ capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
+#endif
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
+ capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
+#endif
+ /* USDHC support 4/8 bit data bus width. */
+ capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
+}
+
+/*!
+ * brief Sets the SD bus clock frequency.
+ *
+ * param base USDHC peripheral base address.
+ * param srcClock_Hz USDHC source clock frequency united in Hz.
+ * param busClock_Hz SD bus clock frequency united in Hz.
+ *
+ * return The nearest frequency of busClock_Hz configured to SD bus.
+ */
+uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
+{
+ assert(srcClock_Hz != 0U);
+ assert(busClock_Hz != 0U);
+
+ uint32_t totalDiv = 0UL;
+ uint32_t divisor = 0UL;
+ uint32_t prescaler = 0UL;
+ uint32_t sysctl = 0UL;
+ uint32_t nearestFrequency = 0UL;
+
+ if (busClock_Hz > srcClock_Hz)
+ {
+ busClock_Hz = srcClock_Hz;
+ }
+
+ totalDiv = srcClock_Hz / busClock_Hz;
+
+ /* calucate total divisor first */
+ if (totalDiv > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
+ {
+ return 0UL;
+ }
+
+ if (totalDiv != 0UL)
+ {
+ /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
+ if ((srcClock_Hz / totalDiv) > busClock_Hz)
+ {
+ totalDiv++;
+ }
+
+ /* divide the total divisor to div and prescaler */
+ if (totalDiv > USDHC_MAX_DVS)
+ {
+ prescaler = totalDiv / USDHC_MAX_DVS;
+ /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
+ while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL))
+ {
+ prescaler++;
+ }
+ /* calucate the divisor */
+ divisor = totalDiv / prescaler;
+ /* fine tuning the divisor until divisor * prescaler >= totalDiv */
+ while ((divisor * prescaler) < totalDiv)
+ {
+ divisor++;
+ if (divisor > USDHC_MAX_DVS)
+ {
+ prescaler <<= 1UL;
+ if (prescaler > USDHC_MAX_CLKFS)
+ {
+ return 0UL;
+ }
+ divisor = totalDiv / prescaler;
+ }
+ }
+ }
+ else
+ {
+ /* in this situation , divsior and SDCLKFS can generate same clock
+ use SDCLKFS*/
+ if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL))
+ {
+ divisor = totalDiv;
+ prescaler = 1UL;
+ }
+ else
+ {
+ divisor = 1UL;
+ prescaler = totalDiv;
+ }
+ }
+ nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler;
+ }
+ /* in this condition , srcClock_Hz = busClock_Hz, */
+ else
+ {
+ /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
+ totoal divider = 2U */
+ divisor = 0UL;
+ prescaler = 0UL;
+ nearestFrequency = srcClock_Hz;
+ }
+
+ /* calucate the value write to register */
+ if (divisor != 0UL)
+ {
+ USDHC_PREV_DVS(divisor);
+ }
+ /* calucate the value write to register */
+ if (prescaler != 0UL)
+ {
+ USDHC_PREV_CLKFS(prescaler, 1UL);
+ }
+
+ /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
+ sysctl = base->SYS_CTRL;
+ sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
+ sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
+ base->SYS_CTRL = sysctl;
+
+ /* Wait until the SD clock is stable. */
+ while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK))
+ {
+ }
+
+ return nearestFrequency;
+}
+
+/*!
+ * brief Sends 80 clocks to the card to set it to the active state.
+ *
+ * This function must be called each time the card is inserted to ensure that the card can receive the command
+ * correctly.
+ *
+ * param base USDHC peripheral base address.
+ * param timeout Timeout to initialize card.
+ * retval true Set card active successfully.
+ * retval false Set card active failed.
+ */
+bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
+{
+ base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
+ /* Delay some time to wait card become active state. */
+ while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK))
+ {
+ if (0UL == timeout)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((0UL == timeout) ? false : true);
+}
+
+/*!
+ * brief the enable/disable DDR mode
+ *
+ * param base USDHC peripheral base address.
+ * param enable/disable flag
+ * param nibble position
+ */
+void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
+{
+ uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
+
+ if (enable)
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
+ base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
+ prescaler >>= 1UL;
+ }
+ else
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
+
+ if (prescaler == 0UL)
+ {
+ prescaler += 1UL;
+ }
+ else
+ {
+ prescaler <<= 1UL;
+ }
+ }
+
+ base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
+}
+
+/*!
+ * brief Configures the MMC boot feature.
+ *
+ * Example:
+ code
+ usdhc_boot_config_t config;
+ config.ackTimeoutCount = 4;
+ config.bootMode = kUSDHC_BootModeNormal;
+ config.blockCount = 5;
+ config.enableBootAck = true;
+ config.enableBoot = true;
+ config.enableAutoStopAtBlockGap = true;
+ USDHC_SetMmcBootConfig(USDHC, &config);
+ endcode
+ *
+ * param base USDHC peripheral base address.
+ * param config The MMC boot configuration information.
+ */
+void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
+{
+ assert(config != NULL);
+ assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
+ assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
+
+ uint32_t mmcboot = base->MMC_BOOT;
+
+ mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
+ mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
+
+ if (config->enableBootAck)
+ {
+ mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
+ }
+ if (config->enableAutoStopAtBlockGap)
+ {
+ mmcboot |=
+ USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
+ /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
+ }
+ else
+ {
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
+ }
+
+ base->MMC_BOOT = mmcboot;
+}
+
+/*!
+ * brief Sets the ADMA1 descriptor table configuration.
+ *
+ * param admaTable Adma table address.
+ * param admaTableWords Adma table length.
+ * param dataBufferAddr Data buffer address.
+ * param dataBytes Data length.
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA1Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
+{
+ assert(NULL != admaTable);
+ assert(NULL != dataBufferAddr);
+
+ uint32_t miniEntries, startEntries = 0UL,
+ maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
+ usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable);
+ uint32_t i, dmaBufferLen = 0UL;
+ const uint32_t *data = dataBufferAddr;
+
+ if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ return kStatus_USDHC_NotSupport;
+ }
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0UL)
+ {
+ /* make the data length as word-aligned */
+ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
+ {
+ miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
+ }
+
+ /* ADMA1 needs two descriptors to finish a transfer */
+ miniEntries <<= 1UL;
+
+ if (miniEntries + startEntries > maxEntries)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ for (i = startEntries; i < (miniEntries + startEntries); i += 2UL)
+ {
+ if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ dmaBufferLen = dataBytes;
+ }
+
+ adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+ adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength;
+ adma1EntryAddress[i + 1UL] = (uint32_t)(data);
+ adma1EntryAddress[i + 1UL] |=
+ (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma1DescriptorInterrupFlag;
+ data = (uint32_t *)((uint32_t)data + dmaBufferLen);
+ dataBytes -= dmaBufferLen;
+ }
+ /* the end of the descriptor */
+ adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets the ADMA2 descriptor table configuration.
+ *
+ * param admaTable Adma table address.
+ * param admaTableWords Adma table length.
+ * param dataBufferAddr Data buffer address.
+ * param dataBytes Data Data length.
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA2Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
+{
+ assert(NULL != admaTable);
+ assert(NULL != dataBufferAddr);
+
+ uint32_t miniEntries, startEntries = 0UL,
+ maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
+ usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable);
+ uint32_t i, dmaBufferLen = 0UL;
+ const uint32_t *data = dataBufferAddr;
+
+ if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0UL)
+ {
+ /* make the data length as word-aligned */
+ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
+ {
+ miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
+ }
+ /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
+ data adress and data size is enough */
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ for (i = 0UL; i < maxEntries; i++)
+ {
+ if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL)
+ {
+ break;
+ }
+ }
+ startEntries = i;
+ /* add one entry for dummy entry */
+ miniEntries += 1UL;
+ }
+
+ if ((miniEntries + startEntries) > maxEntries)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ for (i = startEntries; i < (miniEntries + startEntries); i++)
+ {
+ if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) :
+ dataBytes); /* adma don't support 0 data length transfer descriptor */
+ }
+
+ /* Each descriptor for ADMA2 is 64-bit in length */
+ adma2EntryAddress[i].address = (dataBytes == 0UL) ? &s_usdhcBootDummy : data;
+ adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+ adma2EntryAddress[i].attribute |=
+ (dataBytes == 0UL) ?
+ 0UL :
+ ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag);
+ data = (uint32_t *)((uint32_t)data + dmaBufferLen);
+
+ if (dataBytes != 0UL)
+ {
+ dataBytes -= dmaBufferLen;
+ }
+ }
+
+ /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
+ engine
+ will not stop at block gap */
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer;
+ }
+ else
+ {
+ /* set the end bit */
+ adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Internal DMA configuration.
+ * This function is used to config the USDHC DMA related registers.
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
+ * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to
+ * false.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ const uint32_t *dataAddr,
+ bool enAutoCmd23)
+{
+ assert(dmaConfig != NULL);
+ assert(dataAddr != NULL);
+ assert((NULL != dmaConfig->admaTable) &&
+ (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ /* disable the external DMA if support */
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+#endif
+
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
+ {
+ /* check DMA data buffer address align or not */
+ if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+ /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
+ and block count should load to DS_ADDR*/
+ if (enAutoCmd23)
+ {
+ base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
+ }
+ else
+ {
+ base->DS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
+ }
+ }
+ else
+ {
+ /* When use ADMA, disable simple DMA */
+ base->DS_ADDR = 0UL;
+ base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)(dmaConfig->admaTable));
+ }
+
+#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ /* select DMA mode and config the burst length */
+ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
+ base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
+#else
+ /* select DMA mode and config the burst length */
+ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
+ base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
+#endif
+ /* enable DMA */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets the DMA descriptor table configuration.
+ * A high level DMA descriptor configuration function.
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param data Data descriptor
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_data_t *dataConfig,
+ uint32_t flags)
+{
+ assert(NULL != dmaConfig);
+ assert((NULL != dmaConfig->admaTable) &&
+ (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
+ assert(NULL != dataConfig);
+
+ status_t error = kStatus_Fail;
+ uint32_t bootDummyOffset =
+ dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL;
+ const uint32_t *data = (const uint32_t *)USDHC_ADDR_CPU_2_DMA((uint32_t)(
+ (uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + bootDummyOffset));
+ uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ if (dmaConfig->dmaMode == kUSDHC_ExternalDMA)
+ {
+ /* enable the external DMA */
+ base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+ }
+ else
+#endif
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
+ {
+ error = kStatus_Success;
+ }
+ else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
+ {
+ error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
+ }
+ /* ADMA2 */
+ else
+ {
+ error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
+ }
+
+ /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
+ * boot data, only the DMA descriptor need update */
+ if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
+ (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous))
+ {
+ error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
+ }
+
+ return error;
+}
+
+/*!
+ * brief Transfers the command/data using a blocking method.
+ *
+ * This function waits until the command response/data is received or the USDHC encounters an error by polling the
+ * status
+ * flag.
+ * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
+ * the re-entry mechanism.
+ *
+ * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API.
+ *
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param transfer Transfer content.
+ * retval kStatus_InvalidArgument Argument is invalid.
+ * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * retval kStatus_USDHC_SendCommandFailed Send command failed.
+ * retval kStatus_USDHC_TransferDataFailed Transfer data failed.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
+{
+ assert(transfer != NULL);
+
+ status_t error = kStatus_Fail;
+ usdhc_command_t *command = transfer->command;
+ usdhc_data_t *data = transfer->data;
+ bool enDMA = true;
+ bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
+ uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
+ size_t blockSize = 0U;
+ size_t blockCount = 0U;
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ /*check re-tuning request*/
+ if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL)
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
+ return kStatus_USDHC_ReTuningRequest;
+ }
+#endif
+
+ if (data != NULL)
+ {
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if ((dmaConfig != NULL) && (!executeTuning))
+ {
+ error = USDHC_SetAdmaTableConfig(base, dmaConfig, data,
+ (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ?
+ kUSDHC_AdmaDescriptorMultipleFlag :
+ kUSDHC_AdmaDescriptorSingleFlag));
+ }
+ blockSize = data->blockSize;
+ blockCount = data->blockCount;
+ transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
+ transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
+ transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
+ transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
+ transferFlags |=
+ data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
+
+ command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
+ }
+
+ /* if the DMA desciptor configure fail or not needed , disable it */
+ if (error != kStatus_Success)
+ {
+ enDMA = false;
+ /* disable DMA, using polling mode in this situation */
+ USDHC_EnableInternalDMA(base, false);
+ }
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ else
+ {
+ if (data->txData != NULL)
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
+ }
+ else
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
+ }
+ }
+#endif
+
+ /* config the data transfer parameter */
+ error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+ /* send command first */
+ USDHC_SendCommand(base, command);
+ /* wait command done */
+ error =
+ USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal));
+ if (kStatus_Success != error)
+ {
+ return kStatus_USDHC_SendCommandFailed;
+ }
+
+ /* wait transfer data finsih */
+ if (data != NULL)
+ {
+ error = USDHC_TransferDataBlocking(base, data, enDMA);
+ if (kStatus_Success != error)
+ {
+ return error;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
+static status_t USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_scatter_gather_data_t *dataConfig,
+ uint32_t *totalTransferSize)
+{
+ assert(NULL != dmaConfig);
+ assert((NULL != dmaConfig->admaTable) &&
+ (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
+ assert(NULL != dataConfig);
+
+ status_t error = kStatus_Fail;
+ uint32_t *admaDesBuffer = dmaConfig->admaTable;
+ uint32_t admaDesLen = dmaConfig->admaTableWords;
+ usdhc_scatter_gather_data_list_t *sgDataList = &dataConfig->sgData;
+ uint32_t oneDescriptorMaxTransferSize = dmaConfig->dmaMode == kUSDHC_DmaModeAdma1 ?
+ USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY :
+ USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ uint32_t miniEntries = 0U;
+
+ while (sgDataList != NULL)
+ {
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
+ {
+ error = USDHC_SetADMA1Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
+ }
+ /* ADMA2 */
+ else
+ {
+ error = USDHC_SetADMA2Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
+ }
+
+ if (error != kStatus_Success)
+ {
+ return kStatus_USDHC_PrepareAdmaDescriptorFailed;
+ }
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (dataConfig->dataDirection == kUSDHC_TransferDirectionSend)
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
+ }
+ else
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanInvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
+ }
+#endif
+
+ *totalTransferSize += sgDataList->dataSize;
+ if (sgDataList->dataList != NULL)
+ {
+ if ((sgDataList->dataSize % oneDescriptorMaxTransferSize) == 0UL)
+ {
+ miniEntries = sgDataList->dataSize / oneDescriptorMaxTransferSize;
+ }
+ else
+ {
+ miniEntries = ((sgDataList->dataSize / oneDescriptorMaxTransferSize) + 1UL);
+ }
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
+ {
+ admaDesBuffer[miniEntries * 2U - 1U] &= ~kUSDHC_Adma1DescriptorEndFlag;
+ }
+ else
+ {
+ admaDesBuffer[miniEntries * 2U - 2U] &= ~kUSDHC_Adma2DescriptorEndFlag;
+ }
+ admaDesBuffer += miniEntries * 2U;
+ admaDesLen -= miniEntries * 2U;
+ }
+
+ sgDataList = sgDataList->dataList;
+ }
+
+ base->DS_ADDR = 0UL;
+ base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
+
+ /* select DMA mode and config the burst length */
+ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
+ base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
+
+ /* enable DMA */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
+
+ return error;
+}
+
+/*!
+ * brief Transfers the command/scatter gather data using an interrupt and an asynchronous method.
+ *
+ * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
+ * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
+ * this API doesn't support the re-entry mechanism.
+ * This function is target for the application would like to have scatter gather buffer to be transferred within one
+ * read/write request, non scatter gather buffer is support by this function also.
+ *
+ * note Call API @ref USDHC_TransferCreateHandle when calling this API.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle.
+ * param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only.
+ * param transfer scatter gather transfer content.
+ *
+ * retval #kStatus_InvalidArgument Argument is invalid.
+ * retval #kStatus_USDHC_BusyTransferring Busy transferring.
+ * retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_scatter_gather_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+ assert(dmaConfig != NULL);
+
+ status_t error = kStatus_Fail;
+ usdhc_command_t *command = transfer->command;
+ uint32_t totalTransferSize = 0U;
+ uint32_t transferFlags = kUSDHC_CommandOnly;
+ size_t blockSize = 0U;
+ size_t blockCount = 0U;
+ usdhc_scatter_gather_data_t *scatterGatherData = transfer->data;
+ bool enDMA = false;
+
+ /* check data inhibit flag */
+ if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
+ {
+ return kStatus_USDHC_BusyTransferring;
+ }
+
+ handle->command = command;
+ handle->data = scatterGatherData;
+ /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
+ handle->transferredWords = 0UL;
+
+ /* Update ADMA descriptor table according to different DMA mode(ADMA1, ADMA2).*/
+ if (scatterGatherData != NULL)
+ {
+ if (scatterGatherData->sgData.dataAddr == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (scatterGatherData->dataType != (uint32_t)kUSDHC_TransferDataTuning)
+ {
+ if (USDHC_SetScatterGatherAdmaTableConfig(base, dmaConfig, transfer->data, &totalTransferSize) !=
+ kStatus_Success)
+ {
+ return kStatus_USDHC_PrepareAdmaDescriptorFailed;
+ }
+
+ enDMA = true;
+ }
+ blockSize = scatterGatherData->blockSize;
+ blockCount = totalTransferSize / scatterGatherData->blockSize;
+ transferFlags = scatterGatherData->enableAutoCommand12 ? kUSDHC_DataWithAutoCmd12 : 0U;
+ transferFlags |= scatterGatherData->enableAutoCommand23 ? kUSDHC_DataWithAutoCmd23 : 0U;
+ transferFlags |= scatterGatherData->dataDirection == kUSDHC_TransferDirectionSend ? kUSDHC_CommandAndTxData :
+ kUSDHC_CommandAndRxData;
+ command->flags |= kUSDHC_DataPresentFlag;
+ }
+
+ error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+
+ /* enable interrupt per transfer request */
+ if (scatterGatherData != NULL)
+ {
+ USDHC_ClearInterruptStatusFlags(
+ base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
+ (uint32_t)kUSDHC_CommandFlag);
+ USDHC_EnableInterruptSignal(
+ base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
+ (uint32_t)kUSDHC_CommandFlag);
+ }
+ else
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
+ USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
+ }
+
+ /* send command first */
+ USDHC_SendCommand(base, command);
+
+ return kStatus_Success;
+}
+#else
+/*!
+ * brief Transfers the command/data using an interrupt and an asynchronous method.
+ *
+ * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
+ * error.
+ * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
+ * the re-entry mechanism.
+ *
+ * note Call the API 'USDHC_TransferCreateHandle' when calling this API.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle.
+ * param adma configuration.
+ * param transfer Transfer content.
+ * retval kStatus_InvalidArgument Argument is invalid.
+ * retval kStatus_USDHC_BusyTransferring Busy transferring.
+ * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferNonBlocking(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ status_t error = kStatus_Fail;
+ usdhc_command_t *command = transfer->command;
+ usdhc_data_t *data = transfer->data;
+ bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
+ bool enDMA = true;
+ uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
+ size_t blockSize = 0U;
+ size_t blockCount = 0U;
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ /*check re-tuning request*/
+ if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL)
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
+ return kStatus_USDHC_ReTuningRequest;
+ }
+#endif
+ /* Save command and data into handle before transferring. */
+
+ handle->command = command;
+ handle->data = data;
+ /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
+ handle->transferredWords = 0UL;
+
+ if (data != NULL)
+ {
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if ((dmaConfig != NULL) && (!executeTuning))
+ {
+ error = USDHC_SetAdmaTableConfig(
+ base, dmaConfig, data,
+ (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ?
+ kUSDHC_AdmaDescriptorMultipleFlag :
+ kUSDHC_AdmaDescriptorSingleFlag));
+ }
+
+ blockSize = data->blockSize;
+ blockCount = data->blockCount;
+ transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
+ transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
+ transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
+ transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
+ transferFlags |=
+ data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
+
+ command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
+ }
+
+ /* if the DMA desciptor configure fail or not needed , disable it */
+ if (error != kStatus_Success)
+ {
+ /* disable DMA, using polling mode in this situation */
+ USDHC_EnableInternalDMA(base, false);
+ enDMA = false;
+ }
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ else
+ {
+ if (data->txData != NULL)
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
+ }
+ else
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
+ }
+ }
+#endif
+
+ /* config the data transfer parameter */
+ error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+
+ /* enable interrupt per transfer request */
+ if (handle->data != NULL)
+ {
+ USDHC_ClearInterruptStatusFlags(
+ base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag |
+ (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
+ (uint32_t)kUSDHC_DmaCompleteFlag :
+ 0U));
+ USDHC_EnableInterruptSignal(base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) |
+ (uint32_t)kUSDHC_CommandFlag |
+ (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
+ (uint32_t)kUSDHC_DmaCompleteFlag :
+ 0U));
+ }
+ else
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
+ USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
+ }
+
+ /* send command first */
+ USDHC_SendCommand(base, command);
+
+ return kStatus_Success;
+}
+#endif
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+/*!
+ * brief manual tuning trigger or abort
+ * User should handle the tuning cmd and find the boundary of the delay
+ * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS
+ * This function should called before USDHC_AdjustDelayforSDR104 function
+ * param base USDHC peripheral base address.
+ * param tuning enable flag
+ */
+void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* make sure std_tun_en bit is clear */
+ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
+ /* disable auto tuning here */
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
+ /* execute tuning for SDR104 mode */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK;
+ }
+ else
+ { /* abort the tuning */
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK;
+ }
+}
+
+/*!
+ * brief the SDR104 mode delay setting adjust
+ * This function should called after USDHC_ManualTuningForSDR104
+ * param base USDHC peripheral base address.
+ * param delay setting configuration
+ * retval kStatus_Fail config the delay setting fail
+ * retval kStatus_Success config the delay setting success
+ */
+status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
+{
+ uint32_t clkTuneCtrl = 0UL;
+
+ clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
+
+ clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
+
+ clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
+
+ /* load the delay setting */
+ base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
+ /* check delat setting error */
+ if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
+ USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief The tuning delay cell setting.
+ *
+ * param base USDHC peripheral base address.
+ * param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE.
+ * param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT.
+ * param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST.
+ * retval kStatus_Fail config the delay setting fail
+ * retval kStatus_Success config the delay setting success
+ */
+status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay)
+{
+ assert(preDelay <=
+ (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_SHIFT));
+ assert(outDelay <=
+ (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_SHIFT));
+ assert(postDelay <=
+ (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_SHIFT));
+
+ uint32_t clkTuneCtrl = 0UL;
+
+ clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
+
+ clkTuneCtrl &=
+ ~(USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK | USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK |
+ USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK);
+
+ clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(preDelay) |
+ USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT(outDelay) |
+ USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST(postDelay);
+
+ /* load the delay setting */
+ base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
+ /* check delat setting error */
+ if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
+ USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief the enable standard tuning function
+ * The standard tuning window and tuning counter use the default config
+ * tuning cmd is send by the software, user need to check the tuning result
+ * can be used for SDR50,SDR104,HS200 mode tuning
+ * param base USDHC peripheral base address.
+ * param tuning start tap
+ * param tuning step
+ * param enable/disable flag
+ */
+void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
+{
+ uint32_t tuningCtrl = 0UL;
+
+ if (enable)
+ {
+ /* feedback clock */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
+ /* config tuning start and step */
+ tuningCtrl = base->TUNING_CTRL;
+ tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
+ tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
+ USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
+ base->TUNING_CTRL = tuningCtrl;
+
+ /* excute tuning */
+ base->AUTOCMD12_ERR_STATUS |=
+ (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
+ }
+ else
+ {
+ /* disable the standard tuning */
+ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
+ /* clear excute tuning */
+ base->AUTOCMD12_ERR_STATUS &=
+ ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
+ }
+}
+
+#if FSL_FEATURE_USDHC_HAS_HS400_MODE
+/*!
+ * brief config the strobe DLL delay target and update interval
+ *
+ * param base USDHC peripheral base address.
+ * param delayTarget delay target
+ * param updateInterval update interval
+ */
+void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval)
+{
+ assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >>
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT));
+
+ /* reset strobe dll firstly */
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
+ /* clear reset and other register fields */
+ base->STROBE_DLL_CTRL = 0;
+ /* configure the DELAY target and update interval */
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget);
+
+ while (
+ (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK |
+ USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) !=
+ ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)))
+ {
+ }
+}
+#endif
+
+/*!
+ * brief the auto tuning enbale for CMD/DATA line
+ *
+ * param base USDHC peripheral base address.
+ */
+void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
+{
+ uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
+
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
+
+ /* 1bit data width */
+ if (busWidth == 0UL)
+ {
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+ /* 4bit data width */
+ else if (busWidth == 1UL)
+ {
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+ /* 8bit data width */
+ else
+ {
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
+
+static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag))
+ {
+ if (handle->callback.CardInserted != NULL)
+ {
+ handle->callback.CardInserted(base, handle->userData);
+ }
+ }
+ else
+ {
+ if (handle->callback.CardRemoved != NULL)
+ {
+ handle->callback.CardRemoved(base, handle->userData);
+ }
+ }
+}
+
+static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->command != NULL);
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag))
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
+ }
+ }
+ else
+ {
+ /* Receive response */
+ if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
+ }
+ }
+ else
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData);
+ }
+ }
+ }
+ /* disable interrupt signal and reset command pointer */
+ USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag);
+ handle->command = NULL;
+}
+
+#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
+static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->data != NULL);
+
+ status_t transferStatus = kStatus_USDHC_BusyTransferring;
+
+ if ((!(handle->data->enableIgnoreError)) &&
+ (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
+ {
+ transferStatus = kStatus_USDHC_TransferDataFailed;
+ }
+ else
+ {
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
+ {
+ /* std tuning process only need to wait BRR */
+ if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+ }
+ }
+ else
+ {
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag))
+ {
+ transferStatus = kStatus_USDHC_TransferDMAComplete;
+ }
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->data->dataDirection == kUSDHC_TransferDirectionReceive)
+ {
+ usdhc_scatter_gather_data_list_t *sgDataList = &handle->data->sgData;
+ while (sgDataList != NULL)
+ {
+ DCACHE_InvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
+ sgDataList = sgDataList->dataList;
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
+ {
+ handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
+ USDHC_DisableInterruptSignal(
+ base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_DmaCompleteFlag);
+ handle->data = NULL;
+ }
+}
+
+#else
+static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->data != NULL);
+
+ status_t transferStatus = kStatus_USDHC_BusyTransferring;
+ uint32_t transferredWords = handle->transferredWords;
+
+ if ((!(handle->data->enableIgnoreError)) &&
+ (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
+ {
+ transferStatus = kStatus_USDHC_TransferDataFailed;
+ }
+ else
+ {
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
+ {
+ /* std tuning process only need to wait BRR */
+ if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+ }
+ else
+ {
+ handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords);
+ }
+ }
+ else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag))
+ {
+ handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords);
+ }
+ else
+ {
+ if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) &&
+ (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous))
+ {
+ *(handle->data->rxData) = s_usdhcBootDummy;
+ }
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->data->rxData != NULL)
+ {
+ DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData),
+ (handle->data->blockSize) * (handle->data->blockCount));
+ }
+#endif
+ }
+ }
+ }
+
+ if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
+ {
+ handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
+ USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag);
+ handle->data = NULL;
+ }
+}
+#endif
+
+static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ if (handle->callback.SdioInterrupt != NULL)
+ {
+ handle->callback.SdioInterrupt(base, handle->userData);
+ }
+}
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->callback.ReTuning != NULL);
+ /* retuning request */
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag))
+ {
+ handle->callback.ReTuning(base, handle->userData); /* retuning fail */
+ }
+}
+#endif
+
+static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ if (handle->callback.BlockGap != NULL)
+ {
+ handle->callback.BlockGap(base, handle->userData);
+ }
+}
+
+/*!
+ * brief Creates the USDHC handle.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle pointer.
+ * param callback Structure pointer to contain all callback functions.
+ * param userData Callback function parameter.
+ */
+void USDHC_TransferCreateHandle(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ const usdhc_transfer_callback_t *callback,
+ void *userData)
+{
+ assert(handle != NULL);
+ assert(callback != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the callback. */
+ handle->callback.CardInserted = callback->CardInserted;
+ handle->callback.CardRemoved = callback->CardRemoved;
+ handle->callback.SdioInterrupt = callback->SdioInterrupt;
+ handle->callback.BlockGap = callback->BlockGap;
+ handle->callback.TransferComplete = callback->TransferComplete;
+ handle->callback.ReTuning = callback->ReTuning;
+ handle->userData = userData;
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_usdhcHandle[USDHC_GetInstance(base)] = handle;
+
+ /* save IRQ handler */
+ s_usdhcIsr = USDHC_TransferHandleIRQ;
+
+ (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
+}
+
+/*!
+ * brief IRQ handler for the USDHC.
+ *
+ * This function deals with the IRQs on the given host controller.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle.
+ */
+void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t interruptFlags;
+
+ interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base);
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag))
+ {
+ USDHC_TransferHandleCardDetect(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag))
+ {
+ USDHC_TransferHandleCommand(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag))
+ {
+ USDHC_TransferHandleData(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag))
+ {
+ USDHC_TransferHandleSdioInterrupt(base, handle);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag))
+ {
+ USDHC_TransferHandleBlockGap(base, handle);
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag))
+ {
+ USDHC_TransferHandleReTuning(base, handle, interruptFlags);
+ }
+#endif
+ USDHC_ClearInterruptStatusFlags(base, interruptFlags);
+}
+
+#ifdef USDHC0
+void USDHC0_DriverIRQHandler(void);
+void USDHC0_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#ifdef USDHC1
+void USDHC1_DriverIRQHandler(void);
+void USDHC1_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#ifdef USDHC2
+void USDHC2_DriverIRQHandler(void);
+void USDHC2_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.h b/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.h
new file mode 100644
index 0000000000..9cf1fc07c3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/usdhc/fsl_usdhc.h
@@ -0,0 +1,1703 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_USDHC_H_
+#define _FSL_USDHC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup usdhc
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions.
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Driver version 2.8.2. */
+#define FSL_USDHC_DRIVER_VERSION (MAKE_VERSION(2U, 8U, 2U))
+/*@}*/
+
+/*! @brief Maximum block count can be set one time */
+#define USDHC_MAX_BLOCK_COUNT (USDHC_BLK_ATT_BLKCNT_MASK >> USDHC_BLK_ATT_BLKCNT_SHIFT)
+
+/*! @brief USDHC scatter gather feature control macro */
+#ifndef FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
+#define FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER 0U
+#endif
+
+/*! @brief Enum _usdhc_status. USDHC status. */
+enum
+{
+ kStatus_USDHC_BusyTransferring = MAKE_STATUS(kStatusGroup_USDHC, 0U), /*!< Transfer is on-going. */
+ kStatus_USDHC_PrepareAdmaDescriptorFailed = MAKE_STATUS(kStatusGroup_USDHC, 1U), /*!< Set DMA descriptor failed. */
+ kStatus_USDHC_SendCommandFailed = MAKE_STATUS(kStatusGroup_USDHC, 2U), /*!< Send command failed. */
+ kStatus_USDHC_TransferDataFailed = MAKE_STATUS(kStatusGroup_USDHC, 3U), /*!< Transfer data failed. */
+ kStatus_USDHC_DMADataAddrNotAlign = MAKE_STATUS(kStatusGroup_USDHC, 4U), /*!< Data address not aligned. */
+ kStatus_USDHC_ReTuningRequest = MAKE_STATUS(kStatusGroup_USDHC, 5U), /*!< Re-tuning request. */
+ kStatus_USDHC_TuningError = MAKE_STATUS(kStatusGroup_USDHC, 6U), /*!< Tuning error. */
+ kStatus_USDHC_NotSupport = MAKE_STATUS(kStatusGroup_USDHC, 7U), /*!< Not support. */
+ kStatus_USDHC_TransferDataComplete = MAKE_STATUS(kStatusGroup_USDHC, 8U), /*!< Transfer data complete. */
+ kStatus_USDHC_SendCommandSuccess = MAKE_STATUS(kStatusGroup_USDHC, 9U), /*!< Transfer command complete. */
+ kStatus_USDHC_TransferDMAComplete = MAKE_STATUS(kStatusGroup_USDHC, 10U), /*!< Transfer DMA complete. */
+};
+
+/*! @brief Enum _usdhc_capability_flag. Host controller capabilities flag mask.
+ * @anchor _usdhc_capability_flag
+ */
+enum
+{
+ kUSDHC_SupportAdmaFlag = USDHC_HOST_CTRL_CAP_ADMAS_MASK, /*!< Support ADMA. */
+ kUSDHC_SupportHighSpeedFlag = USDHC_HOST_CTRL_CAP_HSS_MASK, /*!< Support high-speed. */
+ kUSDHC_SupportDmaFlag = USDHC_HOST_CTRL_CAP_DMAS_MASK, /*!< Support DMA. */
+ kUSDHC_SupportSuspendResumeFlag = USDHC_HOST_CTRL_CAP_SRS_MASK, /*!< Support suspend/resume. */
+ kUSDHC_SupportV330Flag = USDHC_HOST_CTRL_CAP_VS33_MASK, /*!< Support voltage 3.3V. */
+ kUSDHC_SupportV300Flag = USDHC_HOST_CTRL_CAP_VS30_MASK, /*!< Support voltage 3.0V. */
+ kUSDHC_SupportV180Flag = USDHC_HOST_CTRL_CAP_VS18_MASK, /*!< Support voltage 1.8V. */
+ kUSDHC_Support4BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0U),
+ /*!< Flag in HTCAPBLT_MBL's position, supporting 4-bit mode. */
+ kUSDHC_Support8BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1U),
+ /*!< Flag in HTCAPBLT_MBL's position, supporting 8-bit mode. */
+ kUSDHC_SupportDDR50Flag = USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK,
+/*!< SD version 3.0 new feature, supporting DDR50 mode. */
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR104_MODE)
+ kUSDHC_SupportSDR104Flag = 0, /*!< not support SDR104 mode */
+#else
+ kUSDHC_SupportSDR104Flag = USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK, /*!< Support SDR104 mode. */
+#endif
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_SupportSDR50Flag = 0U, /*!< not support SDR50 mode */
+#else
+ kUSDHC_SupportSDR50Flag = USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK, /*!< Support SDR50 mode. */
+#endif
+};
+
+/*! @brief Enum _usdhc_wakeup_event. Wakeup event mask.
+ * @anchor _usdhc_wakeup_event
+ */
+enum
+{
+ kUSDHC_WakeupEventOnCardInt = USDHC_PROT_CTRL_WECINT_MASK, /*!< Wakeup on card interrupt. */
+ kUSDHC_WakeupEventOnCardInsert = USDHC_PROT_CTRL_WECINS_MASK, /*!< Wakeup on card insertion. */
+ kUSDHC_WakeupEventOnCardRemove = USDHC_PROT_CTRL_WECRM_MASK, /*!< Wakeup on card removal. */
+ kUSDHC_WakeupEventsAll =
+ (kUSDHC_WakeupEventOnCardInt | kUSDHC_WakeupEventOnCardInsert | kUSDHC_WakeupEventOnCardRemove),
+ /*!< All wakeup events */
+};
+
+/*! @brief Enum _usdhc_reset. Reset type mask.
+ * @anchor _usdhc_reset
+ */
+enum
+{
+ kUSDHC_ResetAll = USDHC_SYS_CTRL_RSTA_MASK, /*!< Reset all except card detection. */
+ kUSDHC_ResetCommand = USDHC_SYS_CTRL_RSTC_MASK, /*!< Reset command line. */
+ kUSDHC_ResetData = USDHC_SYS_CTRL_RSTD_MASK, /*!< Reset data line. */
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_ResetTuning = 0U, /*!< no reset tuning circuit bit */
+#else
+ kUSDHC_ResetTuning = USDHC_SYS_CTRL_RSTT_MASK, /*!< Reset tuning circuit. */
+#endif
+
+ kUSDHC_ResetsAll = (kUSDHC_ResetAll | kUSDHC_ResetCommand | kUSDHC_ResetData | kUSDHC_ResetTuning),
+ /*!< All reset types */
+};
+
+/*! @brief Enum _usdhc_transfer_flag. Transfer flag mask. */
+enum
+{
+ kUSDHC_EnableDmaFlag = USDHC_MIX_CTRL_DMAEN_MASK, /*!< Enable DMA. */
+
+ kUSDHC_CommandTypeSuspendFlag = USDHC_CMD_XFR_TYP_CMDTYP(1U), /*!< Suspend command. */
+ kUSDHC_CommandTypeResumeFlag = USDHC_CMD_XFR_TYP_CMDTYP(2U), /*!< Resume command. */
+ kUSDHC_CommandTypeAbortFlag = USDHC_CMD_XFR_TYP_CMDTYP(3U), /*!< Abort command. */
+
+ kUSDHC_EnableBlockCountFlag = USDHC_MIX_CTRL_BCEN_MASK, /*!< Enable block count. */
+ kUSDHC_EnableAutoCommand12Flag = USDHC_MIX_CTRL_AC12EN_MASK, /*!< Enable auto CMD12. */
+ kUSDHC_DataReadFlag = USDHC_MIX_CTRL_DTDSEL_MASK, /*!< Enable data read. */
+ kUSDHC_MultipleBlockFlag = USDHC_MIX_CTRL_MSBSEL_MASK, /*!< Multiple block data read/write. */
+ kUSDHC_EnableAutoCommand23Flag = USDHC_MIX_CTRL_AC23EN_MASK, /*!< Enable auto CMD23. */
+
+ kUSDHC_ResponseLength136Flag = USDHC_CMD_XFR_TYP_RSPTYP(1U), /*!< 136-bit response length. */
+ kUSDHC_ResponseLength48Flag = USDHC_CMD_XFR_TYP_RSPTYP(2U), /*!< 48-bit response length. */
+ kUSDHC_ResponseLength48BusyFlag = USDHC_CMD_XFR_TYP_RSPTYP(3U), /*!< 48-bit response length with busy status. */
+
+ kUSDHC_EnableCrcCheckFlag = USDHC_CMD_XFR_TYP_CCCEN_MASK, /*!< Enable CRC check. */
+ kUSDHC_EnableIndexCheckFlag = USDHC_CMD_XFR_TYP_CICEN_MASK, /*!< Enable index check. */
+ kUSDHC_DataPresentFlag = USDHC_CMD_XFR_TYP_DPSEL_MASK, /*!< Data present flag. */
+};
+
+/*! @brief Enum _usdhc_present_status_flag. Present status flag mask.
+ * @anchor _usdhc_present_status_flag
+ */
+enum
+{
+ kUSDHC_CommandInhibitFlag = USDHC_PRES_STATE_CIHB_MASK, /*!< Command inhibit. */
+ kUSDHC_DataInhibitFlag = USDHC_PRES_STATE_CDIHB_MASK, /*!< Data inhibit. */
+ kUSDHC_DataLineActiveFlag = USDHC_PRES_STATE_DLA_MASK, /*!< Data line active. */
+ kUSDHC_SdClockStableFlag = USDHC_PRES_STATE_SDSTB_MASK, /*!< SD bus clock stable. */
+ kUSDHC_WriteTransferActiveFlag = USDHC_PRES_STATE_WTA_MASK, /*!< Write transfer active. */
+ kUSDHC_ReadTransferActiveFlag = USDHC_PRES_STATE_RTA_MASK, /*!< Read transfer active. */
+ kUSDHC_BufferWriteEnableFlag = USDHC_PRES_STATE_BWEN_MASK, /*!< Buffer write enable. */
+ kUSDHC_BufferReadEnableFlag = USDHC_PRES_STATE_BREN_MASK, /*!< Buffer read enable. */
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_DelaySettingFinishedFlag = 0U, /*!< not support */
+ kUSDHC_ReTuningRequestFlag = 0U, /*!< not support */
+#else
+ kUSDHC_ReTuningRequestFlag = USDHC_PRES_STATE_RTR_MASK, /*!< Re-tuning request flag, only used for SDR104 mode. */
+ kUSDHC_DelaySettingFinishedFlag = USDHC_PRES_STATE_TSCD_MASK, /*!< Delay setting finished flag. */
+#endif
+
+ kUSDHC_CardInsertedFlag = USDHC_PRES_STATE_CINST_MASK, /*!< Card inserted. */
+ kUSDHC_CommandLineLevelFlag = USDHC_PRES_STATE_CLSL_MASK, /*!< Command line signal level. */
+
+ kUSDHC_Data0LineLevelFlag = 1U << USDHC_PRES_STATE_DLSL_SHIFT, /*!< Data0 line signal level. */
+ kUSDHC_Data1LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 1U), /*!< Data1 line signal level. */
+ kUSDHC_Data2LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 2U), /*!< Data2 line signal level. */
+ kUSDHC_Data3LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 3U), /*!< Data3 line signal level. */
+ kUSDHC_Data4LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 4U), /*!< Data4 line signal level. */
+ kUSDHC_Data5LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 5U), /*!< Data5 line signal level. */
+ kUSDHC_Data6LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 6U), /*!< Data6 line signal level. */
+ kUSDHC_Data7LineLevelFlag = (int)(1U << (USDHC_PRES_STATE_DLSL_SHIFT + 7U)), /*!< Data7 line signal level. */
+};
+
+/*! @brief Enum _usdhc_interrupt_status_flag. Interrupt status flag mask.
+ * @anchor _usdhc_interrupt_status_flag
+ */
+enum
+{
+ kUSDHC_CommandCompleteFlag = USDHC_INT_STATUS_CC_MASK, /*!< Command complete. */
+ kUSDHC_DataCompleteFlag = USDHC_INT_STATUS_TC_MASK, /*!< Data complete. */
+ kUSDHC_BlockGapEventFlag = USDHC_INT_STATUS_BGE_MASK, /*!< Block gap event. */
+ kUSDHC_DmaCompleteFlag = USDHC_INT_STATUS_DINT_MASK, /*!< DMA interrupt. */
+ kUSDHC_BufferWriteReadyFlag = USDHC_INT_STATUS_BWR_MASK, /*!< Buffer write ready. */
+ kUSDHC_BufferReadReadyFlag = USDHC_INT_STATUS_BRR_MASK, /*!< Buffer read ready. */
+ kUSDHC_CardInsertionFlag = USDHC_INT_STATUS_CINS_MASK, /*!< Card inserted. */
+ kUSDHC_CardRemovalFlag = USDHC_INT_STATUS_CRM_MASK, /*!< Card removed. */
+ kUSDHC_CardInterruptFlag = USDHC_INT_STATUS_CINT_MASK, /*!< Card interrupt. */
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_ReTuningEventFlag = 0U, /*!< Re-Tuning event, only for SD3.0 SDR104 mode. */
+ kUSDHC_TuningPassFlag = 0U, /*!< SDR104 mode tuning pass flag. */
+ kUSDHC_TuningErrorFlag = 0U, /*!< SDR104 tuning error flag. */
+#else
+ kUSDHC_ReTuningEventFlag = USDHC_INT_STATUS_RTE_MASK, /*!< Re-Tuning event, only for SD3.0 SDR104 mode. */
+ kUSDHC_TuningPassFlag = USDHC_INT_STATUS_TP_MASK, /*!< SDR104 mode tuning pass flag. */
+ kUSDHC_TuningErrorFlag = USDHC_INT_STATUS_TNE_MASK, /*!< SDR104 tuning error flag. */
+#endif
+
+ kUSDHC_CommandTimeoutFlag = USDHC_INT_STATUS_CTOE_MASK, /*!< Command timeout error. */
+ kUSDHC_CommandCrcErrorFlag = USDHC_INT_STATUS_CCE_MASK, /*!< Command CRC error. */
+ kUSDHC_CommandEndBitErrorFlag = USDHC_INT_STATUS_CEBE_MASK, /*!< Command end bit error. */
+ kUSDHC_CommandIndexErrorFlag = USDHC_INT_STATUS_CIE_MASK, /*!< Command index error. */
+ kUSDHC_DataTimeoutFlag = USDHC_INT_STATUS_DTOE_MASK, /*!< Data timeout error. */
+ kUSDHC_DataCrcErrorFlag = USDHC_INT_STATUS_DCE_MASK, /*!< Data CRC error. */
+ kUSDHC_DataEndBitErrorFlag = USDHC_INT_STATUS_DEBE_MASK, /*!< Data end bit error. */
+ kUSDHC_AutoCommand12ErrorFlag = USDHC_INT_STATUS_AC12E_MASK, /*!< Auto CMD12 error. */
+ kUSDHC_DmaErrorFlag = USDHC_INT_STATUS_DMAE_MASK, /*!< DMA error. */
+
+ kUSDHC_CommandErrorFlag = (kUSDHC_CommandTimeoutFlag | kUSDHC_CommandCrcErrorFlag | kUSDHC_CommandEndBitErrorFlag |
+ kUSDHC_CommandIndexErrorFlag), /*!< Command error */
+ kUSDHC_DataErrorFlag = (kUSDHC_DataTimeoutFlag | kUSDHC_DataCrcErrorFlag | kUSDHC_DataEndBitErrorFlag |
+ kUSDHC_AutoCommand12ErrorFlag), /*!< Data error */
+ kUSDHC_ErrorFlag = (kUSDHC_CommandErrorFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< All error */
+
+ kUSDHC_DataFlag = (kUSDHC_DataCompleteFlag | kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag |
+ kUSDHC_DataErrorFlag), /*!< Data interrupts */
+
+ kUSDHC_DataDMAFlag = (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< Data interrupts */
+
+ kUSDHC_CommandFlag = (kUSDHC_CommandErrorFlag | kUSDHC_CommandCompleteFlag), /*!< Command interrupts */
+ kUSDHC_CardDetectFlag = (kUSDHC_CardInsertionFlag | kUSDHC_CardRemovalFlag), /*!< Card detection interrupts */
+ kUSDHC_SDR104TuningFlag = (kUSDHC_TuningErrorFlag | kUSDHC_TuningPassFlag | kUSDHC_ReTuningEventFlag),
+ /*!< SDR104 tuning flag. */
+ kUSDHC_AllInterruptFlags =
+ (kUSDHC_BlockGapEventFlag | kUSDHC_CardInterruptFlag | kUSDHC_CommandFlag | kUSDHC_DataFlag | kUSDHC_ErrorFlag |
+ kUSDHC_SDR104TuningFlag | kUSDHC_DmaCompleteFlag), /*!< All flags mask */
+};
+
+/*! @brief Enum _usdhc_auto_command12_error_status_flag. Auto CMD12 error status flag mask.
+ * @anchor _usdhc_auto_command12_error_status_flag
+ */
+enum
+{
+ kUSDHC_AutoCommand12NotExecutedFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12NE_MASK, /*!< Not executed error. */
+ kUSDHC_AutoCommand12TimeoutFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12TOE_MASK, /*!< Timeout error. */
+ kUSDHC_AutoCommand12EndBitErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12EBE_MASK, /*!< End bit error. */
+ kUSDHC_AutoCommand12CrcErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12CE_MASK, /*!< CRC error. */
+ kUSDHC_AutoCommand12IndexErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12IE_MASK, /*!< Index error. */
+ kUSDHC_AutoCommand12NotIssuedFlag = USDHC_AUTOCMD12_ERR_STATUS_CNIBAC12E_MASK, /*!< Not issued error. */
+};
+
+/*! @brief Enum _usdhc_standard_tuning. Standard tuning flag. */
+enum
+{
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_ExecuteTuning = 0U, /*!< not support */
+ kUSDHC_TuningSampleClockSel = 0U, /*!< not support */
+#else
+ kUSDHC_ExecuteTuning = USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK, /*!< Used to start tuning procedure. */
+ kUSDHC_TuningSampleClockSel =
+ USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK, /*!< When <b>std_tuning_en</b> bit is set, this
+ bit is used to select sampleing clock. */
+#endif
+};
+
+/*! @brief Enum _usdhc_adma_error_status_flag. ADMA error status flag mask.
+ * @anchor _usdhc_adma_error_status_flag
+ */
+enum
+{
+ kUSDHC_AdmaLenghMismatchFlag = USDHC_ADMA_ERR_STATUS_ADMALME_MASK, /*!< Length mismatch error. */
+ kUSDHC_AdmaDescriptorErrorFlag = USDHC_ADMA_ERR_STATUS_ADMADCE_MASK, /*!< Descriptor error. */
+};
+
+/*!
+ * @brief Enum _usdhc_adma_error_state. ADMA error state.
+ *
+ * This state is the detail state when ADMA error has occurred.
+ */
+enum
+{
+ kUSDHC_AdmaErrorStateStopDma = 0x00U,
+ /*!< Stop DMA, previous location set in the ADMA system address is errored address. */
+ kUSDHC_AdmaErrorStateFetchDescriptor = 0x01U,
+ /*!< Fetch descriptor, current location set in the ADMA system address is errored address. */
+ kUSDHC_AdmaErrorStateChangeAddress = 0x02U, /*!< Change address, no DMA error has occurred. */
+ kUSDHC_AdmaErrorStateTransferData = 0x03U,
+ /*!< Transfer data, previous location set in the ADMA system address is errored address. */
+ kUSDHC_AdmaErrorStateInvalidLength = 0x04U, /*!< Invalid length in ADMA descriptor. */
+ kUSDHC_AdmaErrorStateInvalidDescriptor = 0x08U, /*!< Invalid descriptor fetched by ADMA. */
+
+ kUSDHC_AdmaErrorState = kUSDHC_AdmaErrorStateInvalidLength | kUSDHC_AdmaErrorStateInvalidDescriptor |
+ kUSDHC_AdmaErrorStateFetchDescriptor, /*!< ADMA error state */
+};
+
+/*! @brief Enum _usdhc_force_event. Force event bit position.
+ * @anchor _usdhc_force_event
+ */
+enum
+{
+ kUSDHC_ForceEventAutoCommand12NotExecuted =
+ USDHC_FORCE_EVENT_FEVTAC12NE_MASK, /*!< Auto CMD12 not executed error. */
+ kUSDHC_ForceEventAutoCommand12Timeout = USDHC_FORCE_EVENT_FEVTAC12TOE_MASK, /*!< Auto CMD12 timeout error. */
+ kUSDHC_ForceEventAutoCommand12CrcError = USDHC_FORCE_EVENT_FEVTAC12CE_MASK, /*!< Auto CMD12 CRC error. */
+ kUSDHC_ForceEventEndBitError = USDHC_FORCE_EVENT_FEVTAC12EBE_MASK, /*!< Auto CMD12 end bit error. */
+ kUSDHC_ForceEventAutoCommand12IndexError = USDHC_FORCE_EVENT_FEVTAC12IE_MASK, /*!< Auto CMD12 index error. */
+ kUSDHC_ForceEventAutoCommand12NotIssued = USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK, /*!< Auto CMD12 not issued error. */
+ kUSDHC_ForceEventCommandTimeout = USDHC_FORCE_EVENT_FEVTCTOE_MASK, /*!< Command timeout error. */
+ kUSDHC_ForceEventCommandCrcError = USDHC_FORCE_EVENT_FEVTCCE_MASK, /*!< Command CRC error. */
+ kUSDHC_ForceEventCommandEndBitError = USDHC_FORCE_EVENT_FEVTCEBE_MASK, /*!< Command end bit error. */
+ kUSDHC_ForceEventCommandIndexError = USDHC_FORCE_EVENT_FEVTCIE_MASK, /*!< Command index error. */
+ kUSDHC_ForceEventDataTimeout = USDHC_FORCE_EVENT_FEVTDTOE_MASK, /*!< Data timeout error. */
+ kUSDHC_ForceEventDataCrcError = USDHC_FORCE_EVENT_FEVTDCE_MASK, /*!< Data CRC error. */
+ kUSDHC_ForceEventDataEndBitError = USDHC_FORCE_EVENT_FEVTDEBE_MASK, /*!< Data end bit error. */
+ kUSDHC_ForceEventAutoCommand12Error = USDHC_FORCE_EVENT_FEVTAC12E_MASK, /*!< Auto CMD12 error. */
+ kUSDHC_ForceEventCardInt = (int)USDHC_FORCE_EVENT_FEVTCINT_MASK, /*!< Card interrupt. */
+ kUSDHC_ForceEventDmaError = USDHC_FORCE_EVENT_FEVTDMAE_MASK, /*!< Dma error. */
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ kUSDHC_ForceEventTuningError = 0U, /*!< not support */
+#else
+ kUSDHC_ForceEventTuningError = USDHC_FORCE_EVENT_FEVTTNE_MASK, /*!< Tuning error. */
+#endif
+
+ kUSDHC_ForceEventsAll =
+ (int)(USDHC_FORCE_EVENT_FEVTAC12NE_MASK | USDHC_FORCE_EVENT_FEVTAC12TOE_MASK |
+ USDHC_FORCE_EVENT_FEVTAC12CE_MASK | USDHC_FORCE_EVENT_FEVTAC12EBE_MASK |
+ USDHC_FORCE_EVENT_FEVTAC12IE_MASK | USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK |
+ USDHC_FORCE_EVENT_FEVTCTOE_MASK | USDHC_FORCE_EVENT_FEVTCCE_MASK | USDHC_FORCE_EVENT_FEVTCEBE_MASK |
+ USDHC_FORCE_EVENT_FEVTCIE_MASK | USDHC_FORCE_EVENT_FEVTDTOE_MASK | USDHC_FORCE_EVENT_FEVTDCE_MASK |
+ USDHC_FORCE_EVENT_FEVTDEBE_MASK | USDHC_FORCE_EVENT_FEVTAC12E_MASK | USDHC_FORCE_EVENT_FEVTCINT_MASK |
+ USDHC_FORCE_EVENT_FEVTDMAE_MASK | kUSDHC_ForceEventTuningError), /*!< All force event flags mask. */
+};
+
+/*! @brief Data transfer direction. */
+typedef enum _usdhc_transfer_direction
+{
+ kUSDHC_TransferDirectionReceive = 1U, /*!< USDHC transfer direction receive. */
+ kUSDHC_TransferDirectionSend = 0U, /*!< USDHC transfer direction send. */
+} usdhc_transfer_direction_t;
+
+/*! @brief Data transfer width. */
+typedef enum _usdhc_data_bus_width
+{
+ kUSDHC_DataBusWidth1Bit = 0U, /*!< 1-bit mode */
+ kUSDHC_DataBusWidth4Bit = 1U, /*!< 4-bit mode */
+ kUSDHC_DataBusWidth8Bit = 2U, /*!< 8-bit mode */
+} usdhc_data_bus_width_t;
+
+/*! @brief Endian mode */
+typedef enum _usdhc_endian_mode
+{
+ kUSDHC_EndianModeBig = 0U, /*!< Big endian mode. */
+ kUSDHC_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode. */
+ kUSDHC_EndianModeLittle = 2U, /*!< Little endian mode. */
+} usdhc_endian_mode_t;
+
+/*! @brief DMA mode */
+typedef enum _usdhc_dma_mode
+{
+ kUSDHC_DmaModeSimple = 0U, /*!< External DMA. */
+ kUSDHC_DmaModeAdma1 = 1U, /*!< ADMA1 is selected. */
+ kUSDHC_DmaModeAdma2 = 2U, /*!< ADMA2 is selected. */
+ kUSDHC_ExternalDMA = 3U, /*!< External DMA mode selected. */
+} usdhc_dma_mode_t;
+
+/*! @brief Enum _usdhc_sdio_control_flag. SDIO control flag mask.
+ * @anchor _usdhc_sdio_control_flag
+ */
+enum
+{
+ kUSDHC_StopAtBlockGapFlag = USDHC_PROT_CTRL_SABGREQ_MASK, /*!< Stop at block gap. */
+ kUSDHC_ReadWaitControlFlag = USDHC_PROT_CTRL_RWCTL_MASK, /*!< Read wait control. */
+ kUSDHC_InterruptAtBlockGapFlag = USDHC_PROT_CTRL_IABG_MASK, /*!< Interrupt at block gap. */
+ kUSDHC_ReadDoneNo8CLK = USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK, /*!< Read done without 8 clk for block gap. */
+ kUSDHC_ExactBlockNumberReadFlag = USDHC_PROT_CTRL_NON_EXACT_BLK_RD_MASK, /*!< Exact block number read. */
+};
+
+/*! @brief MMC card boot mode */
+typedef enum _usdhc_boot_mode
+{
+ kUSDHC_BootModeNormal = 0U, /*!< Normal boot */
+ kUSDHC_BootModeAlternative = 1U, /*!< Alternative boot */
+} usdhc_boot_mode_t;
+
+/*! @brief The command type */
+typedef enum _usdhc_card_command_type
+{
+ kCARD_CommandTypeNormal = 0U, /*!< Normal command */
+ kCARD_CommandTypeSuspend = 1U, /*!< Suspend command */
+ kCARD_CommandTypeResume = 2U, /*!< Resume command */
+ kCARD_CommandTypeAbort = 3U, /*!< Abort command */
+ kCARD_CommandTypeEmpty = 4U, /*!< Empty command */
+} usdhc_card_command_type_t;
+
+/*!
+ * @brief The command response type.
+ *
+ * Defines the command response type from card to host controller.
+ */
+typedef enum _usdhc_card_response_type
+{
+ kCARD_ResponseTypeNone = 0U, /*!< Response type: none */
+ kCARD_ResponseTypeR1 = 1U, /*!< Response type: R1 */
+ kCARD_ResponseTypeR1b = 2U, /*!< Response type: R1b */
+ kCARD_ResponseTypeR2 = 3U, /*!< Response type: R2 */
+ kCARD_ResponseTypeR3 = 4U, /*!< Response type: R3 */
+ kCARD_ResponseTypeR4 = 5U, /*!< Response type: R4 */
+ kCARD_ResponseTypeR5 = 6U, /*!< Response type: R5 */
+ kCARD_ResponseTypeR5b = 7U, /*!< Response type: R5b */
+ kCARD_ResponseTypeR6 = 8U, /*!< Response type: R6 */
+ kCARD_ResponseTypeR7 = 9U, /*!< Response type: R7 */
+} usdhc_card_response_type_t;
+
+/*! @brief The alignment size for ADDRESS filed in ADMA1's descriptor. */
+#define USDHC_ADMA1_ADDRESS_ALIGN (4096U)
+/*! @brief The alignment size for LENGTH field in ADMA1's descriptor. */
+#define USDHC_ADMA1_LENGTH_ALIGN (4096U)
+/*! @brief The alignment size for ADDRESS field in ADMA2's descriptor. */
+#define USDHC_ADMA2_ADDRESS_ALIGN (4U)
+/*! @brief The alignment size for LENGTH filed in ADMA2's descriptor. */
+#define USDHC_ADMA2_LENGTH_ALIGN (4U)
+
+/* ADMA1 descriptor table:
+ * |------------------------|---------|--------------------------|
+ * | Address/page field |Reserved | Attribute |
+ * |------------------------|---------|--------------------------|
+ * |31 12|11 6|05 |04 |03|02 |01 |00 |
+ * |------------------------|---------|----|----|--|---|---|-----|
+ * | address or data length | 000000 |Act2|Act1| 0|Int|End|Valid|
+ * |------------------------|---------|----|----|--|---|---|-----|
+ *
+ * ADMA2 action table:
+ * |------|------|-----------------|-------|-------------|
+ * | Act2 | Act1 | Comment | 31-28 | 27 - 12 |
+ * |------|------|-----------------|---------------------|
+ * | 0 | 0 | No op | Don't care |
+ * |------|------|-----------------|-------|-------------|
+ * | 0 | 1 | Set data length | 0000 | Data Length |
+ * |------|------|-----------------|-------|-------------|
+ * | 1 | 0 | Transfer data | Data address |
+ * |------|------|-----------------|---------------------|
+ * | 1 | 1 | Link descriptor | Descriptor address |
+ * |------|------|-----------------|---------------------|
+ */
+/****************************tables below are created only for Doxygen*********************************/
+/*! @brief The bit shift for ADDRESS filed in ADMA1's descriptor.
+ * <table>
+ * <caption>ADMA1 descriptor table</caption>
+ * <tr><th>Address/page field <th>Reserved <th colspan="6">Attribute
+ * <tr><td>31 12 <td>11 6 <td>05 <td>04 <td>03 <td>02 <td>01 <td>00
+ * <tr><td>address or data length <td>000000 <td>Act2 <td>Act1 <td>0 <td>Int <td>End <td>Valid
+ * </table>
+ *
+ * <table>
+ * <caption>ADMA2 action</caption>
+ * <tr><th>Act2 <th>Act1 <th>Comment <th>31-28 <th>27-12
+ * <tr><td>0 <td>0 <td>No op <td colspan="2">Don't care
+ * <tr><td>0 <td>1 <td>Set data length <td>0000 <td> Data Length
+ * <tr><td>1 <td>0 <td>Transfer data <td colspan="2">Data address
+ * <tr><td>1 <td>1 <td>Link descriptor <td colspan="2">Descriptor address
+ * </table>
+ */
+#define USDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT (12U)
+/*! @brief The bit mask for ADDRESS field in ADMA1's descriptor. */
+#define USDHC_ADMA1_DESCRIPTOR_ADDRESS_MASK (0xFFFFFU)
+/*! @brief The bit shift for LENGTH filed in ADMA1's descriptor. */
+#define USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT (12U)
+/*! @brief The mask for LENGTH field in ADMA1's descriptor. */
+#define USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK (0xFFFFU)
+/*! @brief The maximum value of LENGTH filed in ADMA1's descriptor.
+ * Since the max transfer size ADMA1 support is 65535 which is indivisible by
+ * 4096, so to make sure a large data load transfer (>64KB) continuously (require the data
+ * address be always align with 4096), software will set the maximum data length
+ * for ADMA1 to (64 - 4)KB.
+ */
+#define USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK + 1U - 4096U)
+
+/*! @brief Enum _usdhc_adma1_descriptor_flag. The mask for the control/status field in ADMA1 descriptor. */
+enum
+{
+ kUSDHC_Adma1DescriptorValidFlag = (1U << 0U), /*!< Valid flag. */
+ kUSDHC_Adma1DescriptorEndFlag = (1U << 1U), /*!< End flag. */
+ kUSDHC_Adma1DescriptorInterrupFlag = (1U << 2U), /*!< Interrupt flag. */
+ kUSDHC_Adma1DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 flag. */
+ kUSDHC_Adma1DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 flag. */
+ kUSDHC_Adma1DescriptorTypeNop = (kUSDHC_Adma1DescriptorValidFlag), /*!< No operation. */
+ kUSDHC_Adma1DescriptorTypeTransfer = (kUSDHC_Adma1DescriptorActivity2Flag | kUSDHC_Adma1DescriptorValidFlag),
+ /*!< Transfer data. */
+ kUSDHC_Adma1DescriptorTypeLink = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorActivity2Flag |
+ kUSDHC_Adma1DescriptorValidFlag), /*!< Link descriptor. */
+ kUSDHC_Adma1DescriptorTypeSetLength = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorValidFlag),
+ /*!< Set data length. */
+};
+
+/* ADMA2 descriptor table:
+ * |----------------|---------------|-------------|--------------------------|
+ * | Address field | Length | Reserved | Attribute |
+ * |----------------|---------------|-------------|--------------------------|
+ * |63 32|31 16|15 06|05 |04 |03|02 |01 |00 |
+ * |----------------|---------------|-------------|----|----|--|---|---|-----|
+ * | 32-bit address | 16-bit length | 0000000000 |Act2|Act1| 0|Int|End|Valid|
+ * |----------------|---------------|-------------|----|----|--|---|---|-----|
+ *
+ * ADMA2 action table:
+ * | Act2 | Act1 | Comment | Operation |
+ * |------|------|-----------------|-------------------------------------------------------------------|
+ * | 0 | 0 | No op | Don't care |
+ * |------|------|-----------------|-------------------------------------------------------------------|
+ * | 0 | 1 | Reserved | Read this line and go to next one |
+ * |------|------|-----------------|-------------------------------------------------------------------|
+ * | 1 | 0 | Transfer data | Transfer data with address and length set in this descriptor line |
+ * |------|------|-----------------|-------------------------------------------------------------------|
+ * | 1 | 1 | Link descriptor | Link to another descriptor |
+ * |------|------|-----------------|-------------------------------------------------------------------|
+ */
+/**********************************tables below are created only for Doxygen***********************************/
+/*! @brief The bit shift for LENGTH field in ADMA2's descriptor.
+ *
+ * <table>
+ * <caption>ADMA2 descriptor table</caption>
+ * <tr><th>Address field <th>Length <th>Reserved <th colspan="6">Attribute
+ * <tr><td>63 32 <td>31 16 <td>15 06 <td>05 <td>04 <td>03 <td>02 <td>01 <td>00
+ * <tr><td>32-bit address <td>16-bit length <td>0000000000 <td>Act2 <td>Act1 <td>0 <td>Int <td>End <td>Valid
+ *</table>
+ *
+ * <table>
+ * <caption>ADMA2 action</caption>
+ * <tr><th>Act2 <th>Act1 <th>Comment <th>Operation
+ * <tr><td> 0 <td>0 <td>No op <td>Don't care
+ * <tr><td> 0 <td>1 <td> Reserved <td> Read this line and go to next one
+ * <tr><td> 1 <td>0 <td>Transfer data <td>Transfer data with address and length set in this descriptor line
+ * <tr><td> 1 <td>1 <td>Link descriptor <td>Link to another descriptor
+ * </table>
+ */
+#define USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT (16U)
+/*! @brief The bit mask for LENGTH field in ADMA2's descriptor. */
+#define USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK (0xFFFFU)
+/*! @brief The maximum value of LENGTH field in ADMA2's descriptor. */
+#define USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK - 3U)
+
+/*! @brief Enum _usdhc_adma2_descriptor_flag. ADMA1 descriptor control and status mask. */
+enum
+{
+ kUSDHC_Adma2DescriptorValidFlag = (1U << 0U), /*!< Valid flag. */
+ kUSDHC_Adma2DescriptorEndFlag = (1U << 1U), /*!< End flag. */
+ kUSDHC_Adma2DescriptorInterruptFlag = (1U << 2U), /*!< Interrupt flag. */
+ kUSDHC_Adma2DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 mask. */
+ kUSDHC_Adma2DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 mask. */
+
+ kUSDHC_Adma2DescriptorTypeNop = (kUSDHC_Adma2DescriptorValidFlag), /*!< No operation. */
+ kUSDHC_Adma2DescriptorTypeReserved = (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorValidFlag),
+ /*!< Reserved. */
+ kUSDHC_Adma2DescriptorTypeTransfer = (kUSDHC_Adma2DescriptorActivity2Flag | kUSDHC_Adma2DescriptorValidFlag),
+ /*!< Transfer type. */
+ kUSDHC_Adma2DescriptorTypeLink = (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorActivity2Flag |
+ kUSDHC_Adma2DescriptorValidFlag), /*!< Link type. */
+};
+
+/*! @brief Enum _usdhc_adma_flag. ADMA descriptor configuration flag.
+ * @anchor _usdhc_adma_flag
+ */
+enum
+{
+ kUSDHC_AdmaDescriptorSingleFlag = 0U,
+ /*!< Try to finish the transfer in a single ADMA descriptor. If transfer size is bigger than one
+ ADMA descriptor's ability, new another descriptor for data transfer. */
+ kUSDHC_AdmaDescriptorMultipleFlag =
+ 1U, /*!< Create multiple ADMA descriptors within the ADMA table, this is used for
+ mmc boot mode specifically, which need
+ to modify the ADMA descriptor on the fly, so the flag should be used
+ combining with stop at block gap feature. */
+};
+
+/*! @brief DMA transfer burst len config. */
+typedef enum _usdhc_burst_len
+{
+ kUSDHC_EnBurstLenForINCR = 0x01U, /*!< Enable burst len for INCR. */
+ kUSDHC_EnBurstLenForINCR4816 = 0x02U, /*!< Enable burst len for INCR4/INCR8/INCR16. */
+ kUSDHC_EnBurstLenForINCR4816WRAP = 0x04U, /*!< Enable burst len for INCR4/8/16 WRAP. */
+} usdhc_burst_len_t;
+
+/*! @brief Enum _usdhc_transfer_data_type. Tansfer data type definition. */
+enum
+{
+ kUSDHC_TransferDataNormal = 0U, /*!< Transfer normal read/write data. */
+ kUSDHC_TransferDataTuning = 1U, /*!< Transfer tuning data. */
+ kUSDHC_TransferDataBoot = 2U, /*!< Transfer boot data. */
+ kUSDHC_TransferDataBootcontinous = 3U, /*!< Transfer boot data continuously. */
+};
+
+/*! @brief Defines the ADMA1 descriptor structure. */
+typedef uint32_t usdhc_adma1_descriptor_t;
+
+/*! @brief Defines the ADMA2 descriptor structure. */
+typedef struct _usdhc_adma2_descriptor
+{
+ uint32_t attribute; /*!< The control and status field. */
+ const uint32_t *address; /*!< The address field. */
+} usdhc_adma2_descriptor_t;
+
+/*!
+ * @brief USDHC capability information.
+ *
+ * Defines a structure to save the capability information of USDHC.
+ */
+typedef struct _usdhc_capability
+{
+ uint32_t sdVersion; /*!< Support SD card/sdio version. */
+ uint32_t mmcVersion; /*!< Support EMMC card version. */
+ uint32_t maxBlockLength; /*!< Maximum block length united as byte. */
+ uint32_t maxBlockCount; /*!< Maximum block count can be set one time. */
+ uint32_t flags; /*!< Capability flags to indicate the support information(@ref _usdhc_capability_flag). */
+} usdhc_capability_t;
+
+/*! @brief Data structure to configure the MMC boot feature. */
+typedef struct _usdhc_boot_config
+{
+ uint32_t ackTimeoutCount; /*!< Timeout value for the boot ACK. The available range is 0 ~ 15. */
+ usdhc_boot_mode_t bootMode; /*!< Boot mode selection. */
+ uint32_t blockCount; /*!< Stop at block gap value of automatic mode. Available range is 0 ~ 65535. */
+ size_t blockSize; /*!< Block size. */
+ bool enableBootAck; /*!< Enable or disable boot ACK. */
+ bool enableAutoStopAtBlockGap; /*!< Enable or disable auto stop at block gap function in boot period. */
+} usdhc_boot_config_t;
+
+/*! @brief Data structure to initialize the USDHC. */
+typedef struct _usdhc_config
+{
+ uint32_t dataTimeout; /*!< Data timeout value. */
+ usdhc_endian_mode_t endianMode; /*!< Endian mode. */
+ uint8_t readWatermarkLevel; /*!< Watermark level for DMA read operation. Available range is 1 ~ 128. */
+ uint8_t writeWatermarkLevel; /*!< Watermark level for DMA write operation. Available range is 1 ~ 128. */
+#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ uint8_t readBurstLen; /*!< Read burst len. */
+ uint8_t writeBurstLen; /*!< Write burst len. */
+#endif
+} usdhc_config_t;
+
+/*!
+ * @brief Card command descriptor.
+ *
+ * Defines card command-related attribute.
+ */
+typedef struct _usdhc_command
+{
+ uint32_t index; /*!< Command index. */
+ uint32_t argument; /*!< Command argument. */
+ usdhc_card_command_type_t type; /*!< Command type. */
+ usdhc_card_response_type_t responseType; /*!< Command response type. */
+ uint32_t response[4U]; /*!< Response for this command. */
+ uint32_t responseErrorFlags; /*!< Response error flag, which need to check
+ the command reponse. */
+ uint32_t flags; /*!< Cmd flags. */
+} usdhc_command_t;
+
+/*! @brief ADMA configuration. */
+typedef struct _usdhc_adma_config
+{
+ usdhc_dma_mode_t dmaMode; /*!< DMA mode. */
+#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ usdhc_burst_len_t burstLen; /*!< Burst len config. */
+#endif
+ uint32_t *admaTable; /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2. */
+ uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2. */
+} usdhc_adma_config_t;
+
+/*!
+ * @brief Card scatter gather data list.
+ *
+ * Allow application register uncontinuous data buffer for data transfer.
+ */
+typedef struct _usdhc_scatter_gather_data_list
+{
+ uint32_t *dataAddr;
+ uint32_t dataSize;
+ struct _usdhc_scatter_gather_data_list *dataList;
+} usdhc_scatter_gather_data_list_t;
+
+/*!
+ * @brief Card scatter gather data descriptor.
+ *
+ * Defines a structure to contain data-related attribute. The 'enableIgnoreError' is used when upper card
+ * driver wants to ignore the error event to read/write all the data and not to stop read/write immediately when an
+ * error event happens. For example, bus testing procedure for MMC card.
+ */
+typedef struct _usdhc_scatter_gather_data
+{
+ bool enableAutoCommand12; /*!< Enable auto CMD12. */
+ bool enableAutoCommand23; /*!< Enable auto CMD23. */
+ bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data. */
+
+ usdhc_transfer_direction_t dataDirection; /*!< data direction */
+ uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data. */
+ size_t blockSize; /*!< Block size. */
+
+ usdhc_scatter_gather_data_list_t sgData; /*!< scatter gather data */
+} usdhc_scatter_gather_data_t;
+
+/*! @brief usdhc scatter gather transfer. */
+typedef struct _usdhc_scatter_gather_transfer
+{
+ usdhc_scatter_gather_data_t *data; /*!< Data to transfer. */
+ usdhc_command_t *command; /*!< Command to send. */
+} usdhc_scatter_gather_transfer_t;
+
+/*!
+ * @brief Card data descriptor.
+ *
+ * Defines a structure to contain data-related attribute. The 'enableIgnoreError' is used when upper card
+ * driver wants to ignore the error event to read/write all the data and not to stop read/write immediately when an
+ * error event happens. For example, bus testing procedure for MMC card.
+ */
+typedef struct _usdhc_data
+{
+ bool enableAutoCommand12; /*!< Enable auto CMD12. */
+ bool enableAutoCommand23; /*!< Enable auto CMD23. */
+ bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data. */
+ uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data. */
+ size_t blockSize; /*!< Block size. */
+ uint32_t blockCount; /*!< Block count. */
+ uint32_t *rxData; /*!< Buffer to save data read. */
+ const uint32_t *txData; /*!< Data buffer to write. */
+} usdhc_data_t;
+
+/*! @brief Transfer state. */
+typedef struct _usdhc_transfer
+{
+ usdhc_data_t *data; /*!< Data to transfer. */
+ usdhc_command_t *command; /*!< Command to send. */
+} usdhc_transfer_t;
+
+/*! @brief USDHC handle typedef. */
+typedef struct _usdhc_handle usdhc_handle_t;
+
+/*! @brief USDHC callback functions. */
+typedef struct _usdhc_transfer_callback
+{
+ void (*CardInserted)(USDHC_Type *base,
+ void *userData); /*!< Card inserted occurs when DAT3/CD pin is for card detect */
+ void (*CardRemoved)(USDHC_Type *base, void *userData); /*!< Card removed occurs */
+ void (*SdioInterrupt)(USDHC_Type *base, void *userData); /*!< SDIO card interrupt occurs */
+ void (*BlockGap)(USDHC_Type *base, void *userData); /*!< stopped at block gap event */
+ void (*TransferComplete)(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ status_t status,
+ void *userData); /*!< Transfer complete callback. */
+ void (*ReTuning)(USDHC_Type *base, void *userData); /*!< Handle the re-tuning. */
+} usdhc_transfer_callback_t;
+
+/*!
+ * @brief USDHC handle.
+ *
+ * Defines the structure to save the USDHC state information and callback function.
+ *
+ * @note All the fields except interruptFlags and transferredWords must be allocated by the user.
+ */
+struct _usdhc_handle
+{
+#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
+ usdhc_scatter_gather_data_t *volatile data; /*!< scatter gather data pointer */
+#else
+ usdhc_data_t *volatile data; /*!< Transfer parameter. Data to transfer. */
+#endif
+ usdhc_command_t *volatile command; /*!< Transfer parameter. Command to send. */
+
+ volatile uint32_t transferredWords; /*!< Transfer status. Words transferred by DATAPORT way. */
+
+ usdhc_transfer_callback_t callback; /*!< Callback function. */
+ void *userData; /*!< Parameter for transfer complete callback. */
+};
+
+/*! @brief USDHC transfer function. */
+typedef status_t (*usdhc_transfer_function_t)(USDHC_Type *base, usdhc_transfer_t *content);
+
+/*! @brief USDHC host descriptor. */
+typedef struct _usdhc_host
+{
+ USDHC_Type *base; /*!< USDHC peripheral base address. */
+ uint32_t sourceClock_Hz; /*!< USDHC source clock frequency united in Hz. */
+ usdhc_config_t config; /*!< USDHC configuration. */
+ usdhc_capability_t capability; /*!< USDHC capability information. */
+ usdhc_transfer_function_t transfer; /*!< USDHC transfer function. */
+} usdhc_host_t;
+
+/*************************************************************************************************
+ * API
+ ************************************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief USDHC module initialization function.
+ *
+ * Configures the USDHC according to the user configuration.
+ *
+ * Example:
+ @code
+ usdhc_config_t config;
+ config.cardDetectDat3 = false;
+ config.endianMode = kUSDHC_EndianModeLittle;
+ config.dmaMode = kUSDHC_DmaModeAdma2;
+ config.readWatermarkLevel = 128U;
+ config.writeWatermarkLevel = 128U;
+ USDHC_Init(USDHC, &config);
+ @endcode
+ *
+ * @param base USDHC peripheral base address.
+ * @param config USDHC configuration information.
+ * @retval #kStatus_Success Operate successfully.
+ */
+void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config);
+
+/*!
+ * @brief Deinitializes the USDHC.
+ *
+ * @param base USDHC peripheral base address.
+ */
+void USDHC_Deinit(USDHC_Type *base);
+
+/*!
+ * @brief Resets the USDHC.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask The reset type mask(@ref _usdhc_reset).
+ * @param timeout Timeout for reset.
+ * @retval true Reset successfully.
+ * @retval false Reset failed.
+ */
+bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout);
+
+/* @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Sets the DMA descriptor table configuration.
+ * A high level DMA descriptor configuration function.
+ * @param base USDHC peripheral base address.
+ * @param dmaConfig ADMA configuration
+ * @param dataConfig Data descriptor
+ * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * refer to enum @ref _usdhc_adma_flag.
+ * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_data_t *dataConfig,
+ uint32_t flags);
+
+/*!
+ * @brief Internal DMA configuration.
+ * This function is used to config the USDHC DMA related registers.
+ * @param base USDHC peripheral base address.
+ * @param dmaConfig ADMA configuration.
+ * @param dataAddr Transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
+ * @param enAutoCmd23 Flag to indicate Auto CMD23 is enable or not, a simple DMA parameter, if ADMA is used, leave it
+ * to false.
+ * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ const uint32_t *dataAddr,
+ bool enAutoCmd23);
+
+/*!
+ * @brief Sets the ADMA2 descriptor table configuration.
+ *
+ * @param admaTable ADMA table address.
+ * @param admaTableWords ADMA table length.
+ * @param dataBufferAddr Data buffer address.
+ * @param dataBytes Data Data length.
+ * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * refer to enum @ref _usdhc_adma_flag.
+ * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA2Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags);
+
+/*!
+ * @brief Sets the ADMA1 descriptor table configuration.
+ *
+ * @param admaTable ADMA table address.
+ * @param admaTableWords ADMA table length.
+ * @param dataBufferAddr Data buffer address.
+ * @param dataBytes Data length.
+ * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * refer to enum @ref _usdhc_adma_flag.
+ * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA1Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags);
+
+/*!
+ * @brief Enables internal DMA.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable or disable flag
+ */
+static inline void USDHC_EnableInternalDMA(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
+ }
+ else
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_DMAEN_MASK;
+ base->PROT_CTRL &= ~USDHC_PROT_CTRL_DMASEL_MASK;
+ }
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the interrupt status.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask Interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline void USDHC_EnableInterruptStatus(USDHC_Type *base, uint32_t mask)
+{
+ base->INT_STATUS_EN |= mask;
+}
+
+/*!
+ * @brief Disables the interrupt status.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline void USDHC_DisableInterruptStatus(USDHC_Type *base, uint32_t mask)
+{
+ base->INT_STATUS_EN &= ~mask;
+}
+
+/*!
+ * @brief Enables the interrupt signal corresponding to the interrupt status flag.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline void USDHC_EnableInterruptSignal(USDHC_Type *base, uint32_t mask)
+{
+ base->INT_SIGNAL_EN |= mask;
+}
+
+/*!
+ * @brief Disables the interrupt signal corresponding to the interrupt status flag.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline void USDHC_DisableInterruptSignal(USDHC_Type *base, uint32_t mask)
+{
+ base->INT_SIGNAL_EN &= ~mask;
+}
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the enabled interrupt status.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Current interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline uint32_t USDHC_GetEnabledInterruptStatusFlags(USDHC_Type *base)
+{
+ uint32_t intStatus = base->INT_STATUS;
+
+ return intStatus & base->INT_SIGNAL_EN;
+}
+
+/*!
+ * @brief Gets the current interrupt status.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Current interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline uint32_t USDHC_GetInterruptStatusFlags(USDHC_Type *base)
+{
+ return base->INT_STATUS;
+}
+
+/*!
+ * @brief Clears a specified interrupt status.
+ * write 1 clears
+ * @param base USDHC peripheral base address.
+ * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag).
+ */
+static inline void USDHC_ClearInterruptStatusFlags(USDHC_Type *base, uint32_t mask)
+{
+ base->INT_STATUS = mask;
+}
+
+/*!
+ * @brief Gets the status of auto command 12 error.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Auto command 12 error status flags mask(@ref _usdhc_auto_command12_error_status_flag).
+ */
+static inline uint32_t USDHC_GetAutoCommand12ErrorStatusFlags(USDHC_Type *base)
+{
+ return base->AUTOCMD12_ERR_STATUS;
+}
+
+/*!
+ * @brief Gets the status of the ADMA error.
+ *
+ * @param base USDHC peripheral base address.
+ * @return ADMA error status flags mask(@ref _usdhc_adma_error_status_flag).
+ */
+static inline uint32_t USDHC_GetAdmaErrorStatusFlags(USDHC_Type *base)
+{
+ return base->ADMA_ERR_STATUS & 0xFUL;
+}
+
+/*!
+ * @brief Gets a present status.
+ *
+ * This function gets the present USDHC's status except for an interrupt status and an error status.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Present USDHC's status flags mask(@ref _usdhc_present_status_flag).
+ */
+static inline uint32_t USDHC_GetPresentStatusFlags(USDHC_Type *base)
+{
+ return base->PRES_STATE;
+}
+
+/* @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Gets the capability information.
+ *
+ * @param base USDHC peripheral base address.
+ * @param capability Structure to save capability information.
+ */
+void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability);
+
+/*!
+ * @brief Forces the card clock on.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ */
+static inline void USDHC_ForceClockOn(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VEND_SPEC |= USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK;
+ }
+ else
+ {
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK;
+ }
+}
+
+/*!
+ * @brief Sets the SD bus clock frequency.
+ *
+ * @param base USDHC peripheral base address.
+ * @param srcClock_Hz USDHC source clock frequency united in Hz.
+ * @param busClock_Hz SD bus clock frequency united in Hz.
+ *
+ * @return The nearest frequency of busClock_Hz configured for SD bus.
+ */
+uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz);
+
+/*!
+ * @brief Sends 80 clocks to the card to set it to the active state.
+ *
+ * This function must be called each time the card is inserted to ensure that the card can receive the command
+ * correctly.
+ *
+ * @param base USDHC peripheral base address.
+ * @param timeout Timeout to initialize card.
+ * @retval true Set card active successfully.
+ * @retval false Set card active failed.
+ */
+bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout);
+
+/*!
+ * @brief Triggers a hardware reset.
+ *
+ * @param base USDHC peripheral base address.
+ * @param high 1 or 0 level
+ */
+static inline void USDHC_AssertHardwareReset(USDHC_Type *base, bool high)
+{
+ if (high)
+ {
+ base->SYS_CTRL |= USDHC_SYS_CTRL_IPP_RST_N_MASK;
+ }
+ else
+ {
+ base->SYS_CTRL &= ~USDHC_SYS_CTRL_IPP_RST_N_MASK;
+ }
+}
+
+/*!
+ * @brief Sets the data transfer width.
+ *
+ * @param base USDHC peripheral base address.
+ * @param width Data transfer width.
+ */
+static inline void USDHC_SetDataBusWidth(USDHC_Type *base, usdhc_data_bus_width_t width)
+{
+ base->PROT_CTRL = ((base->PROT_CTRL & ~USDHC_PROT_CTRL_DTW_MASK) | USDHC_PROT_CTRL_DTW(width));
+}
+
+/*!
+ * @brief Fills the data port.
+ *
+ * This function is used to implement the data transfer by Data Port instead of DMA.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data The data about to be sent.
+ */
+static inline void USDHC_WriteData(USDHC_Type *base, uint32_t data)
+{
+ base->DATA_BUFF_ACC_PORT = data;
+}
+
+/*!
+ * @brief Retrieves the data from the data port.
+ *
+ * This function is used to implement the data transfer by Data Port instead of DMA.
+ *
+ * @param base USDHC peripheral base address.
+ * @return The data has been read.
+ */
+static inline uint32_t USDHC_ReadData(USDHC_Type *base)
+{
+ return base->DATA_BUFF_ACC_PORT;
+}
+
+/*!
+ * @brief Sends command function.
+ *
+ * @param base USDHC peripheral base address.
+ * @param command configuration
+ */
+void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command);
+
+/*!
+ * @brief Enables or disables a wakeup event in low-power mode.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask Wakeup events mask(@ref _usdhc_wakeup_event).
+ * @param enable True to enable, false to disable.
+ */
+static inline void USDHC_EnableWakeupEvent(USDHC_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->PROT_CTRL |= mask;
+ }
+ else
+ {
+ base->PROT_CTRL &= ~mask;
+ }
+}
+
+/*!
+ * @brief Detects card insert status.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ */
+static inline void USDHC_CardDetectByData3(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK;
+ }
+ else
+ {
+ base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK;
+ }
+}
+
+/*!
+ * @brief Detects card insert status.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline bool USDHC_DetectCardInsert(USDHC_Type *base)
+{
+ return ((base->PRES_STATE & (uint32_t)kUSDHC_CardInsertedFlag) != 0UL) ? true : false;
+}
+
+/*!
+ * @brief Enables or disables the SDIO card control.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask SDIO card control flags mask(@ref _usdhc_sdio_control_flag).
+ * @param enable True to enable, false to disable.
+ */
+static inline void USDHC_EnableSdioControl(USDHC_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->PROT_CTRL |= mask;
+ }
+ else
+ {
+ base->PROT_CTRL &= ~mask;
+ }
+}
+
+/*!
+ * @brief Restarts a transaction which has stopped at the block GAP for the SDIO card.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline void USDHC_SetContinueRequest(USDHC_Type *base)
+{
+ base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
+}
+
+/*!
+ * @brief Request stop at block gap function.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable True to stop at block gap, false to normal transfer.
+ */
+static inline void USDHC_RequestStopAtBlockGap(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->PROT_CTRL |= USDHC_PROT_CTRL_SABGREQ_MASK;
+ }
+ else
+ {
+ base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
+ }
+}
+
+/*!
+ * @brief Configures the MMC boot feature.
+ *
+ * Example:
+ @code
+ usdhc_boot_config_t config;
+ config.ackTimeoutCount = 4;
+ config.bootMode = kUSDHC_BootModeNormal;
+ config.blockCount = 5;
+ config.enableBootAck = true;
+ config.enableBoot = true;
+ config.enableAutoStopAtBlockGap = true;
+ USDHC_SetMmcBootConfig(USDHC, &config);
+ @endcode
+ *
+ * @param base USDHC peripheral base address.
+ * @param config The MMC boot configuration information.
+ */
+void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config);
+
+/*!
+ * @brief Enables or disables the mmc boot mode.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable True to enable, false to disable.
+ */
+static inline void USDHC_EnableMmcBoot(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MMC_BOOT |= USDHC_MMC_BOOT_BOOT_EN_MASK;
+ }
+ else
+ {
+ base->MMC_BOOT &= ~USDHC_MMC_BOOT_BOOT_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Forces generating events according to the given mask.
+ *
+ * @param base USDHC peripheral base address.
+ * @param mask The force events bit posistion (_usdhc_force_event).
+ */
+static inline void USDHC_SetForceEvent(USDHC_Type *base, uint32_t mask)
+{
+ base->FORCE_EVENT = mask;
+}
+
+#if !(defined(FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT) && (FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT))
+/*!
+ * @brief Selects the USDHC output voltage.
+ *
+ * @param base USDHC peripheral base address.
+ * @param en18v True means 1.8V, false means 3.0V.
+ */
+static inline void UDSHC_SelectVoltage(USDHC_Type *base, bool en18v)
+{
+ if (en18v)
+ {
+ base->VEND_SPEC |= USDHC_VEND_SPEC_VSELECT_MASK;
+ }
+ else
+ {
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_VSELECT_MASK;
+ }
+}
+#endif
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+/*!
+ * @brief Checks the SDR50 mode request tuning bit.
+ * When this bit set, application shall perform tuning for SDR50 mode.
+ * @param base USDHC peripheral base address.
+ */
+static inline bool USDHC_RequestTuningForSDR50(USDHC_Type *base)
+{
+ return ((base->HOST_CTRL_CAP & USDHC_HOST_CTRL_CAP_USE_TUNING_SDR50_MASK) != 0UL) ? true : false;
+}
+
+/*!
+ * @brief Checks the request re-tuning bit.
+ * When this bit is set, user should do manual tuning or standard tuning function.
+ * @param base USDHC peripheral base address.
+ */
+static inline bool USDHC_RequestReTuning(USDHC_Type *base)
+{
+ return ((base->PRES_STATE & USDHC_PRES_STATE_RTR_MASK) != 0UL) ? true : false;
+}
+
+/*!
+ * @brief The SDR104 mode auto tuning enable and disable.
+ * This function should be called after tuning function execute pass, auto tuning will handle
+ * by hardware.
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ */
+static inline void USDHC_EnableAutoTuning(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MIX_CTRL |= USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
+ }
+ else
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
+ }
+}
+
+#if !(defined(FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_NO_RETUNING_TIME_COUNTER) && \
+ FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_NO_RETUNING_TIME_COUNTER)
+/*!
+ * @brief Configs the re-tuning timer for mode 1 and mode 3.
+ * This timer is used for standard tuning auto re-tuning,
+ * @param base USDHC peripheral base address.
+ * @param counter timer counter value
+ */
+static inline void USDHC_SetRetuningTimer(USDHC_Type *base, uint32_t counter)
+{
+ base->HOST_CTRL_CAP &= ~USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING_MASK;
+ base->HOST_CTRL_CAP |= USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING(counter);
+}
+#endif /* FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_RETUNING_TIME_COUNTER */
+
+/*!
+ * @brief The auto tuning enbale for CMD/DATA line.
+ *
+ * @param base USDHC peripheral base address.
+ */
+void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base);
+
+/*!
+ * @brief Manual tuning trigger or abort.
+ * User should handle the tuning cmd and find the boundary of the delay
+ * then calucate a average value which will be configured to the <b>CLK_TUNE_CTRL_STATUS</b>
+ * This function should be called before function @ref USDHC_AdjustDelayForManualTuning.
+ * @param base USDHC peripheral base address.
+ * @param enable tuning enable flag
+ */
+void USDHC_EnableManualTuning(USDHC_Type *base, bool enable);
+
+/*!
+ * @brief Get the tuning delay cell setting.
+ *
+ * @param base USDHC peripheral base address.
+ * @retval CLK Tuning Control and Status register value.
+ */
+static inline uint32_t USDHC_GetTuningDelayStatus(USDHC_Type *base)
+{
+ return base->CLK_TUNE_CTRL_STATUS >> 16U;
+}
+
+/*!
+ * @brief The tuning delay cell setting.
+ *
+ * @param base USDHC peripheral base address.
+ * @param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE.
+ * @param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT.
+ * @param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST.
+ * @retval kStatus_Fail config the delay setting fail
+ * @retval kStatus_Success config the delay setting success
+ */
+status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay);
+
+/*!
+ * @brief Adjusts delay for mannual tuning.
+ * @deprecated Do not use this function. It has been superceded by USDHC_SetTuingDelay
+ * @param base USDHC peripheral base address.
+ * @param delay setting configuration
+ * @retval #kStatus_Fail config the delay setting fail
+ * @retval #kStatus_Success config the delay setting success
+ */
+status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay);
+
+/*!
+ * @brief set tuning counter tuning.
+ * @param base USDHC peripheral base address.
+ * @param counter tuning counter
+ * @retval #kStatus_Fail config the delay setting fail
+ * @retval #kStatus_Success config the delay setting success
+ */
+static inline void USDHC_SetStandardTuningCounter(USDHC_Type *base, uint8_t counter)
+{
+ base->TUNING_CTRL =
+ (base->TUNING_CTRL & (~USDHC_TUNING_CTRL_TUNING_COUNTER_MASK)) | USDHC_TUNING_CTRL_TUNING_COUNTER(counter);
+}
+
+/*!
+ * @brief The enable standard tuning function.
+ * The standard tuning window and tuning counter using the default config
+ * tuning cmd is sent by the software, user need to check whether the tuning result
+ * can be used for SDR50, SDR104, and HS200 mode tuning.
+ * @param base USDHC peripheral base address.
+ * @param tuningStartTap start tap
+ * @param step tuning step
+ * @param enable enable/disable flag
+ */
+void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable);
+
+/*!
+ * @brief Gets execute STD tuning status.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline uint32_t USDHC_GetExecuteStdTuningStatus(USDHC_Type *base)
+{
+ return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK);
+}
+
+/*!
+ * @brief Checks STD tuning result.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline uint32_t USDHC_CheckStdTuningResult(USDHC_Type *base)
+{
+ return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
+}
+
+/*!
+ * @brief Checks tuning error.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline uint32_t USDHC_CheckTuningError(USDHC_Type *base)
+{
+ return (base->CLK_TUNE_CTRL_STATUS &
+ (USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK));
+}
+
+#endif
+/*!
+ * @brief The enable/disable DDR mode.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ * @param nibblePos nibble position
+ */
+void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos);
+
+#if FSL_FEATURE_USDHC_HAS_HS400_MODE
+/*!
+ * @brief The enable/disable HS400 mode.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ */
+static inline void USDHC_EnableHS400Mode(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->MIX_CTRL |= USDHC_MIX_CTRL_HS400_MODE_MASK;
+ }
+ else
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_HS400_MODE_MASK;
+ }
+}
+
+/*!
+ * @brief Resets the strobe DLL.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline void USDHC_ResetStrobeDLL(USDHC_Type *base)
+{
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
+}
+
+/*!
+ * @brief Enables/disables the strobe DLL.
+ *
+ * @param base USDHC peripheral base address.
+ * @param enable enable/disable flag
+ */
+static inline void USDHC_EnableStrobeDLL(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK;
+ }
+ else
+ {
+ base->STROBE_DLL_CTRL &= ~USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK;
+ }
+}
+
+/*!
+ * @brief Configs the strobe DLL delay target and update interval.
+ *
+ * @param base USDHC peripheral base address.
+ * @param delayTarget delay target
+ * @param updateInterval update interval
+ */
+void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval);
+
+/*!
+ * @brief Enables manual override for slave delay chain using <b>STROBE_SLV_OVERRIDE_VAL</b>.
+ *
+ * @param base USDHC peripheral base address.
+ * @param delayTaps Valid delay taps range from 1 - 128 taps. A value of 0 selects tap 1, and a value of 0x7F selects
+ * tap 128.
+ */
+static inline void USDHC_SetStrobeDllOverride(USDHC_Type *base, uint32_t delayTaps)
+{
+ base->STROBE_DLL_CTRL &= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_VAL_MASK);
+
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_MASK |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_VAL(delayTaps);
+}
+
+/*!
+ * @brief Gets the strobe DLL status.
+ *
+ * @param base USDHC peripheral base address.
+ */
+static inline uint32_t USDHC_GetStrobeDLLStatus(USDHC_Type *base)
+{
+ return base->STROBE_DLL_STATUS;
+}
+
+#endif
+
+/*!
+ * @brief USDHC data configuration.
+ *
+ * @param base USDHC peripheral base address.
+ * @param dataDirection Data direction, tx or rx.
+ * @param blockCount Data block count.
+ * @param blockSize Data block size.
+ *
+ */
+void USDHC_SetDataConfig(USDHC_Type *base,
+ usdhc_transfer_direction_t dataDirection,
+ uint32_t blockCount,
+ uint32_t blockSize);
+/* @} */
+
+/*!
+ * @name Transactional functions
+ * @{
+ */
+
+/*!
+ * @brief Creates the USDHC handle.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle pointer.
+ * @param callback Structure pointer to contain all callback functions.
+ * @param userData Callback function parameter.
+ */
+void USDHC_TransferCreateHandle(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ const usdhc_transfer_callback_t *callback,
+ void *userData);
+
+#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
+/*!
+ * @brief Transfers the command/scatter gather data using an interrupt and an asynchronous method.
+ *
+ * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
+ * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
+ * this API doesn't support the re-entry mechanism.
+ * This function is target for the application would like to have scatter gather buffer to be transferred within one
+ * read/write request, non scatter gather buffer is support by this function also.
+ *
+ * @note Call API @ref USDHC_TransferCreateHandle when calling this API.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only.
+ * @param transfer scatter gather transfer content.
+ *
+ * @retval #kStatus_InvalidArgument Argument is invalid.
+ * @retval #kStatus_USDHC_BusyTransferring Busy transferring.
+ * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_scatter_gather_transfer_t *transfer);
+#else
+/*!
+ * @brief Transfers the command/data using an interrupt and an asynchronous method.
+ *
+ * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
+ * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
+ * this API doesn't support the re-entry mechanism.
+ *
+ * @note Call API @ref USDHC_TransferCreateHandle when calling this API.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param dmaConfig ADMA configuration.
+ * @param transfer Transfer content.
+ * @retval #kStatus_InvalidArgument Argument is invalid.
+ * @retval #kStatus_USDHC_BusyTransferring Busy transferring.
+ * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferNonBlocking(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_transfer_t *transfer);
+#endif
+
+/*!
+ * @brief Transfers the command/data using a blocking method.
+ *
+ * This function waits until the command response/data is received or the USDHC encounters an error by polling the
+ * status flag. \n
+ * The application must not call this API in multiple threads at the same time. Because this API doesn't
+ * support the re-entry mechanism.
+ *
+ * @note There is no need to call API @ref USDHC_TransferCreateHandle when calling this API.
+ *
+ * @param base USDHC peripheral base address.
+ * @param dmaConfig adma configuration
+ * @param transfer Transfer content.
+ * @retval #kStatus_InvalidArgument Argument is invalid.
+ * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * @retval #kStatus_USDHC_SendCommandFailed Send command failed.
+ * @retval #kStatus_USDHC_TransferDataFailed Transfer data failed.
+ * @retval #kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer);
+
+/*!
+ * @brief IRQ handler for the USDHC.
+ *
+ * This function deals with the IRQs on the given host controller.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ */
+void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+/*! @} */
+
+#endif /* _FSL_USDHC_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.c b/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.c
new file mode 100644
index 0000000000..ea6c970b33
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_wdog.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.wdog01"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+static WDOG_Type *const s_wdogBases[] = WDOG_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of WDOG clock name. */
+static const clock_ip_name_t s_wdogClock[] = WDOG_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+static const IRQn_Type s_wdogIRQ[] = WDOG_IRQS;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t WDOG_GetInstance(WDOG_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_wdogBases); instance++)
+ {
+ if (s_wdogBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_wdogBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the WDOG configuration structure.
+ *
+ * This function initializes the WDOG configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * wdogConfig->enableWdog = true;
+ * wdogConfig->workMode.enableWait = true;
+ * wdogConfig->workMode.enableStop = false;
+ * wdogConfig->workMode.enableDebug = false;
+ * wdogConfig->enableInterrupt = false;
+ * wdogConfig->enablePowerdown = false;
+ * wdogConfig->resetExtension = flase;
+ * wdogConfig->timeoutValue = 0xFFU;
+ * wdogConfig->interruptTimeValue = 0x04u;
+ * endcode
+ *
+ * param config Pointer to the WDOG configuration structure.
+ * see wdog_config_t
+ */
+void WDOG_GetDefaultConfig(wdog_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableWdog = true;
+ config->workMode.enableWait = false;
+ config->workMode.enableStop = false;
+ config->workMode.enableDebug = false;
+ config->enableInterrupt = false;
+ config->softwareResetExtension = false;
+ config->enablePowerDown = false;
+ config->timeoutValue = 0xffu;
+ config->interruptTimeValue = 0x04u;
+ config->enableTimeOutAssert = false;
+}
+
+/*!
+ * brief Initializes the WDOG.
+ *
+ * This function initializes the WDOG. When called, the WDOG runs according to the configuration.
+ *
+ * This is an example.
+ * code
+ * wdog_config_t config;
+ * WDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0xffU;
+ * config->interruptTimeValue = 0x04u;
+ * WDOG_Init(wdog_base,&config);
+ * endcode
+ *
+ * param base WDOG peripheral base address
+ * param config The configuration of WDOG
+ */
+void WDOG_Init(WDOG_Type *base, const wdog_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t value = 0u;
+ uint32_t primaskValue = 0U;
+
+ value = WDOG_WCR_WDE(config->enableWdog) | WDOG_WCR_WDW(config->workMode.enableWait) |
+ WDOG_WCR_WDZST(config->workMode.enableStop) | WDOG_WCR_WDBG(config->workMode.enableDebug) |
+ WDOG_WCR_SRE(config->softwareResetExtension) | WDOG_WCR_WT(config->timeoutValue) |
+ WDOG_WCR_WDT(config->enableTimeOutAssert) | WDOG_WCR_SRS_MASK | WDOG_WCR_WDA_MASK;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Set configuration */
+ CLOCK_EnableClock(s_wdogClock[WDOG_GetInstance(base)]);
+#endif
+
+ primaskValue = DisableGlobalIRQ();
+ base->WICR = WDOG_WICR_WICT(config->interruptTimeValue) | WDOG_WICR_WIE(config->enableInterrupt);
+ base->WMCR = WDOG_WMCR_PDE(config->enablePowerDown);
+ base->WCR = value;
+ EnableGlobalIRQ(primaskValue);
+ if (config->enableInterrupt)
+ {
+ (void)EnableIRQ(s_wdogIRQ[WDOG_GetInstance(base)]);
+ }
+}
+
+/*!
+ * brief Shuts down the WDOG.
+ *
+ * This function shuts down the WDOG.
+ * Watchdog Enable bit is a write one once only bit. It is not
+ * possible to clear this bit by a software write, once the bit is set.
+ * This bit(WDE) can be set/reset only in debug mode(exception).
+ */
+void WDOG_Deinit(WDOG_Type *base)
+{
+ if (0U != (base->WCR & WDOG_WCR_WDBG_MASK))
+ {
+ WDOG_Disable(base);
+ }
+}
+
+/*!
+ * brief Gets the WDOG all reset status flags.
+ *
+ * This function gets all reset status flags.
+ *
+ * code
+ * uint16_t status;
+ * status = WDOG_GetStatusFlags (wdog_base);
+ * endcode
+ * param base WDOG peripheral base address
+ * return State of the status flag: asserted (true) or not-asserted (false).see _wdog_status_flags
+ * - true: a related status flag has been set.
+ * - false: a related status flag is not set.
+ */
+uint16_t WDOG_GetStatusFlags(WDOG_Type *base)
+{
+ uint16_t status_flag = 0U;
+
+ status_flag |= (base->WCR & WDOG_WCR_WDE_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_POR_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_TOUT_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_SFTW_MASK);
+ status_flag |= (base->WICR & WDOG_WICR_WTIS_MASK);
+
+ return status_flag;
+}
+
+/*!
+ * brief Clears the WDOG flag.
+ *
+ * This function clears the WDOG status flag.
+ *
+ * This is an example for clearing the interrupt flag.
+ * code
+ * WDOG_ClearStatusFlags(wdog_base,KWDOG_InterruptFlag);
+ * endcode
+ * param base WDOG peripheral base address
+ * param mask The status flags to clear.
+ * The parameter could be any combination of the following values.
+ * kWDOG_TimeoutFlag
+ */
+void WDOG_ClearInterruptStatus(WDOG_Type *base, uint16_t mask)
+{
+ if (0U != (mask & (uint16_t)kWDOG_InterruptFlag))
+ {
+ base->WICR |= WDOG_WICR_WTIS_MASK;
+ }
+}
+
+/*!
+ * brief Refreshes the WDOG timer.
+ *
+ * This function feeds the WDOG.
+ * This function should be called before the WDOG timer is in timeout. Otherwise, a reset is asserted.
+ *
+ * param base WDOG peripheral base address
+ */
+void WDOG_Refresh(WDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->WSR = WDOG_REFRESH_KEY & 0xFFFFU;
+ base->WSR = (WDOG_REFRESH_KEY >> 16U) & 0xFFFFU;
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.h b/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.h
new file mode 100644
index 0000000000..c49b39abe9
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/wdog01/fsl_wdog.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_WDOG_H_
+#define _FSL_WDOG_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup wdog
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+/*! @name Driver version */
+/*@{*/
+/*! @brief Defines WDOG driver version */
+#define FSL_WDOG_DRIVER_VERSION (MAKE_VERSION(2, 1, 1))
+/*@}*/
+/*! @name Refresh sequence */
+/*@{*/
+#define WDOG_REFRESH_KEY (0xAAAA5555U)
+/*@}*/
+
+/*! @brief Defines WDOG work mode. */
+typedef struct _wdog_work_mode
+{
+ bool enableWait; /*!< continue or suspend WDOG in wait mode */
+ bool enableStop; /*!< continue or suspend WDOG in stop mode */
+ bool enableDebug; /*!< continue or suspend WDOG in debug mode */
+} wdog_work_mode_t;
+
+/*! @brief Describes WDOG configuration structure. */
+typedef struct _wdog_config
+{
+ bool enableWdog; /*!< Enables or disables WDOG */
+ wdog_work_mode_t workMode; /*!< Configures WDOG work mode in debug stop and wait mode */
+ bool enableInterrupt; /*!< Enables or disables WDOG interrupt */
+ uint16_t timeoutValue; /*!< Timeout value */
+ uint16_t interruptTimeValue; /*!< Interrupt count timeout value */
+ bool softwareResetExtension; /*!< software reset extension */
+ bool enablePowerDown; /*!< power down enable bit */
+ bool enableTimeOutAssert; /*!< Enable WDOG_B timeout assertion. */
+} wdog_config_t;
+
+/*!
+ * @brief WDOG interrupt configuration structure, default settings all disabled.
+ *
+ * This structure contains the settings for all of the WDOG interrupt configurations.
+ */
+enum _wdog_interrupt_enable
+{
+ kWDOG_InterruptEnable = WDOG_WICR_WIE_MASK /*!< WDOG timeout generates an interrupt before reset*/
+};
+
+/*!
+ * @brief WDOG status flags.
+ *
+ * This structure contains the WDOG status flags for use in the WDOG functions.
+ */
+enum _wdog_status_flags
+{
+ kWDOG_RunningFlag = WDOG_WCR_WDE_MASK, /*!< Running flag, set when WDOG is enabled*/
+ kWDOG_PowerOnResetFlag = WDOG_WRSR_POR_MASK, /*!< Power On flag, set when reset is the result of a powerOnReset*/
+ kWDOG_TimeoutResetFlag = WDOG_WRSR_TOUT_MASK, /*!< Timeout flag, set when reset is the result of a timeout*/
+ kWDOG_SoftwareResetFlag = WDOG_WRSR_SFTW_MASK, /*!< Software flag, set when reset is the result of a software*/
+ kWDOG_InterruptFlag = WDOG_WICR_WTIS_MASK /*!< interrupt flag,whether interrupt has occurred or not*/
+};
+
+/*******************************************************************************
+ * API
+ *******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name WDOG Initialization and De-initialization.
+ * @{
+ */
+
+/*!
+ * @brief Initializes the WDOG configuration structure.
+ *
+ * This function initializes the WDOG configuration structure to default values. The default
+ * values are as follows.
+ * @code
+ * wdogConfig->enableWdog = true;
+ * wdogConfig->workMode.enableWait = true;
+ * wdogConfig->workMode.enableStop = false;
+ * wdogConfig->workMode.enableDebug = false;
+ * wdogConfig->enableInterrupt = false;
+ * wdogConfig->enablePowerdown = false;
+ * wdogConfig->resetExtension = flase;
+ * wdogConfig->timeoutValue = 0xFFU;
+ * wdogConfig->interruptTimeValue = 0x04u;
+ * @endcode
+ *
+ * @param config Pointer to the WDOG configuration structure.
+ * @see wdog_config_t
+ */
+void WDOG_GetDefaultConfig(wdog_config_t *config);
+
+/*!
+ * @brief Initializes the WDOG.
+ *
+ * This function initializes the WDOG. When called, the WDOG runs according to the configuration.
+ *
+ * This is an example.
+ * @code
+ * wdog_config_t config;
+ * WDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0xffU;
+ * config->interruptTimeValue = 0x04u;
+ * WDOG_Init(wdog_base,&config);
+ * @endcode
+ *
+ * @param base WDOG peripheral base address
+ * @param config The configuration of WDOG
+ */
+void WDOG_Init(WDOG_Type *base, const wdog_config_t *config);
+
+/*!
+ * @brief Shuts down the WDOG.
+ *
+ * This function shuts down the WDOG.
+ * Watchdog Enable bit is a write one once only bit. It is not
+ * possible to clear this bit by a software write, once the bit is set.
+ * This bit(WDE) can be set/reset only in debug mode(exception).
+ */
+void WDOG_Deinit(WDOG_Type *base);
+
+/*!
+ * @brief Enables the WDOG module.
+ *
+ * This function writes a value into the WDOG_WCR register to enable the WDOG.
+ * This is a write one once only bit. It is not possible to clear this bit by a software write,
+ * once the bit is set. only debug mode exception.
+ * @param base WDOG peripheral base address
+ */
+static inline void WDOG_Enable(WDOG_Type *base)
+{
+ base->WCR |= WDOG_WCR_WDE_MASK;
+}
+
+/*!
+ * @brief Disables the WDOG module.
+ *
+ * This function writes a value into the WDOG_WCR register to disable the WDOG.
+ * This is a write one once only bit. It is not possible to clear this bit by a software write,once the bit is set.
+ * only debug mode exception
+ * @param base WDOG peripheral base address
+ */
+static inline void WDOG_Disable(WDOG_Type *base)
+{
+ base->WCR &= ~(uint16_t)WDOG_WCR_WDE_MASK;
+}
+
+/*!
+ * @brief Trigger the system software reset.
+ *
+ * This function will write to the WCR[SRS] bit to trigger a software system reset.
+ * This bit will automatically resets to "1" after it has been asserted to "0".
+ * Note: Calling this API will reset the system right now, please using it with more attention.
+ *
+ * @param base WDOG peripheral base address
+ */
+static inline void WDOG_TriggerSystemSoftwareReset(WDOG_Type *base)
+{
+ base->WCR &= ~(uint16_t)WDOG_WCR_SRS_MASK;
+}
+
+/*!
+ * @brief Trigger an output assertion.
+ *
+ * This function will write to the WCR[WDA] bit to trigger WDOG_B signal assertion.
+ * The WDOG_B signal can be routed to external pin of the chip, the output pin will turn to
+ * assertion along with WDOG_B signal.
+ * Note: The WDOG_B signal will remain assert until a power on reset occurred, so, please
+ * take more attention while calling it.
+ *
+ * @param base WDOG peripheral base address
+ */
+static inline void WDOG_TriggerSoftwareSignal(WDOG_Type *base)
+{
+ base->WCR &= ~(uint16_t)WDOG_WCR_WDA_MASK;
+}
+
+/*!
+ * @brief Enables the WDOG interrupt.
+ *
+ *This bit is a write once only bit. Once the software does a write access to this bit, it will get
+ *locked and cannot be reprogrammed until the next system reset assertion
+ *
+ * @param base WDOG peripheral base address
+ * @param mask The interrupts to enable
+ * The parameter can be combination of the following source if defined.
+ * @arg kWDOG_InterruptEnable
+ */
+static inline void WDOG_EnableInterrupts(WDOG_Type *base, uint16_t mask)
+{
+ base->WICR |= mask;
+}
+
+/*!
+ * @brief Gets the WDOG all reset status flags.
+ *
+ * This function gets all reset status flags.
+ *
+ * @code
+ * uint16_t status;
+ * status = WDOG_GetStatusFlags (wdog_base);
+ * @endcode
+ * @param base WDOG peripheral base address
+ * @return State of the status flag: asserted (true) or not-asserted (false).@see _wdog_status_flags
+ * - true: a related status flag has been set.
+ * - false: a related status flag is not set.
+ */
+uint16_t WDOG_GetStatusFlags(WDOG_Type *base);
+
+/*!
+ * @brief Clears the WDOG flag.
+ *
+ * This function clears the WDOG status flag.
+ *
+ * This is an example for clearing the interrupt flag.
+ * @code
+ * WDOG_ClearStatusFlags(wdog_base,KWDOG_InterruptFlag);
+ * @endcode
+ * @param base WDOG peripheral base address
+ * @param mask The status flags to clear.
+ * The parameter could be any combination of the following values.
+ * kWDOG_TimeoutFlag
+ */
+void WDOG_ClearInterruptStatus(WDOG_Type *base, uint16_t mask);
+
+/*!
+ * @brief Sets the WDOG timeout value.
+ *
+ * This function sets the timeout value.
+ * This function writes a value into WCR registers.
+ * The time-out value can be written at any point of time but it is loaded to the counter at the time
+ * when WDOG is enabled or after the service routine has been performed.
+ *
+ * @param base WDOG peripheral base address
+ * @param timeoutCount WDOG timeout value; count of WDOG clock tick.
+ */
+static inline void WDOG_SetTimeoutValue(WDOG_Type *base, uint16_t timeoutCount)
+{
+ base->WCR = (base->WCR & (uint16_t)~WDOG_WCR_WT_MASK) | WDOG_WCR_WT(timeoutCount);
+}
+
+/*!
+ * @brief Sets the WDOG interrupt count timeout value.
+ *
+ * This function sets the interrupt count timeout value.
+ * This function writes a value into WIC registers which are wirte-once.
+ * This field is write once only. Once the software does a write access to this field, it will get locked
+ * and cannot be reprogrammed until the next system reset assertion.
+ * @param base WDOG peripheral base address
+ * @param timeoutCount WDOG timeout value; count of WDOG clock tick.
+ */
+static inline void WDOG_SetInterrputTimeoutValue(WDOG_Type *base, uint16_t timeoutCount)
+{
+ base->WICR = (base->WICR & ~(uint16_t)WDOG_WICR_WICT_MASK) | WDOG_WICR_WICT(timeoutCount);
+}
+
+/*!
+ * @brief Disable the WDOG power down enable bit.
+ *
+ * This function disable the WDOG power down enable(PDE).
+ * This function writes a value into WMCR registers which are wirte-once.
+ * This field is write once only. Once software sets this bit it cannot be reset until the next system reset.
+ * @param base WDOG peripheral base address
+ */
+static inline void WDOG_DisablePowerDownEnable(WDOG_Type *base)
+{
+ base->WMCR &= ~(uint16_t)WDOG_WMCR_PDE_MASK;
+}
+
+/*!
+ * @brief Refreshes the WDOG timer.
+ *
+ * This function feeds the WDOG.
+ * This function should be called before the WDOG timer is in timeout. Otherwise, a reset is asserted.
+ *
+ * @param base WDOG peripheral base address
+ */
+void WDOG_Refresh(WDOG_Type *base);
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/
+
+#endif /* _FSL_WDOG_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.c b/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.c
new file mode 100644
index 0000000000..cc6307bbb6
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xbara.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xbara"
+#endif
+
+/* Macros for entire XBARA_CTRL register. */
+#define XBARA_CTRLx(base, index) (((volatile uint16_t *)(&((base)->CTRL0)))[(index)])
+
+typedef union
+{
+ uint8_t _u8[2];
+ uint16_t _u16;
+} xbara_u8_u16_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the XBARA instance from peripheral base address.
+ *
+ * @param base XBARA peripheral base address.
+ * @return XBARA instance.
+ */
+static uint32_t XBARA_GetInstance(XBARA_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of XBARA peripheral base address. */
+static XBARA_Type *const s_xbaraBases[] = XBARA_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of XBARA clock name. */
+static const clock_ip_name_t s_xbaraClock[] = XBARA_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t XBARA_GetInstance(XBARA_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_xbaraBases); instance++)
+ {
+ if (s_xbaraBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_xbaraBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the XBARA module.
+ *
+ * This function un-gates the XBARA clock.
+ *
+ * param base XBARA peripheral address.
+ */
+void XBARA_Init(XBARA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable XBARA module clock. */
+ CLOCK_EnableClock(s_xbaraClock[XBARA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Shuts down the XBARA module.
+ *
+ * This function disables XBARA clock.
+ *
+ * param base XBARA peripheral address.
+ */
+void XBARA_Deinit(XBARA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable XBARA module clock. */
+ CLOCK_DisableClock(s_xbaraClock[XBARA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets a connection between the selected XBARA_IN[*] input and the XBARA_OUT[*] output signal.
+ *
+ * This function connects the XBARA input to the selected XBARA output.
+ * If more than one XBARA module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * Example:
+ code
+ XBARA_SetSignalsConnection(XBARA, kXBARA_InputPIT_TRG0, kXBARA_OutputDMAMUX18);
+ endcode
+ *
+ * param base XBARA peripheral address.
+ * param input XBARA input signal.
+ * param output XBARA output signal.
+ */
+void XBARA_SetSignalsConnection(XBARA_Type *base, xbar_input_signal_t input, xbar_output_signal_t output)
+{
+ xbara_u8_u16_t regVal;
+ uint8_t byteInReg;
+ uint8_t outputIndex = (uint8_t)output;
+
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARA_SELx(base, outputIndex);
+
+ regVal._u8[byteInReg] = (uint8_t)input;
+
+ XBARA_SELx(base, outputIndex) = regVal._u16;
+}
+
+/*!
+ * brief Gets the active edge detection status.
+ *
+ * This function gets the active edge detect status of all XBARA_OUTs. If the
+ * active edge occurs, the return value is asserted. When the interrupt or the DMA
+ * functionality is enabled for the XBARA_OUTx, this field is 1 when the interrupt
+ * or DMA request is asserted and 0 when the interrupt or DMA request has been
+ * cleared.
+ *
+ * param base XBARA peripheral address.
+ * return the mask of these status flag bits.
+ */
+uint32_t XBARA_GetStatusFlags(XBARA_Type *base)
+{
+ uint32_t status_flag;
+
+ status_flag = ((uint32_t)base->CTRL0 & (XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+
+ status_flag |= (((uint32_t)base->CTRL1 & (XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK)) << 16U);
+
+ return status_flag;
+}
+
+/*!
+ * brief Clears the edge detection status flags of relative mask.
+ *
+ * param base XBARA peripheral address.
+ * param mask the status flags to clear.
+ */
+void XBARA_ClearStatusFlags(XBARA_Type *base, uint32_t mask)
+{
+ uint16_t regVal;
+
+ /* Assign regVal to CTRL0 register's value */
+ regVal = (base->CTRL0);
+ /* Perform this command to avoid writing 1 into interrupt flag bits */
+ regVal &= (uint16_t)(~(XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+ /* Write 1 to interrupt flag bits corresponding to mask */
+ regVal |= (uint16_t)(mask & (XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+ /* Write regVal value into CTRL0 register */
+ base->CTRL0 = regVal;
+
+ /* Assign regVal to CTRL1 register's value */
+ regVal = (base->CTRL1);
+ /* Perform this command to avoid writing 1 into interrupt flag bits */
+ regVal &= (uint16_t)(~(XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK));
+ /* Write 1 to interrupt flag bits corresponding to mask */
+ regVal |= (uint16_t)((mask >> 16U) & (XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK));
+ /* Write regVal value into CTRL1 register */
+ base->CTRL1 = regVal;
+}
+
+/*!
+ * brief Configures the XBARA control register.
+ *
+ * This function configures an XBARA control register. The active edge detection
+ * and the DMA/IRQ function on the corresponding XBARA output can be set.
+ *
+ * Example:
+ code
+ xbara_control_config_t userConfig;
+ userConfig.activeEdge = kXBARA_EdgeRising;
+ userConfig.requestType = kXBARA_RequestInterruptEnalbe;
+ XBARA_SetOutputSignalConfig(XBARA, kXBARA_OutputDMAMUX18, &userConfig);
+ endcode
+ *
+ * param base XBARA peripheral address.
+ * param output XBARA output number.
+ * param controlConfig Pointer to structure that keeps configuration of control register.
+ */
+void XBARA_SetOutputSignalConfig(XBARA_Type *base,
+ xbar_output_signal_t output,
+ const xbara_control_config_t *controlConfig)
+{
+ uint8_t outputIndex = (uint8_t)output;
+ uint8_t regIndex;
+ uint8_t byteInReg;
+ xbara_u8_u16_t regVal;
+
+ assert(outputIndex < (uint32_t)FSL_FEATURE_XBARA_INTERRUPT_COUNT);
+
+ regIndex = outputIndex / 2U;
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARA_CTRLx(base, regIndex);
+
+ /* Don't clear the status flags. */
+ regVal._u16 &= (uint16_t)(~(XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+
+ regVal._u8[byteInReg] = (uint8_t)(XBARA_CTRL0_EDGE0(controlConfig->activeEdge) |
+ (uint16_t)(((uint32_t)controlConfig->requestType) << XBARA_CTRL0_DEN0_SHIFT));
+
+ XBARA_CTRLx(base, regIndex) = regVal._u16;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.h b/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.h
new file mode 100644
index 0000000000..71756e4769
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xbara/fsl_xbara.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019, 2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_XBARA_H_
+#define _FSL_XBARA_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup xbara
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define FSL_XBARA_DRIVER_VERSION (MAKE_VERSION(2, 0, 5))
+
+/* Macros for entire XBARA_SELx register. */
+#define XBARA_SELx(base, output) (((volatile uint16_t *)(&((base)->SEL0)))[(uint32_t)(output) / 2UL])
+
+/* Set the XBARA_SELx_SELx field to a new value. */
+#define XBARA_WR_SELx_SELx(base, input, output) XBARA_SetSignalsConnection((base), (input), (output))
+
+/* For driver backward compatibility. */
+#define kXBARA_RequestInterruptEnalbe kXBARA_RequestInterruptEnable
+
+/*!
+ * @brief XBARA active edge for detection
+ */
+typedef enum _xbara_active_edge
+{
+ kXBARA_EdgeNone = 0U, /*!< Edge detection status bit never asserts. */
+ kXBARA_EdgeRising = 1U, /*!< Edge detection status bit asserts on rising edges. */
+ kXBARA_EdgeFalling = 2U, /*!< Edge detection status bit asserts on falling edges. */
+ kXBARA_EdgeRisingAndFalling = 3U /*!< Edge detection status bit asserts on rising and falling edges. */
+} xbara_active_edge_t;
+
+/*!
+ * @brief Defines the XBARA DMA and interrupt configurations.
+ */
+typedef enum _xbar_request
+{
+ kXBARA_RequestDisable = 0U, /*!< Interrupt and DMA are disabled. */
+ kXBARA_RequestDMAEnable = 1U, /*!< DMA enabled, interrupt disabled. */
+ kXBARA_RequestInterruptEnable = 2U /*!< Interrupt enabled, DMA disabled. */
+} xbara_request_t;
+
+/*!
+ * @brief XBARA status flags.
+ *
+ * This provides constants for the XBARA status flags for use in the XBARA functions.
+ */
+typedef enum _xbara_status_flag_t
+{
+ kXBARA_EdgeDetectionOut0 =
+ (XBARA_CTRL0_STS0_MASK), /*!< XBAR_OUT0 active edge interrupt flag, sets when active edge detected. */
+ kXBARA_EdgeDetectionOut1 =
+ (XBARA_CTRL0_STS1_MASK), /*!< XBAR_OUT1 active edge interrupt flag, sets when active edge detected. */
+ kXBARA_EdgeDetectionOut2 =
+ (XBARA_CTRL1_STS2_MASK << 16U), /*!< XBAR_OUT2 active edge interrupt flag, sets when active edge detected. */
+ kXBARA_EdgeDetectionOut3 =
+ (XBARA_CTRL1_STS3_MASK << 16U), /*!< XBAR_OUT3 active edge interrupt flag, sets when active edge detected. */
+} xbara_status_flag_t;
+
+/*!
+ * @brief Defines the configuration structure of the XBARA control register.
+ *
+ * This structure keeps the configuration of XBARA control register for one output.
+ * Control registers are available only for a few outputs. Not every XBARA module has
+ * control registers.
+ */
+typedef struct XBARAControlConfig
+{
+ xbara_active_edge_t activeEdge; /*!< Active edge to be detected. */
+ xbara_request_t requestType; /*!< Selects DMA/Interrupt request. */
+} xbara_control_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name XBARA functional Operation.
+ * @{
+ */
+
+/*!
+ * @brief Initializes the XBARA module.
+ *
+ * This function un-gates the XBARA clock.
+ *
+ * @param base XBARA peripheral address.
+ */
+void XBARA_Init(XBARA_Type *base);
+
+/*!
+ * @brief Shuts down the XBARA module.
+ *
+ * This function disables XBARA clock.
+ *
+ * @param base XBARA peripheral address.
+ */
+void XBARA_Deinit(XBARA_Type *base);
+
+/*!
+ * @brief Sets a connection between the selected XBARA_IN[*] input and the XBARA_OUT[*] output signal.
+ *
+ * This function connects the XBARA input to the selected XBARA output.
+ * If more than one XBARA module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * Example:
+ @code
+ XBARA_SetSignalsConnection(XBARA, kXBARA_InputPIT_TRG0, kXBARA_OutputDMAMUX18);
+ @endcode
+ *
+ * @param base XBARA peripheral address.
+ * @param input XBARA input signal.
+ * @param output XBARA output signal.
+ */
+void XBARA_SetSignalsConnection(XBARA_Type *base, xbar_input_signal_t input, xbar_output_signal_t output);
+
+/*!
+ * @brief Gets the active edge detection status.
+ *
+ * This function gets the active edge detect status of all XBARA_OUTs. If the
+ * active edge occurs, the return value is asserted. When the interrupt or the DMA
+ * functionality is enabled for the XBARA_OUTx, this field is 1 when the interrupt
+ * or DMA request is asserted and 0 when the interrupt or DMA request has been
+ * cleared.
+ *
+ * @param base XBARA peripheral address.
+ * @return the mask of these status flag bits.
+ */
+uint32_t XBARA_GetStatusFlags(XBARA_Type *base);
+
+/*!
+ * @brief Clears the edge detection status flags of relative mask.
+ *
+ * @param base XBARA peripheral address.
+ * @param mask the status flags to clear.
+ */
+void XBARA_ClearStatusFlags(XBARA_Type *base, uint32_t mask);
+
+/*!
+ * @brief Configures the XBARA control register.
+ *
+ * This function configures an XBARA control register. The active edge detection
+ * and the DMA/IRQ function on the corresponding XBARA output can be set.
+ *
+ * Example:
+ @code
+ xbara_control_config_t userConfig;
+ userConfig.activeEdge = kXBARA_EdgeRising;
+ userConfig.requestType = kXBARA_RequestInterruptEnalbe;
+ XBARA_SetOutputSignalConfig(XBARA, kXBARA_OutputDMAMUX18, &userConfig);
+ @endcode
+ *
+ * @param base XBARA peripheral address.
+ * @param output XBARA output number.
+ * @param controlConfig Pointer to structure that keeps configuration of control register.
+ */
+void XBARA_SetOutputSignalConfig(XBARA_Type *base,
+ xbar_output_signal_t output,
+ const xbara_control_config_t *controlConfig);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/
+
+/*!* @} */
+
+#endif /* _FSL_XBARA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.c b/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.c
new file mode 100644
index 0000000000..c1878a2ae4
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xbarb.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xbarb"
+#endif
+
+typedef union
+{
+ uint8_t _u8[2];
+ uint16_t _u16;
+} xbarb_u8_u16_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the XBARB instance from peripheral base address.
+ *
+ * @param base XBARB peripheral base address.
+ * @return XBARB instance.
+ */
+static uint32_t XBARB_GetInstance(XBARB_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of XBARB peripheral base address. */
+static XBARB_Type *const s_xbarbBases[] = XBARB_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of XBARB clock name. */
+static const clock_ip_name_t s_xbarbClock[] = XBARB_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t XBARB_GetInstance(XBARB_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_xbarbBases); instance++)
+ {
+ if (s_xbarbBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_xbarbBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the XBARB module.
+ *
+ * This function un-gates the XBARB clock.
+ *
+ * param base XBARB peripheral address.
+ */
+void XBARB_Init(XBARB_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable XBARB module clock. */
+ CLOCK_EnableClock(s_xbarbClock[XBARB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Shuts down the XBARB module.
+ *
+ * This function disables XBARB clock.
+ *
+ * param base XBARB peripheral address.
+ */
+void XBARB_Deinit(XBARB_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable XBARB module clock. */
+ CLOCK_DisableClock(s_xbarbClock[XBARB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures a connection between the selected XBARB_IN[*] input and the XBARB_OUT[*] output signal.
+ *
+ * This function configures which XBARB input is connected to the selected XBARB output.
+ * If more than one XBARB module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * param base XBARB peripheral address.
+ * param input XBARB input signal.
+ * param output XBARB output signal.
+ */
+void XBARB_SetSignalsConnection(XBARB_Type *base, xbar_input_signal_t input, xbar_output_signal_t output)
+{
+ xbarb_u8_u16_t regVal;
+ uint8_t byteInReg;
+ uint8_t outputIndex = (uint8_t)output;
+
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARB_SELx(base, outputIndex);
+
+ regVal._u8[byteInReg] = (uint8_t)input;
+
+ XBARB_SELx(base, outputIndex) = regVal._u16;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.h b/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.h
new file mode 100644
index 0000000000..def13c31ad
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xbarb/fsl_xbarb.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_XBARB_H_
+#define _FSL_XBARB_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup xbarb
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define FSL_XBARB_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+
+/* Macros for entire XBARB_SELx register. */
+#define XBARB_SELx(base, output) (((volatile uint16_t *)(&((base)->SEL0)))[(uint32_t)(output) / 2UL])
+/* Set the SELx field to a new value. */
+#define XBARB_WR_SELx_SELx(base, input, output) XBARB_SetSignalsConnection((base), (input), (output))
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name XBARB functional Operation.
+ * @{
+ */
+
+/*!
+ * @brief Initializes the XBARB module.
+ *
+ * This function un-gates the XBARB clock.
+ *
+ * @param base XBARB peripheral address.
+ */
+void XBARB_Init(XBARB_Type *base);
+
+/*!
+ * @brief Shuts down the XBARB module.
+ *
+ * This function disables XBARB clock.
+ *
+ * @param base XBARB peripheral address.
+ */
+void XBARB_Deinit(XBARB_Type *base);
+
+/*!
+ * @brief Configures a connection between the selected XBARB_IN[*] input and the XBARB_OUT[*] output signal.
+ *
+ * This function configures which XBARB input is connected to the selected XBARB output.
+ * If more than one XBARB module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * @param base XBARB peripheral address.
+ * @param input XBARB input signal.
+ * @param output XBARB output signal.
+ */
+void XBARB_SetSignalsConnection(XBARB_Type *base, xbar_input_signal_t input, xbar_output_signal_t output);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @}*/
+
+/*!* @} */
+
+#endif /* _FSL_XBARB_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.c b/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.c
new file mode 100644
index 0000000000..fa6b7984c7
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xecc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xecc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief XECC module initialization function.
+ *
+ * param base XECC base address.
+ */
+void XECC_Init(XECC_Type *base, const xecc_config_t *config)
+{
+ /* Enable all the interrupt status */
+ base->ERR_STAT_EN = kXECC_AllInterruptsStatusEnable;
+ /* Clear all the interrupt status */
+ base->ERR_STATUS = kXECC_AllInterruptsFlag;
+ /* Disable all the interrpt */
+ base->ERR_SIG_EN = 0U;
+
+ /* Set ECC regions, which are 4KB aligned */
+ base->ECC_BASE_ADDR0 = config->Region0BaseAddress >> 12U;
+ base->ECC_END_ADDR0 = config->Region0EndAddress >> 12U;
+ base->ECC_BASE_ADDR1 = config->Region1BaseAddress >> 12U;
+ base->ECC_END_ADDR1 = config->Region1EndAddress >> 12U;
+ base->ECC_BASE_ADDR2 = config->Region2BaseAddress >> 12U;
+ base->ECC_END_ADDR2 = config->Region2EndAddress >> 12U;
+ base->ECC_BASE_ADDR3 = config->Region3BaseAddress >> 12U;
+ base->ECC_END_ADDR3 = config->Region3EndAddress >> 12U;
+
+ /* Enable ECC function */
+ base->ECC_CTRL = XECC_ECC_CTRL_ECC_EN(config->enableXECC);
+ base->ECC_CTRL |= XECC_ECC_CTRL_WECC_EN(config->enableWriteECC);
+ base->ECC_CTRL |= XECC_ECC_CTRL_RECC_EN(config->enableReadECC);
+ base->ECC_CTRL |= XECC_ECC_CTRL_SWAP_EN(config->enableSwap);
+
+ /* Make sure XECC register configuration operation has been done. */
+ __DSB();
+}
+
+/*!
+ * brief Deinitializes the XECC.
+ *
+ */
+void XECC_Deinit(XECC_Type *base)
+{
+ /* Disable ECC function */
+ base->ECC_CTRL &= ~XECC_ECC_CTRL_ECC_EN(1);
+}
+
+void XECC_GetDefaultConfig(xecc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Default XECC function */
+ config->enableXECC = false;
+ /* Default write ECC function */
+ config->enableWriteECC = false;
+ /* Default read ECC function */
+ config->enableReadECC = false;
+ /* Default swap function */
+ config->enableSwap = false;
+
+ /* ECC region 0 base address */
+ config->Region0BaseAddress = 0U;
+ /* ECC region 0 end address */
+ config->Region0EndAddress = 0U;
+ /* ECC region 1 base address */
+ config->Region1BaseAddress = 0U;
+ /* ECC region 1 end address */
+ config->Region1EndAddress = 0U;
+ /* ECC region 2 base address */
+ config->Region2BaseAddress = 0U;
+ /* ECC region 2 end address */
+ config->Region2EndAddress = 0U;
+ /* ECC region 3 base address */
+ config->Region3BaseAddress = 0U;
+ /* ECC region 3 end address */
+ config->Region3EndAddress = 0U;
+}
+
+/* Mainly use for debug, it can be deprecated when release */
+status_t XECC_ErrorInjection(XECC_Type *base, uint32_t errordata, uint8_t erroreccdata)
+{
+ status_t status = kStatus_Success;
+
+ if ((errordata != 0x00U) || (erroreccdata != 0x00U))
+ {
+ /* error data injection */
+ base->ERR_DATA_INJ = errordata;
+ /* error ecc code injection */
+ base->ERR_ECC_INJ = erroreccdata;
+ /* Make sure injection operation has been done. */
+ __DSB();
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+void XECC_GetSingleErrorInfo(XECC_Type *base, xecc_single_error_info_t *info)
+{
+ assert(info != NULL);
+
+ info->singleErrorAddress = base->SINGLE_ERR_ADDR;
+ info->singleErrorData = base->SINGLE_ERR_DATA;
+ info->singleErrorEccCode = base->SINGLE_ERR_ECC;
+ info->singleErrorBitField = base->SINGLE_ERR_BIT_FIELD;
+ info->singleErrorBitPos = base->SINGLE_ERR_POS;
+}
+
+void XECC_GetMultiErrorInfo(XECC_Type *base, xecc_multi_error_info_t *info)
+{
+ assert(info != NULL);
+
+ info->multiErrorAddress = base->MULTI_ERR_ADDR;
+ info->multiErrorData = base->MULTI_ERR_DATA;
+ info->multiErrorEccCode = base->MULTI_ERR_ECC;
+ info->multiErrorBitField = base->MULTI_ERR_BIT_FIELD;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.h b/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.h
new file mode 100644
index 0000000000..21b2226596
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xecc/fsl_xecc.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_XECC_H_
+#define _FSL_XECC_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup xecc
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions.
+ *****************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief Driver version 2.0.0. */
+#define FSL_XECC_DRIVER_VERSION (MAKE_VERSION(2U, 0U, 0U))
+/*@}*/
+
+/*!
+ * @brief XECC interrupt configuration structure, , xecc_interrupt_enable_t.
+ *
+ * This structure contains the settings for all of the XECC interrupt configurations.
+ */
+enum
+{
+ kXECC_SingleErrorInterruptEnable = XECC_ERR_SIG_EN_SINGLE_ERR_SIG_EN_MASK, /*!< Single bit error interrupt enable*/
+ kXECC_MultiErrorInterruptEnable = XECC_ERR_SIG_EN_MULTI_ERR_SIG_EN_MASK, /*!< Multiple bit error interrupt enable*/
+
+ kXECC_AllInterruptsEnable =
+ XECC_ERR_SIG_EN_SINGLE_ERR_SIG_EN_MASK | XECC_ERR_SIG_EN_MULTI_ERR_SIG_EN_MASK, /*!< all interrupts enable */
+};
+
+/*!
+ * @brief XECC interrupt status configuration structure, xecc_interrupt_status_enable_t.
+ *
+ * This structure contains the settings for all of the XECC interrupt status configurations.
+ */
+enum
+{
+ kXECC_SingleErrorInterruptStatusEnable =
+ XECC_ERR_STAT_EN_SINGLE_ERR_STAT_EN_MASK, /*!< Single bit error interrupt status enable*/
+ kXECC_MultiErrorInterruptStatusEnable =
+ XECC_ERR_STAT_EN_MULIT_ERR_STAT_EN_MASK, /*!< Multiple bits error interrupt status enable*/
+
+ kXECC_AllInterruptsStatusEnable = XECC_ERR_STAT_EN_SINGLE_ERR_STAT_EN_MASK |
+ XECC_ERR_STAT_EN_MULIT_ERR_STAT_EN_MASK, /*!< all interrupts enable */
+};
+
+/*!
+ * @brief XECC status flags, xecc_interrupt_status_t.
+ *
+ * This provides constants for the XECC status flags for use in the XECC functions.
+ */
+enum
+{
+ kXECC_SingleErrorInterruptFlag =
+ XECC_ERR_STATUS_SINGLE_ERR_MASK, /*!< Single bit error interrupt happens on read data*/
+ kXECC_MultiErrorInterruptFlag =
+ XECC_ERR_STATUS_MULTI_ERR_MASK, /*!< Multiple bits error interrupt happens on read data*/
+
+ kXECC_AllInterruptsFlag =
+ XECC_ERR_STATUS_SINGLE_ERR_MASK | XECC_ERR_STATUS_MULTI_ERR_MASK, /*!< all interrupts happens on read data*/
+};
+
+/*! @brief XECC user configuration.*/
+typedef struct _xecc_config
+{
+ bool enableXECC; /*!< Enable the XECC function. */
+ bool enableWriteECC; /*!< Enable write ECC function. */
+ bool enableReadECC; /*!< Enable read ECC function. */
+ bool enableSwap; /*!< Enable swap function. */
+
+ /*!< The minimum ECC region range is 4k, so the lower 12 bits of this register must be 0.*/
+ uint32_t Region0BaseAddress; /*!< ECC region 0 base address. */
+ uint32_t Region0EndAddress; /*!< ECC region 0 end address. */
+ uint32_t Region1BaseAddress; /*!< ECC region 1 base address. */
+ uint32_t Region1EndAddress; /*!< ECC region 1 end address. */
+ uint32_t Region2BaseAddress; /*!< ECC region 2 base address. */
+ uint32_t Region2EndAddress; /*!< ECC region 2 end address. */
+ uint32_t Region3BaseAddress; /*!< ECC region 3 base address. */
+ uint32_t Region3EndAddress; /*!< ECC region 3 end address. */
+} xecc_config_t;
+
+/*! @brief XECC single error information, including single error address, ECC code, error data, error bit
+ * position and error bit field */
+typedef struct _xecc_single_error_info
+{
+ uint32_t singleErrorAddress; /*!< Single error address */
+ uint32_t singleErrorData; /*!< Single error read data */
+ uint32_t singleErrorEccCode; /*!< Single error ECC code */
+ uint32_t singleErrorBitPos; /*!< Single error bit postion */
+ uint32_t singleErrorBitField; /*!< Single error bit field */
+} xecc_single_error_info_t;
+
+/*! @brief XECC multiple error information, including multiple error address, ECC code, error data and error bit field
+ */
+typedef struct _xecc_multi_error_info
+{
+ uint32_t multiErrorAddress; /*!< Multiple error address */
+ uint32_t multiErrorData; /*!< Multiple error read data */
+ uint32_t multiErrorEccCode; /*!< Multiple error ECC code */
+ uint32_t multiErrorBitField; /*!< Single error bit field */
+} xecc_multi_error_info_t;
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief XECC module initialization function.
+ *
+ * @param base XECC base address.
+ * @param config pointer to the XECC configuration structure.
+ */
+void XECC_Init(XECC_Type *base, const xecc_config_t *config);
+
+/*!
+ * @brief Deinitializes the XECC.
+ *
+ * @param base XECC base address.
+ */
+void XECC_Deinit(XECC_Type *base);
+
+/*!
+ * @brief Sets the XECC configuration structure to default values.
+ *
+ * @param config pointer to the XECC configuration structure.
+ */
+void XECC_GetDefaultConfig(xecc_config_t *config);
+
+/* @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+/*!
+ * @brief Gets XECC status flags.
+ *
+ * @param base XECC peripheral base address.
+ * @return XECC status flags.
+ */
+static inline uint32_t XECC_GetStatusFlags(XECC_Type *base)
+{
+ return base->ERR_STATUS & (uint32_t)kXECC_AllInterruptsFlag;
+}
+
+/*!
+ * @brief XECC module clear interrupt status.
+ *
+ * @param base XECC base address.
+ * @param mask status to clear from xecc_interrupt_status_t.
+ */
+static inline void XECC_ClearStatusFlags(XECC_Type *base, uint32_t mask)
+{
+ base->ERR_STATUS = mask;
+}
+
+/*!
+ * @brief XECC module enable interrupt status.
+ *
+ * @param base XECC base address.
+ * @param mask status to enable from xecc_interrupt_status_enable_t.
+ */
+static inline void XECC_EnableInterruptStatus(XECC_Type *base, uint32_t mask)
+{
+ base->ERR_STAT_EN |= mask;
+}
+
+/*!
+ * @brief XECC module disable interrupt status.
+ *
+ * @param base XECC base address.
+ * @param mask status to disable from xecc_interrupt_status_enable_t.
+ */
+static inline void XECC_DisableInterruptStatus(XECC_Type *base, uint32_t mask)
+{
+ base->ERR_STAT_EN &= ~mask;
+}
+
+/* @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief XECC module enable interrupt.
+ *
+ * @param base XECC base address.
+ * @param mask The interrupts to enable from xecc_interrupt_enable_t.
+ */
+static inline void XECC_EnableInterrupts(XECC_Type *base, uint32_t mask)
+{
+ base->ERR_SIG_EN |= mask;
+}
+
+/*!
+ * @brief XECC module disable interrupt.
+ *
+ * @param base XECC base address.
+ * @param mask The interrupts to disable from xecc_interrupt_enable_t.
+ */
+static inline void XECC_DisableInterrupts(XECC_Type *base, uint32_t mask)
+{
+ base->ERR_SIG_EN &= ~mask;
+}
+/* @} */
+
+/*!
+ * @name functional
+ * @{
+ */
+/*!
+ * @brief XECC module write ECC function enable.
+ *
+ * @param base XECC base address.
+ * @param enable enable or disable.
+ */
+static inline void XECC_WriteECCEnable(XECC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_WECC_EN(1);
+ }
+ else
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_WECC_EN(0);
+ }
+}
+
+/*!
+ * @brief XECC module read ECC function enable.
+ *
+ * @param base XECC base address.
+ * @param enable enable or disable.
+ */
+static inline void XECC_ReadECCEnable(XECC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_RECC_EN(1);
+ }
+ else
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_RECC_EN(0);
+ }
+}
+
+/*!
+ * @brief XECC module swap data enable.
+ *
+ * @param base XECC base address.
+ * @param enable enable or disable.
+ */
+static inline void XECC_SwapECCEnable(XECC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_SWAP_EN(1);
+ }
+ else
+ {
+ base->ECC_CTRL |= XECC_ECC_CTRL_SWAP_EN(0);
+ }
+}
+
+/*!
+ * @brief XECC module error injection.
+ *
+ * @param base XECC base address.
+ * @param errordata error data.
+ * @param erroreccdata ecc code.
+ * @retval kStatus_Success.
+ */
+status_t XECC_ErrorInjection(XECC_Type *base, uint32_t errordata, uint8_t erroreccdata);
+
+/*!
+ * @brief XECC module get single error information.
+ *
+ * @param base XECC base address.
+ * @param info single error information.
+ */
+void XECC_GetSingleErrorInfo(XECC_Type *base, xecc_single_error_info_t *info);
+
+/*!
+ * @brief XECC module get multiple error information.
+ *
+ * @param base XECC base address.
+ * @param info multiple error information.
+ */
+void XECC_GetMultiErrorInfo(XECC_Type *base, xecc_multi_error_info_t *info);
+
+/*! @}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.c b/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.c
new file mode 100644
index 0000000000..9aaf8fb156
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.c
@@ -0,0 +1,925 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xrdc2.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xrdc2"
+#endif
+
+/* Definitions for access policy. */
+#define XRDC2_DXACP_WIDTH (3U)
+#define XRDC2_DXACP_MASK ((1UL << XRDC2_DXACP_WIDTH) - 1U)
+
+#define XRDC2_DXACP_0_7(domainId, dxacp) ((uint32_t)(dxacp) << (XRDC2_DXACP_WIDTH * (uint32_t)(domainId)))
+#define XRDC2_DXACP_8_15(domainId, dxacp) ((uint32_t)(dxacp) << (XRDC2_DXACP_WIDTH * ((uint32_t)(domainId)-8U)))
+
+#define XRDC2_DXACP_0_7_MASK(domainId) XRDC2_DXACP_0_7(domainId, XRDC2_DXACP_MASK)
+#define XRDC2_DXACP_8_15_MASK(domainId) XRDC2_DXACP_8_15(domainId, XRDC2_DXACP_MASK)
+
+/* Memory region alignment. */
+#define XRDC2_MRGD_ADDR_ALIGN_MASK (0x00000FFFU)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static void XRDC2_MakeDXACP(const xrdc2_access_policy_t policy[FSL_FEATURE_XRDC2_DOMAIN_COUNT],
+ uint32_t *w0,
+ uint32_t *w1);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void XRDC2_MakeDXACP(const xrdc2_access_policy_t policy[FSL_FEATURE_XRDC2_DOMAIN_COUNT],
+ uint32_t *w0,
+ uint32_t *w1)
+{
+ uint32_t domain = (uint32_t)FSL_FEATURE_XRDC2_DOMAIN_COUNT;
+
+ *w0 = 0U;
+ *w1 = 0U;
+
+#if (FSL_FEATURE_XRDC2_DOMAIN_COUNT > 8)
+ while (domain > 8U)
+ {
+ domain--;
+ *w0 <<= XRDC2_DXACP_WIDTH;
+ *w0 |= (uint32_t)policy[domain - 8U];
+ }
+#endif
+
+ while (domain > 0U)
+ {
+ domain--;
+ *w1 <<= XRDC2_DXACP_WIDTH;
+ *w1 |= (uint32_t)policy[domain];
+ }
+}
+
+/*!
+ * brief Initializes the XRDC2 module.
+ *
+ * This function enables the XRDC2 clock.
+ *
+ * param base XRDC2 peripheral base address.
+ */
+void XRDC2_Init(XRDC2_Type *base)
+{
+}
+
+/*!
+ * brief De-initializes the XRDC2 module.
+ *
+ * This function disables the XRDC2 clock.
+ *
+ * param base XRDC2 peripheral base address.
+ */
+void XRDC2_Deinit(XRDC2_Type *base)
+{
+}
+
+/*!
+ * brief Sets the XRDC2 global valid.
+ *
+ * This function sets the XRDC2 global valid or invalid. When the XRDC2 is global
+ * invalid, all accesses from all bus masters to all slaves are allowed.
+ *
+ * param base XRDC2 peripheral base address.
+ * param valid True to valid XRDC2.
+ */
+void XRDC2_SetGlobalValid(XRDC2_Type *base, bool valid)
+{
+ uint32_t mcr = base->MCR & ~(XRDC2_MCR_GVLDM_MASK | XRDC2_MCR_GVLDC_MASK);
+
+ if (valid)
+ {
+ mcr |= XRDC2_MCR_GVLDM_MASK;
+ base->MCR = mcr;
+
+ /* Two dummy read to ensure the configuration takes effect. */
+ (void)base->MCR;
+ (void)base->MCR;
+
+ mcr |= XRDC2_MCR_GVLDC_MASK;
+ base->MCR = mcr;
+ }
+ else
+ {
+ base->MCR = mcr;
+ }
+}
+
+/*!
+ * brief Gets the default master domain assignment.
+ *
+ * This function sets the assignment as follows:
+ *
+ * code
+ * config->lock = false;
+ * config->privilegeAttr = kXRDC2_MasterPrivilege;
+ * config->secureAttr = kXRDC2_MasterSecure;
+ * config->domainId = 0U;
+ * config->mask = 0U;
+ * config->match = 0U;
+ * endcode
+ *
+ * param assignment Pointer to the assignment structure.
+ */
+void XRDC2_GetDefaultMasterDomainAssignment(xrdc2_master_domain_assignment_t *assignment)
+{
+ assert(NULL != assignment);
+
+ assignment->lock = false;
+ assignment->privilegeAttr = kXRDC2_MasterPrivilege;
+ assignment->secureAttr = kXRDC2_MasterSecure;
+ assignment->domainId = 0U;
+ assignment->mask = 0U;
+ assignment->match = 0U;
+}
+
+/*!
+ * brief Sets the processor bus master domain assignment.
+ *
+ * param base XRDC2 peripheral base address.
+ * param master Which master to configure.
+ * param assignIndex Which assignment register to set.
+ * param assignment Pointer to the assignment structure.
+ */
+void XRDC2_SetMasterDomainAssignment(XRDC2_Type *base,
+ xrdc2_master_t master,
+ uint8_t assignIndex,
+ const xrdc2_master_domain_assignment_t *assignment)
+{
+ assert(NULL != assignment);
+ uint32_t w0;
+ uint32_t w1;
+
+ w0 = (((uint32_t)assignment->mask << XRDC2_MDAC_MDA_W0_MASK_SHIFT) |
+ ((uint32_t)assignment->match << XRDC2_MDAC_MDA_W0_MATCH_SHIFT));
+
+ w1 = ((uint32_t)assignment->domainId << XRDC2_MDAC_MDA_W1_DID_SHIFT) |
+ (XRDC2_MDAC_MDA_W1_PA(assignment->privilegeAttr)) | (XRDC2_MDAC_MDA_W1_SA(assignment->secureAttr)) |
+ XRDC2_MDAC_MDA_W1_VLD_MASK;
+
+ if (assignment->lock)
+ {
+ w1 |= XRDC2_MDAC_MDA_W1_DL_MASK;
+ }
+
+ base->MDACI_MDAJ[master][assignIndex].MDAC_MDA_W0 = w0;
+ base->MDACI_MDAJ[master][assignIndex].MDAC_MDA_W1 = w1;
+}
+
+/*!
+ * brief Gets the default memory slot access configuration.
+ *
+ * This function sets the assignment as follows:
+ *
+ * code
+ * config->lockMode = kXRDC2_AccessConfigLockDisabled;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * endcode
+ *
+ * param config Pointer to the configuration.
+ */
+void XRDC2_GetMemSlotAccessDefaultConfig(xrdc2_mem_slot_access_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t domain;
+
+ config->lockMode = kXRDC2_AccessConfigLockDisabled;
+
+ for (domain = 0; domain < (uint32_t)FSL_FEATURE_XRDC2_DOMAIN_COUNT; domain++)
+ {
+ config->policy[domain] = kXRDC2_AccessPolicyNone;
+ }
+}
+
+/*!
+ * brief Sets the memory slot access policy.
+ *
+ * param base XRDC2 peripheral base address.
+ * param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetMemSlotAccessConfig(XRDC2_Type *base,
+ xrdc2_mem_slot_t memSlot,
+ const xrdc2_mem_slot_access_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t w0 = 0;
+ uint32_t w1 = 0;
+
+ XRDC2_MakeDXACP(config->policy, &w0, &w1);
+
+ w1 |= XRDC2_MSC_MSAC_W1_DL2(config->lockMode);
+ w1 |= XRDC2_MSC_MSAC_W1_VLD_MASK;
+
+ base->MSCI_MSAC_WK[(uint8_t)memSlot].MSC_MSAC_W0 = w0;
+ base->MSCI_MSAC_WK[(uint8_t)memSlot].MSC_MSAC_W1 = w1;
+}
+
+/*!
+ * brief Sets the memory slot descriptor as valid or invalid.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot Which memory slot descriptor to set.
+ * param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetMemSlotAccessValid(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, bool valid)
+{
+ uint32_t reg = base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 & ~XRDC2_EAL_MASK;
+
+ if (valid)
+ {
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = (reg | XRDC2_MSC_MSAC_W1_VLD_MASK);
+ }
+ else
+ {
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = (reg & ~XRDC2_MSC_MSAC_W1_VLD_MASK);
+ }
+}
+
+/*!
+ * brief Sets the memory slot descriptor lock mode.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot Which memory slot descriptor to set.
+ * param lockMode The lock mode to set.
+ */
+void XRDC2_SetMemSlotAccessLockMode(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, xrdc2_access_config_lock_t lockMode)
+{
+ uint32_t reg = base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 & ~(XRDC2_EAL_MASK | XRDC2_MRC_MRGD_W6_DL2_MASK);
+
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = (reg | XRDC2_MRC_MRGD_W6_DL2(lockMode));
+}
+
+/*!
+ * brief Sets the memory slot access policy for specific domain.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot The memory slot to operate.
+ * param domainId The ID of the domain whose policy will be changed.
+ * param policy The access policy to set.
+ */
+void XRDC2_SetMemSlotDomainAccessPolicy(XRDC2_Type *base,
+ xrdc2_mem_slot_t memSlot,
+ uint8_t domainId,
+ xrdc2_access_policy_t policy)
+{
+ uint32_t reg;
+
+ if (domainId < 8U)
+ {
+ reg = base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W0 & ~XRDC2_DXACP_0_7_MASK(domainId);
+ reg |= XRDC2_DXACP_0_7(domainId, policy);
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W0 = reg;
+ }
+ else
+ {
+ reg = base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 & ~XRDC2_DXACP_8_15_MASK(domainId);
+ reg |= XRDC2_DXACP_8_15(domainId, policy);
+ reg &= ~XRDC2_EAL_MASK;
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = reg;
+ }
+}
+
+/*!
+ * brief Enable or disable the memory slot exclusive access lock.
+ *
+ * The lock must be enabled first before use. Once disabled, it could not be
+ * enabled until reset.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot The memory slot to operate.
+ * param enable True to enable, false to disable.
+ */
+void XRDC2_EnableMemSlotExclAccessLock(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, bool enable)
+{
+ if (enable)
+ {
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = XRDC2_EAL_UNLOCKED;
+ }
+ else
+ {
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = XRDC2_EAL_DISABLE_UNTIL_RESET;
+ }
+}
+
+/*!
+ * @brief Get current memory slot exclusive access lock owner.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ * @return The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetMemSlotExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_mem_slot_t memSlot)
+{
+ return (uint8_t)((base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W0 & XRDC2_MSC_MSAC_W0_EALO_MASK) >>
+ XRDC2_MSC_MSAC_W0_EALO_SHIFT);
+}
+
+/*!
+ * brief Try to lock the memory slot exclusive access.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot The memory slot to operate.
+ * retval kStatus_Fail Failed to lock.
+ * retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockMemSlotExclAccess(XRDC2_Type *base, xrdc2_mem_slot_t memSlot)
+{
+ status_t status;
+ uint8_t curDomainID;
+ volatile uint32_t *lockReg = &(base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ if (curDomainID != XRDC2_GetMemSlotExclAccessLockDomainOwner(base, memSlot))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Lock the memory slot exclusive access using blocking method.
+ *
+ * param base XRDC2 peripheral base address.
+ * param memSlot The memory slot to operate.
+ *
+ * note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockMemSlotExclAccess(XRDC2_Type *base, xrdc2_mem_slot_t memSlot)
+{
+ uint8_t curDomainID;
+ volatile uint32_t *lockReg = &(base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ while (true)
+ {
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ /* Locked and owner is current domain. */
+ if (curDomainID == XRDC2_GetMemSlotExclAccessLockDomainOwner(base, memSlot))
+ {
+ break;
+ }
+ }
+
+ return;
+}
+
+/*!
+ * brief Gets the default memory access configuration.
+ *
+ * This function sets the assignment as follows:
+ *
+ * code
+ * config->startAddr = 0U;
+ * config->endAddr = 0xFFFFFFFFU;
+ * config->lockMode = kXRDC2_AccessConfigLockDisabled;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * endcode
+ *
+ * param config Pointer to the configuration.
+ */
+void XRDC2_GetMemAccessDefaultConfig(xrdc2_mem_access_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t domain;
+
+ config->startAddr = 0U;
+ config->endAddr = 0xFFFFFFFFU;
+ config->lockMode = kXRDC2_AccessConfigLockDisabled;
+
+ for (domain = 0; domain < (uint32_t)FSL_FEATURE_XRDC2_DOMAIN_COUNT; domain++)
+ {
+ config->policy[domain] = kXRDC2_AccessPolicyNone;
+ }
+}
+
+/*!
+ * brief Sets the memory region access policy.
+ *
+ * param base XRDC2 peripheral base address.
+ * param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetMemAccessConfig(XRDC2_Type *base, xrdc2_mem_t mem, const xrdc2_mem_access_config_t *config)
+{
+ assert(NULL != config);
+ /* Check the memory region alignment. */
+ assert((config->startAddr & XRDC2_MRGD_ADDR_ALIGN_MASK) == 0U);
+ assert(((config->endAddr + 1U) & XRDC2_MRGD_ADDR_ALIGN_MASK) == 0U);
+
+ uint32_t w5 = 0;
+ uint32_t w6 = 0;
+
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ XRDC2_MakeDXACP(config->policy, &w5, &w6);
+
+ w6 |= XRDC2_MRC_MRGD_W6_DL2(config->lockMode);
+ w6 |= XRDC2_MRC_MRGD_W6_VLD_MASK;
+
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W0 = config->startAddr;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W1 = 0U;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W2 = config->endAddr;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W3 = 0U;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W5 = w5;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = w6;
+}
+
+/*!
+ * brief Sets the memory region descriptor as valid or invalid.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem Which memory region descriptor to set.
+ * param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetMemAccessValid(XRDC2_Type *base, xrdc2_mem_t mem, bool valid)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+ uint32_t reg = base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 & ~XRDC2_EAL_MASK;
+
+ if (valid)
+ {
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = (reg | XRDC2_MRC_MRGD_W6_VLD_MASK);
+ }
+ else
+ {
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = (reg & ~XRDC2_MRC_MRGD_W6_VLD_MASK);
+ }
+}
+
+/*!
+ * brief Sets the memory descriptor lock mode.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem Which memory descriptor to set.
+ * param lockMode The lock mode to set.
+ */
+void XRDC2_SetMemAccessLockMode(XRDC2_Type *base, xrdc2_mem_t mem, xrdc2_access_config_lock_t lockMode)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+ uint32_t reg = base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 & ~(XRDC2_EAL_MASK | XRDC2_MRC_MRGD_W6_DL2_MASK);
+
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = (reg | XRDC2_MRC_MRGD_W6_DL2(lockMode));
+}
+
+/*!
+ * brief Sets the memory region access policy for specific domain.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ * param domainId The ID of the domain whose policy will be changed.
+ * param policy The access policy to set.
+ */
+void XRDC2_SetMemDomainAccessPolicy(XRDC2_Type *base, xrdc2_mem_t mem, uint8_t domainId, xrdc2_access_policy_t policy)
+{
+ uint32_t reg;
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ if (domainId < 8U)
+ {
+ reg = base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W5 & ~XRDC2_DXACP_0_7_MASK(domainId);
+ reg |= XRDC2_DXACP_0_7(domainId, policy);
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W5 = reg;
+ }
+ else
+ {
+ reg = base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 & ~XRDC2_DXACP_8_15_MASK(domainId);
+ reg |= XRDC2_DXACP_8_15(domainId, policy);
+ reg &= ~XRDC2_EAL_MASK;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = reg;
+ }
+}
+
+/*!
+ * brief Disable the memory region exclusive access lock.
+ *
+ * Once disabled, it could not be enabled until reset.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ */
+void XRDC2_EnableMemExclAccessLock(XRDC2_Type *base, xrdc2_mem_t mem, bool enable)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ if (enable)
+ {
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = XRDC2_EAL_UNLOCKED;
+ }
+ else
+ {
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = XRDC2_EAL_DISABLE_UNTIL_RESET;
+ }
+}
+
+/*!
+ * brief Get current memory region exclusive access lock owner.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ * param The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetMemExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_mem_t mem)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ return (uint8_t)((base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W5 & XRDC2_MRC_MRGD_W5_EALO_MASK) >>
+ XRDC2_MRC_MRGD_W5_EALO_SHIFT);
+}
+
+/*!
+ * brief Try to lock the memory region exclusive access.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ * retval kStatus_Fail Failed to lock.
+ * retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem)
+{
+ status_t status;
+ uint8_t curDomainID;
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+ volatile uint32_t *lockReg = &(base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ if (curDomainID != XRDC2_GetMemExclAccessLockDomainOwner(base, mem))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Lock the memory region exclusive access using blocking method.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ *
+ * note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem)
+{
+ uint8_t curDomainID;
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+ volatile uint32_t *lockReg = &(base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ while (true)
+ {
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ /* Locked and owner is current domain. */
+ if (curDomainID == XRDC2_GetMemExclAccessLockDomainOwner(base, mem))
+ {
+ break;
+ }
+ }
+
+ return;
+}
+
+/*!
+ * brief Unlock the memory region exclusive access.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ *
+ * note This function must be called by the lock owner.
+ */
+void XRDC2_UnlockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = XRDC2_EAL_UNLOCKED;
+}
+
+/*!
+ * brief Force the memory region exclusive access lock release.
+ *
+ * The master does not own the lock could call this function to force release the lock.
+ *
+ * param base XRDC2 peripheral base address.
+ * param mem The memory region to operate.
+ */
+void XRDC2_ForceMemExclAccessLockRelease(XRDC2_Type *base, xrdc2_mem_t mem)
+{
+ uint32_t mrc = XRDC2_GET_MRC((uint32_t)mem);
+ uint32_t mrgd = XRDC2_GET_MRGD((uint32_t)mem);
+
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = XRDC2_EAL_FORCE_RELEASE_MAGIC_0;
+ base->MRCI_MRGDJ[mrc][mrgd].MRC_MRGD_W6 = XRDC2_EAL_FORCE_RELEASE_MAGIC_1;
+}
+
+/*!
+ * brief Gets the default peripheral access configuration.
+ *
+ * The default configuration is set as follows:
+ * code
+ * config->lockMode = kXRDC2_AccessConfigLockWritable;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * config->policy[15] = kXRDC2_AccessPolicyNone;
+ * endcode
+ *
+ * param config Pointer to the configuration structure.
+ */
+void XRDC2_GetPeriphAccessDefaultConfig(xrdc2_periph_access_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t domain;
+
+ config->lockMode = kXRDC2_AccessConfigLockDisabled;
+
+ for (domain = 0; domain < (uint32_t)FSL_FEATURE_XRDC2_DOMAIN_COUNT; domain++)
+ {
+ config->policy[domain] = kXRDC2_AccessPolicyNone;
+ }
+}
+
+/*!
+ * brief Sets the peripheral access policy.
+ *
+ * param base XRDC2 peripheral base address.
+ * param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetPeriphAccessConfig(XRDC2_Type *base, xrdc2_periph_t periph, const xrdc2_periph_access_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t w0 = 0;
+ uint32_t w1 = 0;
+
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ XRDC2_MakeDXACP(config->policy, &w0, &w1);
+
+ w1 |= XRDC2_PAC_PDAC_W1_DL2(config->lockMode);
+ w1 |= XRDC2_PAC_PDAC_W1_VLD_MASK;
+
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W0 = w0;
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = w1;
+}
+
+/*!
+ * brief Sets the peripheral descriptor as valid or invalid.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph Which peripheral descriptor to set.
+ * param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetPeriphAccessValid(XRDC2_Type *base, xrdc2_periph_t periph, bool valid)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+ uint32_t reg = base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 & ~XRDC2_EAL_MASK;
+
+ if (valid)
+ {
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = (reg | XRDC2_PAC_PDAC_W1_VLD_MASK);
+ }
+ else
+ {
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = (reg & ~XRDC2_PAC_PDAC_W1_VLD_MASK);
+ }
+}
+
+/*!
+ * brief Sets the peripheral descriptor lock mode.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph Which peripheral descriptor to set.
+ * param lockMode The lock mode to set.
+ */
+void XRDC2_SetPeriphAccessLockMode(XRDC2_Type *base, xrdc2_periph_t periph, xrdc2_access_config_lock_t lockMode)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+ uint32_t reg = base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 & ~(XRDC2_EAL_MASK | XRDC2_PAC_PDAC_W1_DL2_MASK);
+
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = (reg | XRDC2_PAC_PDAC_W1_DL2(lockMode));
+}
+
+/*!
+ * brief Sets the peripheral access policy for specific domain.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ * param domainId The ID of the domain whose policy will be changed.
+ * param policy The access policy to set.
+ */
+void XRDC2_SetPeriphDomainAccessPolicy(XRDC2_Type *base,
+ xrdc2_periph_t periph,
+ uint8_t domainId,
+ xrdc2_access_policy_t policy)
+{
+ uint32_t reg;
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ if (domainId < 8U)
+ {
+ reg = base->PACI_PDACJ[pac][pdac].PAC_PDAC_W0 & ~XRDC2_DXACP_0_7_MASK(domainId);
+ reg |= XRDC2_DXACP_0_7(domainId, policy);
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W0 = reg;
+ }
+ else
+ {
+ reg = base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 & ~XRDC2_DXACP_8_15_MASK(domainId);
+ reg |= XRDC2_DXACP_8_15(domainId, policy);
+ reg &= ~XRDC2_EAL_MASK;
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = reg;
+ }
+}
+
+/*!
+ * brief Get current peripheral exclusive access lock owner.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ * param The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetPeriphExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_periph_t periph)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ return (uint8_t)((base->PACI_PDACJ[pac][pdac].PAC_PDAC_W0 & XRDC2_PAC_PDAC_W0_EALO_MASK) >>
+ XRDC2_PAC_PDAC_W0_EALO_SHIFT);
+}
+
+/*!
+ * brief Disable the peripheral exclusive access lock.
+ *
+ * Once disabled, it could not be enabled until reset.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ * param enable True to enable, false to disable.
+ */
+void XRDC2_EnablePeriphExclAccessLock(XRDC2_Type *base, xrdc2_periph_t periph, bool enable)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ if (enable)
+ {
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = XRDC2_EAL_UNLOCKED;
+ }
+ else
+ {
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = XRDC2_EAL_DISABLE_UNTIL_RESET;
+ }
+}
+
+/*!
+ * brief Try to lock the peripheral exclusive access.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ * retval kStatus_Fail Failed to lock.
+ * retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph)
+{
+ status_t status;
+ uint8_t curDomainID;
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ volatile uint32_t *lockReg = &(base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ if (curDomainID != XRDC2_GetPeriphExclAccessLockDomainOwner(base, periph))
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Lock the peripheral exclusive access using blocking method.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ *
+ * note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph)
+{
+ uint8_t curDomainID;
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ volatile uint32_t *lockReg = &(base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1);
+
+ curDomainID = XRDC2_GetCurrentMasterDomainId(base);
+
+ while (true)
+ {
+ *lockReg = XRDC2_EAL_LOCKED;
+
+ /* Locked and owner is current domain. */
+ if (curDomainID == XRDC2_GetPeriphExclAccessLockDomainOwner(base, periph))
+ {
+ break;
+ }
+ }
+
+ return;
+}
+
+/*!
+ * brief Unlock the peripheral exclusive access.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ *
+ * note This function must be called by the lock owner.
+ */
+void XRDC2_UnlockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = XRDC2_EAL_UNLOCKED;
+}
+
+/*!
+ * brief Force the peripheral exclusive access lock release.
+ *
+ * The master does not own the lock could call this function to force release the lock.
+ *
+ * param base XRDC2 peripheral base address.
+ * param periph The peripheral to operate.
+ */
+void XRDC2_ForcePeriphExclAccessLockRelease(XRDC2_Type *base, xrdc2_periph_t periph)
+{
+ uint32_t pac = XRDC2_GET_PAC((uint32_t)periph);
+ uint32_t pdac = XRDC2_GET_PDAC((uint32_t)periph);
+
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = XRDC2_EAL_FORCE_RELEASE_MAGIC_0;
+ base->PACI_PDACJ[pac][pdac].PAC_PDAC_W1 = XRDC2_EAL_FORCE_RELEASE_MAGIC_1;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.h b/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.h
new file mode 100644
index 0000000000..bb0f1a884b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/xrdc2/fsl_xrdc2.h
@@ -0,0 +1,690 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_XRDC2_H_
+#define _FSL_XRDC2_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup xrdc2
+ * @{
+ */
+
+/******************************************************************************
+ * Definitions
+ *****************************************************************************/
+/*! @brief Driver version. */
+#define FSL_XRDC2_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
+
+/* Definitions for XRDC2 Exclusive access lock. */
+#define XRDC2_EAL_FORCE_RELEASE_MAGIC_0 0x02000046UL
+#define XRDC2_EAL_FORCE_RELEASE_MAGIC_1 0x02000052UL
+
+#define XRDC2_EAL_DISABLE (0UL << XRDC2_MSC_MSAC_W1_EAL_SHIFT)
+#define XRDC2_EAL_DISABLE_UNTIL_RESET (1UL << XRDC2_MSC_MSAC_W1_EAL_SHIFT)
+#define XRDC2_EAL_UNLOCKED (2UL << XRDC2_MSC_MSAC_W1_EAL_SHIFT)
+#define XRDC2_EAL_LOCKED (3UL << XRDC2_MSC_MSAC_W1_EAL_SHIFT)
+
+#define XRDC2_EAL_MASK XRDC2_MSC_MSAC_W1_EAL_MASK
+
+/*!
+ * @brief Global configuration lock.
+ */
+typedef enum _xrdc2_global_config_lock
+{
+ kXRDC2_GlobalConfigLockDisabled, /*!< Lock disabled, registers can be written by any domain. */
+ kXRDC2_GlobalConfigLockDisabledUntilReset, /*!< Lock disabled until the next reset. */
+ kXRDC2_GlobalConfigLockOwnerOnly, /*!< Lock enabled, only the lock owner can write. */
+ kXRDC2_GlobalConfigLockEnabledUntilReset /*!< Lock enabled, all registers are read only until the next reset. */
+} xrdc2_global_config_lock_t;
+
+/*!
+ * @brief XRDC2 secure attribute, the register bit MDACi_MDAj_W0[SA],
+ * secure/nonsecure attribute output on a hit.
+ */
+typedef enum _xrdc2_secure_attr
+{
+ kXRDC2_MasterSecure = 0, /*!< Use the bus master's secure/nonsecure attribute directly. */
+ kXRDC2_ForceSecure = 2, /*!< Force the bus attribute for this master to secure. */
+ kXRDC2_ForceNonSecure = 3, /*!< Force the bus attribute for this master to non-secure. */
+} xrdc2_secure_attr_t;
+
+/*!
+ * @brief XRDC2 privileged attribute, the register bit MDACi_MDAj_W0[PA],
+ * defines the privileged/user attribute on a hit.
+ */
+typedef enum _xrdc2_privilege_attr
+{
+ kXRDC2_MasterPrivilege = 0, /*!< Use the bus master's attribute directly. */
+ kXRDC2_ForceUser = 2, /*!< Force the bus attribute for this master to user. */
+ kXRDC2_ForcePrivilege = 3, /*!< Force the bus attribute for this master to privileged. */
+} xrdc2_privilege_attr_t;
+
+/*!
+ * @brief Domain assignment for the bus master.
+ *
+ * XRDC2 compares the bus master @e match @e input with the parameter @ref mask
+ * and @ref match in this structure. If hit, the domain ID, privilege attribute,
+ * and secure attribute are used for the access.
+ */
+typedef struct _xrdc2_master_domain_assignment
+{
+ bool lock; /*!< Set true to lock the descriptor. */
+ xrdc2_privilege_attr_t privilegeAttr; /*!< Privilege attribute. */
+ xrdc2_secure_attr_t secureAttr; /*!< Secure attribute. */
+ uint8_t domainId; /*!< Domain ID used when this descriptor hit. */
+ uint16_t mask; /*!< Mask used for descriptor hit. */
+ uint16_t match; /*!< Match used for descriptor hit. */
+} xrdc2_master_domain_assignment_t;
+
+/*!
+ * @brief XRDC2 domain access control policy.
+ */
+typedef enum _xrdc2_access_policy
+{
+ /* policy SecurePriv SecureUser NonSecurePriv NonSecureUsr */
+ kXRDC2_AccessPolicyNone = 0U, /* 000 none none none none */
+ kXRDC2_AccessPolicyAlt1 = 1U, /* 001 r r none none */
+ kXRDC2_AccessPolicyAlt2 = 2U, /* 010 r,w none none none */
+ kXRDC2_AccessPolicyAlt3 = 3U, /* 011 r,w r,w none none */
+ kXRDC2_AccessPolicyAlt4 = 4U, /* 100 r,w r,w r none */
+ kXRDC2_AccessPolicyAlt5 = 5U, /* 101 r,w r,w r r */
+ kXRDC2_AccessPolicyAlt6 = 6U, /* 110 r,w r,w r,w none */
+ kXRDC2_AccessPolicyAll = 7U /* 111 r,w r,w r,w r,w */
+} xrdc2_access_policy_t;
+
+/*!
+ * @brief Access configuration lock mode, the register field PDAC and MRGD LK2.
+ */
+typedef enum _xrdc2_access_config_lock
+{
+ kXRDC2_AccessConfigLockDisabled = 0U, /*!< Entire PDACn/MRGDn/MSC can be written. */
+ kXRDC2_AccessConfigLockDisabledUntilReset = 1U, /*!< Entire PDACn/MRGDn/MSC can be written until next reset. */
+ kXRDC2_AccessConfigLockDomainXOnly = 2U, /*!< Domain x only write the DxACP field. */
+ kXRDC2_AccessConfigLockEnabledUntilReset = 3U /*!< PDACn/MRGDn/MSC is read-only until the next reset. */
+} xrdc2_access_config_lock_t;
+
+/*!
+ * @brief XRDC2 peripheral domain access control configuration.
+ */
+typedef struct _xrdc2_periph_access_config
+{
+ xrdc2_access_config_lock_t lockMode; /*!< PDACn lock configuration. */
+ xrdc2_access_policy_t policy[FSL_FEATURE_XRDC2_DOMAIN_COUNT]; /*!< Access policy for each domain. */
+} xrdc2_periph_access_config_t;
+
+/*!
+ * @brief XRDC2 memory region domain access control configuration.
+ */
+typedef struct _xrdc2_mem_access_config
+{
+ uint32_t startAddr; /*!< Memory region start address, should be 4k aligned. */
+ uint32_t endAddr; /*!< Memory region end address, (endAddr + 1) should be 4k aligned. */
+ xrdc2_access_config_lock_t lockMode; /*!< MRGDn lock configuration. */
+ xrdc2_access_policy_t policy[FSL_FEATURE_XRDC2_DOMAIN_COUNT]; /*!< Access policy for each domain. */
+} xrdc2_mem_access_config_t;
+
+/*!
+ * @brief XRDC2 memory slot domain access control configuration.
+ */
+typedef struct _xrdc2_mem_slot_access_config
+{
+ xrdc2_access_config_lock_t lockMode; /*!< Descriptor lock configuration. */
+ xrdc2_access_policy_t policy[FSL_FEATURE_XRDC2_DOMAIN_COUNT]; /*!< Access policy for each domain. */
+} xrdc2_mem_slot_access_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Initializes the XRDC2 module.
+ *
+ * @param base XRDC2 peripheral base address.
+ */
+void XRDC2_Init(XRDC2_Type *base);
+
+/*!
+ * @brief De-initializes the XRDC2 module.
+ *
+ * @param base XRDC2 peripheral base address.
+ */
+void XRDC2_Deinit(XRDC2_Type *base);
+
+/*!
+ * @name XRDC2 manager (XRDC2)
+ * @{
+ */
+
+/*!
+ * @brief Sets the XRDC2 global valid.
+ *
+ * This function sets the XRDC2 global valid or invalid. When the XRDC2 is global
+ * invalid, all accesses from all bus masters to all slaves are allowed.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param valid True to valid XRDC2.
+ */
+void XRDC2_SetGlobalValid(XRDC2_Type *base, bool valid);
+
+/*!
+ * @brief Gets the domain ID of the current bus master.
+ *
+ * This function returns the domain ID of the current bus master.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @return Domain ID of current bus master.
+ */
+static inline uint8_t XRDC2_GetCurrentMasterDomainId(XRDC2_Type *base)
+{
+#if defined(XRDC2_SR_DIN_MASK)
+ return (uint8_t)((base->SR & XRDC2_SR_DIN_MASK) >> XRDC2_SR_DIN_SHIFT);
+#else
+ return (uint8_t)((base->SR & XRDC2_SR_DID_MASK) >> XRDC2_SR_DID_SHIFT);
+#endif
+}
+
+/*!
+ * @brief Set the global configuration lock mode.
+ *
+ * Once change the lock mode, it could not be changed until next reset.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mode The lock mode.
+ */
+static inline void XRDC2_SetGlobalConfigLock(XRDC2_Type *base, xrdc2_global_config_lock_t mode)
+{
+ base->MCR = (base->MCR & ~XRDC2_MCR_GCL_MASK) | XRDC2_MCR_GCL(mode);
+}
+
+/*!
+ * @brief Gets the domain ID of global configuration lock owner.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @return Domain ID of the global configuration lock owner.
+ */
+static inline uint8_t XRDC2_GetCurrentGlobalConfigLockOwnerDomainId(XRDC2_Type *base)
+{
+ return (uint8_t)((base->SR & XRDC2_SR_GCLO_MASK) >> XRDC2_SR_GCLO_SHIFT);
+}
+
+/*@}*/
+
+/*!
+ * @name XRDC2 Master Domain Assignment Controller (XRDC2_MDAC).
+ * @{
+ */
+
+/*!
+ * @brief Gets the default master domain assignment.
+ *
+ * This function sets the assignment as follows:
+ *
+ * @code
+ * config->lock = false;
+ * config->privilegeAttr = kXRDC2_MasterPrivilege;
+ * config->secureAttr = kXRDC2_MasterSecure;
+ * config->domainId = 0U;
+ * config->mask = 0U;
+ * config->match = 0U;
+ * @endcode
+ *
+ * @param assignment Pointer to the assignment structure.
+ */
+void XRDC2_GetDefaultMasterDomainAssignment(xrdc2_master_domain_assignment_t *assignment);
+
+/*!
+ * @brief Sets the processor bus master domain assignment.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param master Which master to configure.
+ * @param assignIndex Which assignment register to set.
+ * @param assignment Pointer to the assignment structure.
+ */
+void XRDC2_SetMasterDomainAssignment(XRDC2_Type *base,
+ xrdc2_master_t master,
+ uint8_t assignIndex,
+ const xrdc2_master_domain_assignment_t *assignment);
+
+/*!
+ * @brief Locks the bus master domain assignment register.
+ *
+ * This function locks the master domain assignment. One bus master might have
+ * multiple domain assignment registers. The parameter \p assignIndex specifies
+ * which assignment register to lock. After it is locked, the register can't be changed
+ * until next reset.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param master Which master to configure.
+ * @param assignIndex Which assignment register to lock.
+ */
+static inline void XRDC2_LockMasterDomainAssignment(XRDC2_Type *base, xrdc2_master_t master, uint8_t assignIndex)
+{
+ base->MDACI_MDAJ[master][assignIndex].MDAC_MDA_W1 |= XRDC2_MDAC_MDA_W1_DL_MASK;
+}
+
+/*!
+ * @brief Sets the master domain assignment as valid or invalid.
+ *
+ * This function sets the master domain assignment as valid or invalid. One bus master might have
+ * multiple domain assignment registers. The parameter \p assignIndex specifies
+ * which assignment register to configure.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param master Which master to configure.
+ * @param assignIndex Index for the domain assignment register.
+ * @param valid True to set valid, false to set invalid.
+ */
+static inline void XRDC2_SetMasterDomainAssignmentValid(XRDC2_Type *base,
+ xrdc2_master_t master,
+ uint8_t assignIndex,
+ bool valid)
+{
+ if (valid)
+ {
+ base->MDACI_MDAJ[master][assignIndex].MDAC_MDA_W1 |= XRDC2_MDAC_MDA_W1_VLD_MASK;
+ }
+ else
+ {
+ base->MDACI_MDAJ[master][assignIndex].MDAC_MDA_W1 &= ~XRDC2_MDAC_MDA_W1_VLD_MASK;
+ }
+}
+
+/*@}*/
+
+/*!
+ * @name XRDC2 Memory Slot Access Controller (XRDC2_MSC).
+ * @{
+ */
+
+/*!
+ * @brief Gets the default memory slot access configuration.
+ *
+ * This function sets the assignment as follows:
+ *
+ * @code
+ * config->lockMode = kXRDC2_AccessConfigLockDisabled;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * @endcode
+ *
+ * @param config Pointer to the configuration.
+ */
+void XRDC2_GetMemSlotAccessDefaultConfig(xrdc2_mem_slot_access_config_t *config);
+
+/*!
+ * @brief Sets the memory slot access policy.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot Which memory slot descriptor to set.
+ * @param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetMemSlotAccessConfig(XRDC2_Type *base,
+ xrdc2_mem_slot_t memSlot,
+ const xrdc2_mem_slot_access_config_t *config);
+
+/*!
+ * @brief Sets the memory slot descriptor as valid or invalid.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot Which memory slot descriptor to set.
+ * @param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetMemSlotAccessValid(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, bool valid);
+
+/*!
+ * @brief Sets the memory slot descriptor lock mode.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot Which memory slot descriptor to set.
+ * @param lockMode The lock mode to set.
+ */
+void XRDC2_SetMemSlotAccessLockMode(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, xrdc2_access_config_lock_t lockMode);
+
+/*!
+ * @brief Sets the memory slot access policy for specific domain.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ * @param domainId The ID of the domain whose policy will be changed.
+ * @param policy The access policy to set.
+ */
+void XRDC2_SetMemSlotDomainAccessPolicy(XRDC2_Type *base,
+ xrdc2_mem_slot_t memSlot,
+ uint8_t domainId,
+ xrdc2_access_policy_t policy);
+
+/*!
+ * @brief Enable or disable the memory slot exclusive access lock.
+ *
+ * The lock must be enabled first before use. Once disabled, it could not be
+ * enabled until reset.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ * @param enable True to enable, false to disable.
+ */
+void XRDC2_EnableMemSlotExclAccessLock(XRDC2_Type *base, xrdc2_mem_slot_t memSlot, bool enable);
+
+/*!
+ * @brief Get current memory slot exclusive access lock owner.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ * @return The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetMemSlotExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_mem_slot_t memSlot);
+
+/*!
+ * @brief Try to lock the memory slot exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ * @retval kStatus_Fail Failed to lock.
+ * @retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockMemSlotExclAccess(XRDC2_Type *base, xrdc2_mem_slot_t memSlot);
+
+/*!
+ * @brief Lock the memory slot exclusive access using blocking method.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ *
+ * @note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockMemSlotExclAccess(XRDC2_Type *base, xrdc2_mem_slot_t memSlot);
+
+/*!
+ * @brief Unlock the memory slot exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ *
+ * @note This function must be called by the lock owner.
+ */
+static inline void XRDC2_UnlockMemSlotExclAccess(XRDC2_Type *base, xrdc2_mem_slot_t memSlot)
+{
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = XRDC2_EAL_UNLOCKED;
+}
+
+/*!
+ * @brief Force the memory slot exclusive access lock release.
+ *
+ * The master does not own the lock could call this function to force release the lock.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param memSlot The memory slot to operate.
+ */
+static inline void XRDC2_ForceMemSlotExclAccessLockRelease(XRDC2_Type *base, xrdc2_mem_slot_t memSlot)
+{
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = XRDC2_EAL_FORCE_RELEASE_MAGIC_0;
+ base->MSCI_MSAC_WK[(uint32_t)memSlot].MSC_MSAC_W1 = XRDC2_EAL_FORCE_RELEASE_MAGIC_1;
+}
+
+/*@}*/
+
+/*!
+ * @name XRDC2 Memory Region Controller (XRDC2_MRC)
+ * @{
+ */
+
+/*!
+ * @brief Gets the default memory access configuration.
+ *
+ * This function sets the assignment as follows:
+ *
+ * @code
+ * config->startAddr = 0U;
+ * config->endAddr = 0xFFFFFFFFU;
+ * config->lockMode = kXRDC2_AccessConfigLockDisabled;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * @endcode
+ *
+ * @param config Pointer to the configuration.
+ */
+void XRDC2_GetMemAccessDefaultConfig(xrdc2_mem_access_config_t *config);
+
+/*!
+ * @brief Sets the memory region access policy.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem Which memory region descriptor to set.
+ * @param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetMemAccessConfig(XRDC2_Type *base, xrdc2_mem_t mem, const xrdc2_mem_access_config_t *config);
+
+/*!
+ * @brief Sets the memory region descriptor as valid or invalid.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem Which memory region descriptor to set.
+ * @param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetMemAccessValid(XRDC2_Type *base, xrdc2_mem_t mem, bool valid);
+
+/*!
+ * @brief Sets the memory descriptor lock mode.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem Which memory descriptor to set.
+ * @param lockMode The lock mode to set.
+ */
+void XRDC2_SetMemAccessLockMode(XRDC2_Type *base, xrdc2_mem_t mem, xrdc2_access_config_lock_t lockMode);
+
+/*!
+ * @brief Sets the memory region access policy for specific domain.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ * @param domainId The ID of the domain whose policy will be changed.
+ * @param policy The access policy to set.
+ */
+void XRDC2_SetMemDomainAccessPolicy(XRDC2_Type *base, xrdc2_mem_t mem, uint8_t domainId, xrdc2_access_policy_t policy);
+
+/*!
+ * @brief Enable or disable the memory region exclusive access lock.
+ *
+ * Once disabled, it could not be enabled until reset.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ * @param enable True to enable, false to disable.
+ */
+void XRDC2_EnableMemExclAccessLock(XRDC2_Type *base, xrdc2_mem_t mem, bool enable);
+
+/*!
+ * @brief Get current memory region exclusive access lock owner.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ * @return The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetMemExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_mem_t mem);
+
+/*!
+ * @brief Try to lock the memory region exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ * @retval kStatus_Fail Failed to lock.
+ * @retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem);
+
+/*!
+ * @brief Lock the memory region exclusive access using blocking method.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ *
+ * @note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem);
+
+/*!
+ * @brief Unlock the memory region exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ *
+ * @note This function must be called by the lock owner.
+ */
+void XRDC2_UnlockMemExclAccess(XRDC2_Type *base, xrdc2_mem_t mem);
+
+/*!
+ * @brief Force the memory region exclusive access lock release.
+ *
+ * The master does not own the lock could call this function to force release the lock.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param mem The memory region to operate.
+ */
+void XRDC2_ForceMemExclAccessLockRelease(XRDC2_Type *base, xrdc2_mem_t mem);
+
+/*@}*/
+
+/*!
+ * @name XRDC2 Peripheral Access Controller (XRDC2_PAC)
+ * @{
+ */
+
+/*!
+ * @brief Gets the default peripheral access configuration.
+ *
+ * The default configuration is set as follows:
+ * @code
+ * config->lockMode = kXRDC2_AccessConfigLockWritable;
+ * config->policy[0] = kXRDC2_AccessPolicyNone;
+ * config->policy[1] = kXRDC2_AccessPolicyNone;
+ * ...
+ * config->policy[15] = kXRDC2_AccessPolicyNone;
+ * @endcode
+ *
+ * @param config Pointer to the configuration structure.
+ */
+void XRDC2_GetPeriphAccessDefaultConfig(xrdc2_periph_access_config_t *config);
+
+/*!
+ * @brief Sets the peripheral access policy.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph Which peripheral descriptor to set.
+ * @param config Pointer to the access policy configuration structure.
+ */
+void XRDC2_SetPeriphAccessConfig(XRDC2_Type *base, xrdc2_periph_t periph, const xrdc2_periph_access_config_t *config);
+
+/*!
+ * @brief Sets the peripheral descriptor as valid or invalid.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph Which peripheral descriptor to set.
+ * @param valid True to set valid, false to set invalid.
+ */
+void XRDC2_SetPeriphAccessValid(XRDC2_Type *base, xrdc2_periph_t periph, bool valid);
+
+/*!
+ * @brief Sets the peripheral descriptor lock mode.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph Which peripheral descriptor to set.
+ * @param lockMode The lock mode to set.
+ */
+void XRDC2_SetPeriphAccessLockMode(XRDC2_Type *base, xrdc2_periph_t periph, xrdc2_access_config_lock_t lockMode);
+
+/*!
+ * @brief Sets the peripheral access policy for specific domain.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ * @param domainId The ID of the domain whose policy will be changed.
+ * @param policy The access policy to set.
+ */
+void XRDC2_SetPeriphDomainAccessPolicy(XRDC2_Type *base,
+ xrdc2_periph_t periph,
+ uint8_t domainId,
+ xrdc2_access_policy_t policy);
+
+/*!
+ * @brief Disable the peripheral exclusive access lock.
+ *
+ * Once disabled, it could not be enabled until reset.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ * @param enable True to enable, false to disable.
+ */
+void XRDC2_EnablePeriphExclAccessLock(XRDC2_Type *base, xrdc2_periph_t periph, bool enable);
+
+/*!
+ * @brief Get current peripheral exclusive access lock owner.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ * @return The domain ID of the lock owner.
+ */
+uint8_t XRDC2_GetPeriphExclAccessLockDomainOwner(XRDC2_Type *base, xrdc2_periph_t periph);
+
+/*!
+ * @brief Try to lock the peripheral exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ * @retval kStatus_Fail Failed to lock.
+ * @retval kStatus_Success Locked succussfully.
+ */
+status_t XRDC2_TryLockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph);
+
+/*!
+ * @brief Lock the peripheral exclusive access using blocking method.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ *
+ * @note This function must be called when the lock is not disabled.
+ */
+void XRDC2_LockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph);
+
+/*!
+ * @brief Unlock the peripheral exclusive access.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ *
+ * @note This function must be called by the lock owner.
+ */
+void XRDC2_UnlockPeriphExclAccess(XRDC2_Type *base, xrdc2_periph_t periph);
+
+/*!
+ * @brief Force the peripheral exclusive access lock release.
+ *
+ * The master does not own the lock could call this function to force release the lock.
+ *
+ * @param base XRDC2 peripheral base address.
+ * @param periph The peripheral to operate.
+ */
+void XRDC2_ForcePeriphExclAccessLockRelease(XRDC2_Type *base, xrdc2_periph_t periph);
+
+/*@}*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* _FSL_XRDC2_H_ */