diff options
author | Christian Mauderer <christian.mauderer@embedded-brains.de> | 2020-10-12 13:40:30 +0200 |
---|---|---|
committer | Christian Mauderer <christian.mauderer@embedded-brains.de> | 2020-11-20 08:53:18 +0100 |
commit | 48f6a6c302a3e1a3f8915e2503d0fe618d1af285 (patch) | |
tree | b5d570ddd5e432519c5a9d42b4cf6725d8161551 /bsps/arm/imxrt/nxp | |
parent | b169095c7dfd106a9c0c3d47e9f1c640ac3377d2 (diff) | |
download | rtems-48f6a6c302a3e1a3f8915e2503d0fe618d1af285.tar.bz2 |
bsp/imxrt: Import files from MCUXpresso SDK V2.8.5
The following files have been imported:
cp ${SDK}/boards/evkbimxrt1050/project_template/clock_config.c nxp/boards/evkbimxrt1050
cp ${SDK}/boards/evkbimxrt1050/project_template/clock_config.h include/fsl_clock_config.h
cp ${SDK}/boards/evkbimxrt1050/project_template/dcd.c start/flash-dcd.c
cp ${SDK}/boards/evkbimxrt1050/project_template/pin_mux.c nxp/boards/evkbimxrt1050
cp ${SDK}/boards/evkbimxrt1050/project_template/pin_mux.h include/fsl_pin_mux.h
cp ${SDK}/boards/evkbimxrt1050/xip/evkbimxrt1050_flexspi_nor_config.h include/fsl_flexspi_nor_config.h
cp ${SDK}/devices/MIMXRT1052/MIMXRT1052.h include
cp ${SDK}/devices/MIMXRT1052/MIMXRT1052_features.h include
cp ${SDK}/devices/MIMXRT1052/drivers/fsl_*.c nxp/devices/MIMXRT1052/drivers
cp ${SDK}/devices/MIMXRT1052/drivers/fsl_*.h include
cp ${SDK}/devices/MIMXRT1052/fsl_device_registers.h include
cp ${SDK}/devices/MIMXRT1052/system_MIMXRT1052.h include/
cp ${SDK}/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c
cp ${SDK}/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.h include
Update #4180
Diffstat (limited to 'bsps/arm/imxrt/nxp')
69 files changed, 55900 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c new file mode 100644 index 0000000000..2ed6638cbe --- /dev/null +++ b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c @@ -0,0 +1,471 @@ +/* + * Copyright 2017-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * How to setup clock using clock driver functions: + * + * 1. Call CLOCK_InitXXXPLL() to configure corresponding PLL clock. + * + * 2. Call CLOCK_InitXXXpfd() to configure corresponding PLL pfd clock. + * + * 3. Call CLOCK_SetMux() to configure corresponding clock source for target clock out. + * + * 4. Call CLOCK_SetDiv() to configure corresponding clock divider for target clock out. + * + * 5. Call CLOCK_SetXtalFreq() to set XTAL frequency based on board settings. + * + */ + +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Clocks v5.0 +processor: MIMXRT1052xxxxB +package_id: MIMXRT1052DVL6B +mcu_data: ksdk2_0 +processor_version: 0.0.0 +board: IMXRT1050-EVKB + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ + +#include "clock_config.h" +#include "fsl_iomuxc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* System clock frequency. */ +extern uint32_t SystemCoreClock; + +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ +void BOARD_InitBootClocks(void) +{ + BOARD_BootClockRUN(); +} + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockRUN +called_from_default_init: true +outputs: +- {id: AHB_CLK_ROOT.outFreq, value: 600 MHz} +- {id: CAN_CLK_ROOT.outFreq, value: 40 MHz} +- {id: CKIL_SYNC_CLK_ROOT.outFreq, value: 32.768 kHz} +- {id: CLK_1M.outFreq, value: 1 MHz} +- {id: CLK_24M.outFreq, value: 24 MHz} +- {id: CSI_CLK_ROOT.outFreq, value: 12 MHz} +- {id: ENET1_TX_CLK.outFreq, value: 2.4 MHz} +- {id: ENET_125M_CLK.outFreq, value: 2.4 MHz} +- {id: ENET_25M_REF_CLK.outFreq, value: 1.2 MHz} +- {id: FLEXIO1_CLK_ROOT.outFreq, value: 30 MHz} +- {id: FLEXIO2_CLK_ROOT.outFreq, value: 30 MHz} +- {id: FLEXSPI_CLK_ROOT.outFreq, value: 160 MHz} +- {id: GPT1_ipg_clk_highfreq.outFreq, value: 75 MHz} +- {id: GPT2_ipg_clk_highfreq.outFreq, value: 75 MHz} +- {id: IPG_CLK_ROOT.outFreq, value: 150 MHz} +- {id: LCDIF_CLK_ROOT.outFreq, value: 67.5 MHz} +- {id: LPI2C_CLK_ROOT.outFreq, value: 60 MHz} +- {id: LPSPI_CLK_ROOT.outFreq, value: 105.6 MHz} +- {id: LVDS1_CLK.outFreq, value: 1.2 GHz} +- {id: MQS_MCLK.outFreq, value: 1080/17 MHz} +- {id: PERCLK_CLK_ROOT.outFreq, value: 75 MHz} +- {id: PLL7_MAIN_CLK.outFreq, value: 24 MHz} +- {id: SAI1_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK2.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK3.outFreq, value: 30 MHz} +- {id: SAI2_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI2_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI2_MCLK3.outFreq, value: 30 MHz} +- {id: SAI3_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI3_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI3_MCLK3.outFreq, value: 30 MHz} +- {id: SEMC_CLK_ROOT.outFreq, value: 75 MHz} +- {id: SPDIF0_CLK_ROOT.outFreq, value: 30 MHz} +- {id: TRACE_CLK_ROOT.outFreq, value: 352/3 MHz} +- {id: UART_CLK_ROOT.outFreq, value: 80 MHz} +- {id: USDHC1_CLK_ROOT.outFreq, value: 198 MHz} +- {id: USDHC2_CLK_ROOT.outFreq, value: 198 MHz} +settings: +- {id: CCM.AHB_PODF.scale, value: '1', locked: true} +- {id: CCM.ARM_PODF.scale, value: '2', locked: true} +- {id: CCM.FLEXSPI_PODF.scale, value: '3', locked: true} +- {id: CCM.FLEXSPI_SEL.sel, value: CCM.PLL3_SW_CLK_SEL} +- {id: CCM.LPSPI_PODF.scale, value: '5', locked: true} +- {id: CCM.PERCLK_PODF.scale, value: '2', locked: true} +- {id: CCM.SEMC_PODF.scale, value: '8'} +- {id: CCM.TRACE_PODF.scale, value: '3', locked: true} +- {id: CCM_ANALOG.PLL1_BYPASS.sel, value: CCM_ANALOG.PLL1} +- {id: CCM_ANALOG.PLL1_PREDIV.scale, value: '1', locked: true} +- {id: CCM_ANALOG.PLL1_VDIV.scale, value: '50', locked: true} +- {id: CCM_ANALOG.PLL2.denom, value: '1', locked: true} +- {id: CCM_ANALOG.PLL2.num, value: '0', locked: true} +- {id: CCM_ANALOG.PLL2_BYPASS.sel, value: CCM_ANALOG.PLL2_OUT_CLK} +- {id: CCM_ANALOG.PLL2_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD0} +- {id: CCM_ANALOG.PLL2_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD1} +- {id: CCM_ANALOG.PLL2_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD2} +- {id: CCM_ANALOG.PLL2_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD3} +- {id: CCM_ANALOG.PLL3_BYPASS.sel, value: CCM_ANALOG.PLL3} +- {id: CCM_ANALOG.PLL3_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD0} +- {id: CCM_ANALOG.PLL3_PFD0_DIV.scale, value: '33', locked: true} +- {id: CCM_ANALOG.PLL3_PFD0_MUL.scale, value: '18', locked: true} +- {id: CCM_ANALOG.PLL3_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD1} +- {id: CCM_ANALOG.PLL3_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD2} +- {id: CCM_ANALOG.PLL3_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD3} +- {id: CCM_ANALOG.PLL4.denom, value: '50'} +- {id: CCM_ANALOG.PLL4.div, value: '47'} +- {id: CCM_ANALOG.PLL5.denom, value: '1'} +- {id: CCM_ANALOG.PLL5.div, value: '40'} +- {id: CCM_ANALOG.PLL5.num, value: '0'} +- {id: CCM_ANALOG_PLL_ENET_POWERDOWN_CFG, value: 'Yes'} +- {id: CCM_ANALOG_PLL_USB1_POWER_CFG, value: 'Yes'} +sources: +- {id: XTALOSC24M.OSC.outFreq, value: 24 MHz, enabled: true} +- {id: XTALOSC24M.RTC_OSC.outFreq, value: 32.768 kHz, enabled: true} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ + +/******************************************************************************* + * Variables for BOARD_BootClockRUN configuration + ******************************************************************************/ +const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN = { + .loopDivider = 100, /* PLL loop divider, Fout = Fin * 50 */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ +}; +const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN = { + .loopDivider = 1, /* PLL loop divider, Fout = Fin * ( 20 + loopDivider*2 + numerator / denominator ) */ + .numerator = 0, /* 30 bit numerator of fractional loop divider */ + .denominator = 1, /* 30 bit denominator of fractional loop divider */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ +}; +const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN = { + .loopDivider = 0, /* PLL loop divider, Fout = Fin * 20 */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ +}; +/******************************************************************************* + * Code for BOARD_BootClockRUN configuration + ******************************************************************************/ +void BOARD_BootClockRUN(void) +{ + /* Init RTC OSC clock frequency. */ + CLOCK_SetRtcXtalFreq(32768U); + /* Enable 1MHz clock output. */ + XTALOSC24M->OSC_CONFIG2 |= XTALOSC24M_OSC_CONFIG2_ENABLE_1M_MASK; + /* Use free 1MHz clock output. */ + XTALOSC24M->OSC_CONFIG2 &= ~XTALOSC24M_OSC_CONFIG2_MUX_1M_MASK; + /* Set XTAL 24MHz clock frequency. */ + CLOCK_SetXtalFreq(24000000U); + /* Enable XTAL 24MHz clock source. */ + CLOCK_InitExternalClk(0); + /* Enable internal RC. */ + CLOCK_InitRcOsc24M(); + /* Switch clock source to external OSC. */ + CLOCK_SwitchOsc(kCLOCK_XtalOsc); + /* Set Oscillator ready counter value. */ + CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(127); + /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialed */ + CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1); /* Set PERIPH_CLK2 MUX to OSC */ + CLOCK_SetMux(kCLOCK_PeriphMux, 1); /* Set PERIPH_CLK MUX to PERIPH_CLK2 */ + /* Setting the VDD_SOC to 1.275V. It is necessary to config AHB to 600Mhz. */ + DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(0x13); + /* Waiting for DCDC_STS_DC_OK bit is asserted */ + while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0)) + { + } + /* Set AHB_PODF. */ + CLOCK_SetDiv(kCLOCK_AhbDiv, 0); + /* Disable IPG clock gate. */ + CLOCK_DisableClock(kCLOCK_Adc1); + CLOCK_DisableClock(kCLOCK_Adc2); + CLOCK_DisableClock(kCLOCK_Xbar1); + CLOCK_DisableClock(kCLOCK_Xbar2); + CLOCK_DisableClock(kCLOCK_Xbar3); + /* Set IPG_PODF. */ + CLOCK_SetDiv(kCLOCK_IpgDiv, 3); + /* Set ARM_PODF. */ + CLOCK_SetDiv(kCLOCK_ArmDiv, 1); + /* Set PERIPH_CLK2_PODF. */ + CLOCK_SetDiv(kCLOCK_PeriphClk2Div, 0); + /* Disable PERCLK clock gate. */ + CLOCK_DisableClock(kCLOCK_Gpt1); + CLOCK_DisableClock(kCLOCK_Gpt1S); + CLOCK_DisableClock(kCLOCK_Gpt2); + CLOCK_DisableClock(kCLOCK_Gpt2S); + CLOCK_DisableClock(kCLOCK_Pit); + /* Set PERCLK_PODF. */ + CLOCK_SetDiv(kCLOCK_PerclkDiv, 1); + /* Disable USDHC1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Usdhc1); + /* Set USDHC1_PODF. */ + CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1); + /* Set Usdhc1 clock source. */ + CLOCK_SetMux(kCLOCK_Usdhc1Mux, 0); + /* Disable USDHC2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Usdhc2); + /* Set USDHC2_PODF. */ + CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1); + /* Set Usdhc2 clock source. */ + CLOCK_SetMux(kCLOCK_Usdhc2Mux, 0); +/* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd. + * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left + * unchanged. + * Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as well.*/ +#ifndef SKIP_SYSCLK_INIT + /* Disable Semc clock gate. */ + CLOCK_DisableClock(kCLOCK_Semc); + /* Set SEMC_PODF. */ + CLOCK_SetDiv(kCLOCK_SemcDiv, 7); + /* Set Semc alt clock source. */ + CLOCK_SetMux(kCLOCK_SemcAltMux, 0); + /* Set Semc clock source. */ + CLOCK_SetMux(kCLOCK_SemcMux, 0); +#endif +/* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd. + * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left + * unchanged. + * Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as well.*/ +#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)) + /* Disable Flexspi clock gate. */ + CLOCK_DisableClock(kCLOCK_FlexSpi); + /* Set FLEXSPI_PODF. */ + CLOCK_SetDiv(kCLOCK_FlexspiDiv, 2); + /* Set Flexspi clock source. */ + CLOCK_SetMux(kCLOCK_FlexspiMux, 1); +#endif + /* Disable CSI clock gate. */ + CLOCK_DisableClock(kCLOCK_Csi); + /* Set CSI_PODF. */ + CLOCK_SetDiv(kCLOCK_CsiDiv, 1); + /* Set Csi clock source. */ + CLOCK_SetMux(kCLOCK_CsiMux, 0); + /* Disable LPSPI clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpspi1); + CLOCK_DisableClock(kCLOCK_Lpspi2); + CLOCK_DisableClock(kCLOCK_Lpspi3); + CLOCK_DisableClock(kCLOCK_Lpspi4); + /* Set LPSPI_PODF. */ + CLOCK_SetDiv(kCLOCK_LpspiDiv, 4); + /* Set Lpspi clock source. */ + CLOCK_SetMux(kCLOCK_LpspiMux, 2); + /* Disable TRACE clock gate. */ + CLOCK_DisableClock(kCLOCK_Trace); + /* Set TRACE_PODF. */ + CLOCK_SetDiv(kCLOCK_TraceDiv, 2); + /* Set Trace clock source. */ + CLOCK_SetMux(kCLOCK_TraceMux, 2); + /* Disable SAI1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai1); + /* Set SAI1_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3); + /* Set SAI1_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai1Div, 1); + /* Set Sai1 clock source. */ + CLOCK_SetMux(kCLOCK_Sai1Mux, 0); + /* Disable SAI2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai2); + /* Set SAI2_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3); + /* Set SAI2_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai2Div, 1); + /* Set Sai2 clock source. */ + CLOCK_SetMux(kCLOCK_Sai2Mux, 0); + /* Disable SAI3 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai3); + /* Set SAI3_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai3PreDiv, 3); + /* Set SAI3_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai3Div, 1); + /* Set Sai3 clock source. */ + CLOCK_SetMux(kCLOCK_Sai3Mux, 0); + /* Disable Lpi2c clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpi2c1); + CLOCK_DisableClock(kCLOCK_Lpi2c2); + CLOCK_DisableClock(kCLOCK_Lpi2c3); + /* Set LPI2C_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 0); + /* Set Lpi2c clock source. */ + CLOCK_SetMux(kCLOCK_Lpi2cMux, 0); + /* Disable CAN clock gate. */ + CLOCK_DisableClock(kCLOCK_Can1); + CLOCK_DisableClock(kCLOCK_Can2); + CLOCK_DisableClock(kCLOCK_Can1S); + CLOCK_DisableClock(kCLOCK_Can2S); + /* Set CAN_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_CanDiv, 1); + /* Set Can clock source. */ + CLOCK_SetMux(kCLOCK_CanMux, 2); + /* Disable UART clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpuart1); + CLOCK_DisableClock(kCLOCK_Lpuart2); + CLOCK_DisableClock(kCLOCK_Lpuart3); + CLOCK_DisableClock(kCLOCK_Lpuart4); + CLOCK_DisableClock(kCLOCK_Lpuart5); + CLOCK_DisableClock(kCLOCK_Lpuart6); + CLOCK_DisableClock(kCLOCK_Lpuart7); + CLOCK_DisableClock(kCLOCK_Lpuart8); + /* Set UART_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_UartDiv, 0); + /* Set Uart clock source. */ + CLOCK_SetMux(kCLOCK_UartMux, 0); + /* Disable LCDIF clock gate. */ + CLOCK_DisableClock(kCLOCK_LcdPixel); + /* Set LCDIF_PRED. */ + CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 1); + /* Set LCDIF_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_LcdifDiv, 3); + /* Set Lcdif pre clock source. */ + CLOCK_SetMux(kCLOCK_LcdifPreMux, 5); + /* Disable SPDIF clock gate. */ + CLOCK_DisableClock(kCLOCK_Spdif); + /* Set SPDIF0_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Spdif0PreDiv, 1); + /* Set SPDIF0_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Spdif0Div, 7); + /* Set Spdif clock source. */ + CLOCK_SetMux(kCLOCK_SpdifMux, 3); + /* Disable Flexio1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Flexio1); + /* Set FLEXIO1_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, 1); + /* Set FLEXIO1_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Flexio1Div, 7); + /* Set Flexio1 clock source. */ + CLOCK_SetMux(kCLOCK_Flexio1Mux, 3); + /* Disable Flexio2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Flexio2); + /* Set FLEXIO2_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Flexio2PreDiv, 1); + /* Set FLEXIO2_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Flexio2Div, 7); + /* Set Flexio2 clock source. */ + CLOCK_SetMux(kCLOCK_Flexio2Mux, 3); + /* Set Pll3 sw clock source. */ + CLOCK_SetMux(kCLOCK_Pll3SwMux, 0); + /* Init ARM PLL. */ + CLOCK_InitArmPll(&armPllConfig_BOARD_BootClockRUN); + /* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd. + * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left + * unchanged. Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as + * well.*/ +#ifndef SKIP_SYSCLK_INIT + /* Init System PLL. */ + CLOCK_InitSysPll(&sysPllConfig_BOARD_BootClockRUN); + /* Init System pfd0. */ + CLOCK_InitSysPfd(kCLOCK_Pfd0, 27); + /* Init System pfd1. */ + CLOCK_InitSysPfd(kCLOCK_Pfd1, 16); + /* Init System pfd2. */ + CLOCK_InitSysPfd(kCLOCK_Pfd2, 24); + /* Init System pfd3. */ + CLOCK_InitSysPfd(kCLOCK_Pfd3, 16); + /* Disable pfd offset. */ + CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_PFD_OFFSET_EN_MASK; +#endif + /* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd. + * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left + * unchanged. Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as + * well.*/ +#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)) + /* Init Usb1 PLL. */ + CLOCK_InitUsb1Pll(&usb1PllConfig_BOARD_BootClockRUN); + /* Init Usb1 pfd0. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 33); + /* Init Usb1 pfd1. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, 16); + /* Init Usb1 pfd2. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, 17); + /* Init Usb1 pfd3. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, 19); + /* Disable Usb1 PLL output for USBPHY1. */ + CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK; +#endif + /* DeInit Audio PLL. */ + CLOCK_DeinitAudioPll(); + /* Bypass Audio PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1); + /* Set divider for Audio PLL. */ + CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; + CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK; + /* Enable Audio PLL output. */ + CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK; + /* DeInit Video PLL. */ + CLOCK_DeinitVideoPll(); + /* Bypass Video PLL. */ + CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; + /* Set divider for Video PLL. */ + CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & (~CCM_ANALOG_MISC2_VIDEO_DIV_MASK)) | CCM_ANALOG_MISC2_VIDEO_DIV(0); + /* Enable Video PLL output. */ + CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_ENABLE_MASK; + /* DeInit Enet PLL. */ + CLOCK_DeinitEnetPll(); + /* Bypass Enet PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllEnet, 1); + /* Set Enet output divider. */ + CCM_ANALOG->PLL_ENET = + (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK)) | CCM_ANALOG_PLL_ENET_DIV_SELECT(1); + /* Enable Enet output. */ + CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENABLE_MASK; + /* Enable Enet25M output. */ + CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK; + /* DeInit Usb2 PLL. */ + CLOCK_DeinitUsb2Pll(); + /* Bypass Usb2 PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllUsb2, 1); + /* Enable Usb2 PLL output. */ + CCM_ANALOG->PLL_USB2 |= CCM_ANALOG_PLL_USB2_ENABLE_MASK; + /* Set preperiph clock source. */ + CLOCK_SetMux(kCLOCK_PrePeriphMux, 3); + /* Set periph clock source. */ + CLOCK_SetMux(kCLOCK_PeriphMux, 0); + /* Set periph clock2 clock source. */ + CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 0); + /* Set per clock source. */ + CLOCK_SetMux(kCLOCK_PerclkMux, 0); + /* Set lvds1 clock source. */ + CCM_ANALOG->MISC1 = + (CCM_ANALOG->MISC1 & (~CCM_ANALOG_MISC1_LVDS1_CLK_SEL_MASK)) | CCM_ANALOG_MISC1_LVDS1_CLK_SEL(0); + /* Set clock out1 divider. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_DIV_MASK)) | CCM_CCOSR_CLKO1_DIV(0); + /* Set clock out1 source. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_SEL_MASK)) | CCM_CCOSR_CLKO1_SEL(1); + /* Set clock out2 divider. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_DIV_MASK)) | CCM_CCOSR_CLKO2_DIV(0); + /* Set clock out2 source. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_SEL_MASK)) | CCM_CCOSR_CLKO2_SEL(18); + /* Set clock out1 drives clock out1. */ + CCM->CCOSR &= ~CCM_CCOSR_CLK_OUT_SEL_MASK; + /* Disable clock out1. */ + CCM->CCOSR &= ~CCM_CCOSR_CLKO1_EN_MASK; + /* Disable clock out2. */ + CCM->CCOSR &= ~CCM_CCOSR_CLKO2_EN_MASK; + /* Set SAI1 MCLK1 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk1Sel, 0); + /* Set SAI1 MCLK2 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk2Sel, 0); + /* Set SAI1 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk3Sel, 0); + /* Set SAI2 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI2MClk3Sel, 0); + /* Set SAI3 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI3MClk3Sel, 0); + /* Set MQS configuration. */ + IOMUXC_MQSConfig(IOMUXC_GPR, kIOMUXC_MqsPwmOverSampleRate32, 0); + /* Set ENET Tx clock source. */ + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); + /* Set GPT1 High frequency reference clock source. */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_MASK; + /* Set GPT2 High frequency reference clock source. */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK; + /* Set SystemCoreClock variable. */ + SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK; +} diff --git a/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c new file mode 100644 index 0000000000..8e3021afcb --- /dev/null +++ b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c @@ -0,0 +1,1094 @@ +/* + * Copyright 2018 NXP. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Pins v4.1 +processor: MIMXRT1052xxxxB +package_id: MIMXRT1052DVL6B +mcu_data: ksdk2_0 +processor_version: 4.0.0 +board: IMXRT1050-EVKB +pin_labels: +- {pin_num: E3, pin_signal: GPIO_EMC_00, label: SEMC_D0, identifier: SEMC_D0} +- {pin_num: F3, pin_signal: GPIO_EMC_01, label: SEMC_D1, identifier: SEMC_D1} +- {pin_num: F4, pin_signal: GPIO_EMC_02, label: SEMC_D2, identifier: SEMC_D2} +- {pin_num: F2, pin_signal: GPIO_EMC_04, label: SEMC_D4, identifier: SEMC_D4} +- {pin_num: G4, pin_signal: GPIO_EMC_03, label: SEMC_D3, identifier: SEMC_D3} +- {pin_num: G5, pin_signal: GPIO_EMC_05, label: SEMC_D5, identifier: SEMC_D5} +- {pin_num: H5, pin_signal: GPIO_EMC_06, label: SEMC_D6, identifier: SEMC_D6} +- {pin_num: H4, pin_signal: GPIO_EMC_07, label: SEMC_D7, identifier: SEMC_D7} +- {pin_num: H3, pin_signal: GPIO_EMC_08, label: SEMC_DM0, identifier: SEMC_DM0} +- {pin_num: C2, pin_signal: GPIO_EMC_09, label: SEMC_A0, identifier: SEMC_A0} +- {pin_num: G1, pin_signal: GPIO_EMC_10, label: SEMC_A1, identifier: SEMC_A1} +- {pin_num: G3, pin_signal: GPIO_EMC_11, label: SEMC_A2, identifier: SEMC_A2} +- {pin_num: H1, pin_signal: GPIO_EMC_12, label: SEMC_A3, identifier: SEMC_A3} +- {pin_num: A6, pin_signal: GPIO_EMC_13, label: SEMC_A4, identifier: SEMC_A4} +- {pin_num: B6, pin_signal: GPIO_EMC_14, label: SEMC_A5, identifier: SEMC_A5} +- {pin_num: B1, pin_signal: GPIO_EMC_15, label: SEMC_A6, identifier: SEMC_A6} +- {pin_num: A5, pin_signal: GPIO_EMC_16, label: SEMC_A7, identifier: SEMC_A7} +- {pin_num: A4, pin_signal: GPIO_EMC_17, label: SEMC_A8, identifier: SEMC_A8} +- {pin_num: B2, pin_signal: GPIO_EMC_18, label: SEMC_A9, identifier: SEMC_A9} +- {pin_num: B4, pin_signal: GPIO_EMC_19, label: SEMC_A11, identifier: SEMC_A11} +- {pin_num: G2, pin_signal: GPIO_EMC_23, label: SEMC_A10, identifier: SEMC_A10} +- {pin_num: A3, pin_signal: GPIO_EMC_20, label: SEMC_A12, identifier: SEMC_A12} +- {pin_num: C1, pin_signal: GPIO_EMC_21, label: SEMC_BA0, identifier: SEMC_BA0} +- {pin_num: F1, pin_signal: GPIO_EMC_22, label: SEMC_BA1, identifier: SEMC_BA1} +- {pin_num: D3, pin_signal: GPIO_EMC_24, label: SEMC_CAS, identifier: SEMC_CAS} +- {pin_num: D2, pin_signal: GPIO_EMC_25, label: SEMC_RAS, identifier: SEMC_RAS} +- {pin_num: B3, pin_signal: GPIO_EMC_26, label: SEMC_CLK, identifier: SEMC_CLK} +- {pin_num: A2, pin_signal: GPIO_EMC_27, label: SEMC_CKE, identifier: SEMC_CKE} +- {pin_num: D1, pin_signal: GPIO_EMC_28, label: SEMC_WE, identifier: SEMC_WE} +- {pin_num: E1, pin_signal: GPIO_EMC_29, label: SEMC_CS0, identifier: SEMC_CS0} +- {pin_num: C6, pin_signal: GPIO_EMC_30, label: SEMC_D8, identifier: SEMC_D8} +- {pin_num: C5, pin_signal: GPIO_EMC_31, label: SEMC_D9, identifier: SEMC_D9} +- {pin_num: D5, pin_signal: GPIO_EMC_32, label: SEMC_D10, identifier: SEMC_D10} +- {pin_num: C4, pin_signal: GPIO_EMC_33, label: SEMC_D11, identifier: SEMC_D11} +- {pin_num: D4, pin_signal: GPIO_EMC_34, label: SEMC_D12, identifier: SEMC_D12} +- {pin_num: E5, pin_signal: GPIO_EMC_35, label: SEMC_D13, identifier: SEMC_D13} +- {pin_num: C3, pin_signal: GPIO_EMC_36, label: SEMC_D14, identifier: SEMC_D14} +- {pin_num: E4, pin_signal: GPIO_EMC_37, label: SEMC_D15, identifier: SEMC_D15} +- {pin_num: D6, pin_signal: GPIO_EMC_38, label: SEMC_DM1, identifier: SEMC_DM1} +- {pin_num: B7, pin_signal: GPIO_EMC_39, label: SEMC_DQS, identifier: SEMC_DQS} +- {pin_num: A7, pin_signal: GPIO_EMC_40, label: ENET_MDC, identifier: ENET_MDC} +- {pin_num: C7, pin_signal: GPIO_EMC_41, label: ENET_MDIO, identifier: ENET_MDIO} +- {pin_num: D7, pin_signal: GPIO_B0_00, label: LCDIF_CLK, identifier: LCDIF_CLK} +- {pin_num: E7, pin_signal: GPIO_B0_01, label: LCDIF_ENABLE, identifier: LCDIF_ENABLE} +- {pin_num: E8, pin_signal: GPIO_B0_02, label: LCDIF_HSYNC, identifier: LCDIF_HSYNC} +- {pin_num: D8, pin_signal: GPIO_B0_03, label: LCDIF_VSYNC, identifier: LCDIF_VSYNC} +- {pin_num: C8, pin_signal: GPIO_B0_04, label: 'LCDIF_D0/BT_CFG[0]', identifier: LCDIF_D0} +- {pin_num: B8, pin_signal: GPIO_B0_05, label: 'LCDIF_D1/BT_CFG[1]', identifier: LCDIF_D1} +- {pin_num: A8, pin_signal: GPIO_B0_06, label: 'LCDIF_D2/BT_CFG[2]', identifier: LCDIF_D2} +- {pin_num: A9, pin_signal: GPIO_B0_07, label: 'LCDIF_D3/BT_CFG[3]', identifier: LCDIF_D3} +- {pin_num: B9, pin_signal: GPIO_B0_08, label: 'LCDIF_D4/BT_CFG[4]', identifier: LCDIF_D4} +- {pin_num: C9, pin_signal: GPIO_B0_09, label: 'LCDIF_D5/BT_CFG[5]', identifier: LCDIF_D5} +- {pin_num: D9, pin_signal: GPIO_B0_10, label: 'LCDIF_D6/BT_CFG[6]', identifier: LCDIF_D6} +- {pin_num: A10, pin_signal: GPIO_B0_11, label: 'LCDIF_D7/BT_CFG[7]', identifier: LCDIF_D7} +- {pin_num: C10, pin_signal: GPIO_B0_12, label: 'LCDIF_D8/BT_CFG[8]', identifier: LCDIF_D8} +- {pin_num: D10, pin_signal: GPIO_B0_13, label: 'LCDIF_D9/BT_CFG[9]', identifier: LCDIF_D9} +- {pin_num: E10, pin_signal: GPIO_B0_14, label: 'LCDIF_D10/BT_CFG[10]', identifier: LCDIF_D10} +- {pin_num: E11, pin_signal: GPIO_B0_15, label: 'LCDIF_D11/BT_CFG[11]', identifier: LCDIF_D11} +- {pin_num: A11, pin_signal: GPIO_B1_00, label: LCDIF_D12, identifier: LCDIF_D12} +- {pin_num: B11, pin_signal: GPIO_B1_01, label: LCDIF_D13, identifier: LCDIF_D13} +- {pin_num: C11, pin_signal: GPIO_B1_02, label: LCDIF_D14, identifier: LCDIF_D14} +- {pin_num: D11, pin_signal: GPIO_B1_03, label: LCDIF_D15, identifier: LCDIF_D15} +- {pin_num: E12, pin_signal: GPIO_B1_04, label: ENET_RXD0, identifier: ENET_RXD0} +- {pin_num: D12, pin_signal: GPIO_B1_05, label: ENET_RXD1, identifier: ENET_RXD1} +- {pin_num: C12, pin_signal: GPIO_B1_06, label: ENET_CRS_DV, identifier: ENET_CRS_DV} +- {pin_num: B12, pin_signal: GPIO_B1_07, label: ENET_TXD0, identifier: ENET_TXD0} +- {pin_num: A12, pin_signal: GPIO_B1_08, label: ENET_TXD1, identifier: ENET_TXD1} +- {pin_num: A13, pin_signal: GPIO_B1_09, label: ENET_TXEN, identifier: ENET_TXEN} +- {pin_num: B13, pin_signal: GPIO_B1_10, label: ENET_TX_CLK, identifier: ENET_TX_CLK} +- {pin_num: C13, pin_signal: GPIO_B1_11, label: ENET_RXER, identifier: ENET_RXER} +- {pin_num: D13, pin_signal: GPIO_B1_12, label: SD_CD_SW, identifier: SD_CD_SW} +- {pin_num: D14, pin_signal: GPIO_B1_13, label: WDOG_B, identifier: WDOG_B} +- {pin_num: C14, pin_signal: GPIO_B1_14, label: SD0_VSELECT, identifier: SD0_VSELECT} +- {pin_num: B14, pin_signal: GPIO_B1_15, label: USB_HOST_PWR/BACKLIGHT_CTL, identifier: BACKLIGHT_CTL} +- {pin_num: E9, pin_signal: NVCC_GPIO0, label: DCDC_3V3/NVCC_GPIO_3V3} +- {pin_num: F10, pin_signal: NVCC_GPIO1, label: DCDC_3V3/NVCC_GPIO_3V3} +- {pin_num: J10, pin_signal: NVCC_GPIO2, label: DCDC_3V3/NVCC_GPIO_3V3} +- {pin_num: M14, pin_signal: GPIO_AD_B0_00, label: 'USB_HOST_OC/J24[10]'} +- {pin_num: H10, pin_signal: GPIO_AD_B0_01, label: 'USB_OTG1_ID/J24[9]'} +- {pin_num: M11, pin_signal: GPIO_AD_B0_02, label: 'USB_OTG1_PWR/J24[2]'} +- {pin_num: G11, pin_signal: GPIO_AD_B0_03, label: 'USB_OTG1_OC/J24[1]'} +- {pin_num: F11, pin_signal: GPIO_AD_B0_04, label: 'CSI_PWDN/J35[17]/BOOT_MODE[0]', identifier: CSI_PWDN} +- {pin_num: G14, pin_signal: GPIO_AD_B0_05, label: 'CAN_STBY/BOOT_MODE[1]/Flash_RST/U12[8]', identifier: CAN_STBY} +- {pin_num: E14, pin_signal: GPIO_AD_B0_06, label: 'JTAG_TMS/J21[7]/SWD_DIO'} +- {pin_num: F12, pin_signal: GPIO_AD_B0_07, label: 'JTAG_TCK/J21[9]/SWD_CLK'} +- {pin_num: F13, pin_signal: GPIO_AD_B0_08, label: JTAG_MOD} +- {pin_num: F14, pin_signal: GPIO_AD_B0_09, label: 'JTAG_TDI/J21[5]/ENET_RST/J22[5]'} +- {pin_num: G13, pin_signal: GPIO_AD_B0_10, label: 'JTAG_TDO/J21[13]/INT1_COMBO/ENET_INT/J22[6]/U32[11]', identifier: INT1_COMBO} +- {pin_num: G10, pin_signal: GPIO_AD_B0_11, label: 'JTAG_nTRST/J21[3]/INT2_COMBO/LCD_TOUCH_INT/J22[3]/U32[9]', identifier: INT2_COMBO} +- {pin_num: K14, pin_signal: GPIO_AD_B0_12, label: UART1_TXD, identifier: UART1_TXD} +- {pin_num: L14, pin_signal: GPIO_AD_B0_13, label: UART1_RXD, identifier: UART1_RXD} +- {pin_num: H14, pin_signal: GPIO_AD_B0_14, label: 'CAN2_TX/U12[1]', identifier: CAN2_TX} +- {pin_num: L10, pin_signal: GPIO_AD_B0_15, label: 'CAN2_RX/U12[4]', identifier: CAN2_RX} +- {pin_num: J11, pin_signal: GPIO_AD_B1_00, label: 'I2C1_SCL/CSI_I2C_SCL/J35[20]/J23[6]/U13[17]/U32[4]', identifier: I2C_SCL_FXOS8700CQ;CSI_I2C_SCL} +- {pin_num: K11, pin_signal: GPIO_AD_B1_01, label: 'I2C1_SDA/CSI_I2C_SDA/J35[22]/J23[5]/U13[18]/U32[6]', identifier: I2C_SDA_FXOS8700CQ;CSI_I2C_SDA} +- {pin_num: L11, pin_signal: GPIO_AD_B1_02, label: 'SPDIF_OUT/J22[7]', identifier: SPDIF_OUT} +- {pin_num: M12, pin_signal: GPIO_AD_B1_03, label: 'SPDIF_IN/J22[8]', identifier: SPDIF_IN} +- {pin_num: H13, pin_signal: GPIO_AD_B1_08, label: 'AUD_INT/CSI_D9//J35[13]/J22[4]', identifier: CSI_D9} +- {pin_num: M13, pin_signal: GPIO_AD_B1_09, label: 'SAI1_MCLK/CSI_D8/J35[11]', identifier: CSI_D8} +- {pin_num: L13, pin_signal: GPIO_AD_B1_10, label: 'SAI1_RX_SYNC/CSI_D7/J35[9]/J23[1]', identifier: CSI_D7} +- {pin_num: J13, pin_signal: GPIO_AD_B1_11, label: 'SAI1_RX_BCLK/CSI_D6/J35[7]/J23[2]', identifier: CSI_D6} +- {pin_num: H12, pin_signal: GPIO_AD_B1_12, label: 'SAI1_RXD/CSI_D5/J35[5]/U13[16]', identifier: CSI_D5} +- {pin_num: H11, pin_signal: GPIO_AD_B1_13, label: 'SAI1_TXD/CSI_D4/J35[3]/U13[14]', identifier: CSI_D4} +- {pin_num: G12, pin_signal: GPIO_AD_B1_14, label: 'SAI1_TX_BCLK/CSI_D3/J35[4]/U13[12]', identifier: CSI_D3} +- {pin_num: J14, pin_signal: GPIO_AD_B1_15, label: 'SAI1_TX_SYNC/CSI_D2/J35[6]/U13[13]', identifier: CSI_D2} +- {pin_num: J4, pin_signal: GPIO_SD_B0_00, label: 'SD1_CMD/J24[6]', identifier: SD1_CMD} +- {pin_num: J3, pin_signal: GPIO_SD_B0_01, label: 'SD1_CLK/J24[3]', identifier: SD1_CLK} +- {pin_num: J1, pin_signal: GPIO_SD_B0_02, label: 'SD1_D0/J24[4]/SPI_MOSI/PWM', identifier: SD1_D0} +- {pin_num: K1, pin_signal: GPIO_SD_B0_03, label: 'SD1_D1/J24[5]/SPI_MISO', identifier: SD1_D1} +- {pin_num: H2, pin_signal: GPIO_SD_B0_04, label: SD1_D2, identifier: SD1_D2} +- {pin_num: J2, pin_signal: GPIO_SD_B0_05, label: SD1_D3, identifier: SD1_D3} +- {pin_num: L5, pin_signal: GPIO_SD_B1_00, label: FlexSPI_D3_B, identifier: FlexSPI_D3_B} +- {pin_num: M5, pin_signal: GPIO_SD_B1_01, label: FlexSPI_D2_B, identifier: FlexSPI_D2_B} +- {pin_num: M3, pin_signal: GPIO_SD_B1_02, label: FlexSPI_D1_B, identifier: FlexSPI_D1_B} +- {pin_num: M4, pin_signal: GPIO_SD_B1_03, label: FlexSPI_D0_B, identifier: FlexSPI_D0_B} +- {pin_num: P2, pin_signal: GPIO_SD_B1_04, label: FlexSPI_CLK_B, identifier: FlexSPI_CLK_B} +- {pin_num: N3, pin_signal: GPIO_SD_B1_05, label: FlexSPI_DQS, identifier: FlexSPI_DQS} +- {pin_num: L3, pin_signal: GPIO_SD_B1_06, label: FlexSPI_SS0, identifier: FlexSPI_SS0} +- {pin_num: L4, pin_signal: GPIO_SD_B1_07, label: FlexSPI_CLK, identifier: FlexSPI_CLK} +- {pin_num: P3, pin_signal: GPIO_SD_B1_08, label: FlexSPI_D0_A, identifier: FlexSPI_D0_A} +- {pin_num: N4, pin_signal: GPIO_SD_B1_09, label: FlexSPI_D1_A, identifier: FlexSPI_D1_A} +- {pin_num: P4, pin_signal: GPIO_SD_B1_10, label: FlexSPI_D2_A, identifier: FlexSPI_D2_A} +- {pin_num: P5, pin_signal: GPIO_SD_B1_11, label: FlexSPI_D3_A, identifier: FlexSPI_D3_A} +- {pin_num: M8, pin_signal: USB_OTG1_DN, label: OTG1_DN, identifier: OTG1_DN} +- {pin_num: L8, pin_signal: USB_OTG1_DP, label: OTG1_DP, identifier: OTG1_DP} +- {pin_num: N7, pin_signal: USB_OTG2_DN, label: OTG2_DN, identifier: OTG2_DN} +- {pin_num: P7, pin_signal: USB_OTG2_DP, label: OTG2_DP, identifier: OTG2_DP} +- {pin_num: K8, pin_signal: VDD_USB_CAP, label: VDD_USB_3V} +- {pin_num: N6, pin_signal: USB_OTG1_VBUS, label: 5V_USB_OTG} +- {pin_num: P6, pin_signal: USB_OTG2_VBUS, label: 5V_USB_HS} +- {pin_num: L12, pin_signal: GPIO_AD_B1_04, label: 'CSI_PIXCLK/J35[8]/J23[3]', identifier: CSI_PIXCLK} +- {pin_num: K12, pin_signal: GPIO_AD_B1_05, label: 'CSI_MCLK/J35[12]/J23[4]', identifier: CSI_MCLK} +- {pin_num: J12, pin_signal: GPIO_AD_B1_06, label: 'CSI_VSYNC/J35[18]/J22[2]/UART_TX', identifier: CSI_VSYNC} +- {pin_num: K10, pin_signal: GPIO_AD_B1_07, label: 'CSI_HSYNC/J35[16]/J22[1]/UART_RX', identifier: CSI_HSYNC} +- {pin_num: M7, pin_signal: POR_B, label: 'RST_TGTMCU_B/POR_B/J21[15]', identifier: RST_TGTMCU_B;POR_B} +- {pin_num: N14, pin_signal: VDDA_ADC_3P3, label: VDDA_ADC_3P3_MCU} +- {pin_num: P12, pin_signal: VDD_HIGH_IN, label: VDD_HIGH_IN_MCU} +- {pin_num: M9, pin_signal: VDD_SNVS_IN, label: VDD_SNVS_IN} +- {pin_num: F6, pin_signal: VDD_SOC_IN0, label: VDD_SOC_IN} +- {pin_num: H6, pin_signal: VDD_SOC_IN2, label: VDD_SOC_IN} +- {pin_num: G6, pin_signal: VDD_SOC_IN1, label: VDD_SOC_IN} +- {pin_num: F7, pin_signal: VDD_SOC_IN3, label: VDD_SOC_IN} +- {pin_num: F8, pin_signal: VDD_SOC_IN4, label: VDD_SOC_IN} +- {pin_num: F9, pin_signal: VDD_SOC_IN5, label: VDD_SOC_IN} +- {pin_num: G9, pin_signal: VDD_SOC_IN6, label: VDD_SOC_IN} +- {pin_num: H9, pin_signal: VDD_SOC_IN7, label: VDD_SOC_IN} +- {pin_num: J9, pin_signal: VDD_SOC_IN8, label: VDD_SOC_IN} +- {pin_num: P1, pin_signal: VSS1, label: GND} +- {pin_num: E2, pin_signal: VSS2, label: GND} +- {pin_num: K2, pin_signal: VSS3, label: GND} +- {pin_num: B5, pin_signal: VSS4, label: GND} +- {pin_num: N5, pin_signal: VSS5, label: GND} +- {pin_num: G7, pin_signal: VSS6, label: GND} +- {pin_num: H7, pin_signal: VSS7, label: GND} +- {pin_num: J7, pin_signal: VSS8, label: GND} +- {pin_num: G8, pin_signal: VSS9, label: GND} +- {pin_num: H8, pin_signal: VSS10, label: GND} +- {pin_num: J8, pin_signal: VSS11, label: GND} +- {pin_num: N8, pin_signal: VSS12, label: GND} +- {pin_num: L9, pin_signal: VSS13, label: GND} +- {pin_num: B10, pin_signal: VSS14, label: GND} +- {pin_num: E13, pin_signal: VSS15, label: GND} +- {pin_num: K13, pin_signal: VSS16, label: GND} +- {pin_num: A14, pin_signal: VSS17, label: GND} +- {pin_num: P14, pin_signal: VSS18, label: GND} +- {pin_num: A1, pin_signal: VSS0, label: GND} +- {pin_num: J6, pin_signal: NVCC_SD0, label: NVCC_SD, identifier: NVCC_SD} +- {pin_num: K5, pin_signal: NVCC_SD1, label: FLASH_VCC, identifier: FLASH_VCC} +- {pin_num: F5, pin_signal: NVCC_EMC0, label: DCDC_3V3} +- {pin_num: E6, pin_signal: NVCC_EMC1, label: DCDC_3V3} +- {pin_num: L6, pin_signal: WAKEUP, label: SD_PWREN, identifier: SD_PWREN} +- {pin_num: L1, pin_signal: DCDC_IN0, label: MCU_DCDC_IN_3V3} +- {pin_num: L2, pin_signal: DCDC_IN1, label: MCU_DCDC_IN_3V3} +- {pin_num: K4, pin_signal: DCDC_IN_Q, label: MCU_DCDC_IN_3V3} +- {pin_num: M1, pin_signal: DCDC_LP0, label: VDD_SOC_IN} +- {pin_num: M2, pin_signal: DCDC_LP1, label: VDD_SOC_IN} +- {pin_num: P11, pin_signal: XTALI, label: XTALI, identifier: XTALI} +- {pin_num: N11, pin_signal: XTALO, label: XTALO, identifier: XTALO} +- {pin_num: N9, pin_signal: RTC_XTALI, label: RTC_XTALI, identifier: RTC_XTALI} +- {pin_num: P9, pin_signal: RTC_XTALO, label: RTC_XTALO, identifier: RTC_XTALO} +- {pin_num: N1, pin_signal: DCDC_GND0, label: GND} +- {pin_num: N2, pin_signal: DCDC_GND1, label: GND} +- {pin_num: J5, pin_signal: DCDC_SENSE, label: VDD_SOC_IN} +- {pin_num: K3, pin_signal: DCDC_PSWITCH, label: MCU_DCDC_IN_3V3} +- {pin_num: K7, pin_signal: PMIC_ON_REQ, label: PMIC_ON_REQ, identifier: PMIC_ON_REQ} +- {pin_num: L7, pin_signal: PMIC_STBY_REQ, label: PERI_PWREN, identifier: PERI_PWREN} +- {pin_num: M6, pin_signal: ONOFF, label: ONOFF, identifier: ONOFF} +- {pin_num: K6, pin_signal: TEST_MODE, label: GND} +- {pin_num: P10, pin_signal: NVCC_PLL, label: VDDA_1P1_CAP} +- {pin_num: P8, pin_signal: VDD_HIGH_CAP, label: VDDA_2P5_CAP} +- {pin_num: K9, pin_signal: NGND_KEL0, label: GND} +- {pin_num: M10, pin_signal: VDD_SNVS_CAP, label: GND} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +#include "fsl_common.h" +#include "fsl_iomuxc.h" +#include "pin_mux.h" + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitBootPins + * Description : Calls initialization functions. + * + * END ****************************************************************************************************************/ +void BOARD_InitBootPins(void) { + BOARD_InitPins(); + BOARD_InitDEBUG_UARTPins(); +} + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitPins: +- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} +- pin_list: [] + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitPins(void) { +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitDEBUG_UARTPins: +- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: K14, peripheral: LPUART1, signal: TX, pin_signal: GPIO_AD_B0_12, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Down_100K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + - {pin_num: L14, peripheral: LPUART1, signal: RX, pin_signal: GPIO_AD_B0_13, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Down_100K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitDEBUG_UARTPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitDEBUG_UARTPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitSDRAMPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: C2, peripheral: SEMC, signal: 'ADDR, 00', pin_signal: GPIO_EMC_09} + - {pin_num: G1, peripheral: SEMC, signal: 'ADDR, 01', pin_signal: GPIO_EMC_10} + - {pin_num: G3, peripheral: SEMC, signal: 'ADDR, 02', pin_signal: GPIO_EMC_11} + - {pin_num: H1, peripheral: SEMC, signal: 'ADDR, 03', pin_signal: GPIO_EMC_12} + - {pin_num: A6, peripheral: SEMC, signal: 'ADDR, 04', pin_signal: GPIO_EMC_13} + - {pin_num: B6, peripheral: SEMC, signal: 'ADDR, 05', pin_signal: GPIO_EMC_14} + - {pin_num: B1, peripheral: SEMC, signal: 'ADDR, 06', pin_signal: GPIO_EMC_15} + - {pin_num: A5, peripheral: SEMC, signal: 'ADDR, 07', pin_signal: GPIO_EMC_16} + - {pin_num: A4, peripheral: SEMC, signal: 'ADDR, 08', pin_signal: GPIO_EMC_17} + - {pin_num: B2, peripheral: SEMC, signal: 'ADDR, 09', pin_signal: GPIO_EMC_18} + - {pin_num: G2, peripheral: SEMC, signal: 'ADDR, 10', pin_signal: GPIO_EMC_23} + - {pin_num: B4, peripheral: SEMC, signal: 'ADDR, 11', pin_signal: GPIO_EMC_19} + - {pin_num: A3, peripheral: SEMC, signal: 'ADDR, 12', pin_signal: GPIO_EMC_20} + - {pin_num: C1, peripheral: SEMC, signal: 'BA, 0', pin_signal: GPIO_EMC_21} + - {pin_num: F1, peripheral: SEMC, signal: 'BA, 1', pin_signal: GPIO_EMC_22} + - {pin_num: D3, peripheral: SEMC, signal: semc_cas, pin_signal: GPIO_EMC_24} + - {pin_num: A2, peripheral: SEMC, signal: semc_cke, pin_signal: GPIO_EMC_27} + - {pin_num: B3, peripheral: SEMC, signal: semc_clk, pin_signal: GPIO_EMC_26} + - {pin_num: E3, peripheral: SEMC, signal: 'DATA, 00', pin_signal: GPIO_EMC_00} + - {pin_num: F3, peripheral: SEMC, signal: 'DATA, 01', pin_signal: GPIO_EMC_01} + - {pin_num: F4, peripheral: SEMC, signal: 'DATA, 02', pin_signal: GPIO_EMC_02} + - {pin_num: G4, peripheral: SEMC, signal: 'DATA, 03', pin_signal: GPIO_EMC_03} + - {pin_num: F2, peripheral: SEMC, signal: 'DATA, 04', pin_signal: GPIO_EMC_04} + - {pin_num: G5, peripheral: SEMC, signal: 'DATA, 05', pin_signal: GPIO_EMC_05} + - {pin_num: H5, peripheral: SEMC, signal: 'DATA, 06', pin_signal: GPIO_EMC_06} + - {pin_num: H4, peripheral: SEMC, signal: 'DATA, 07', pin_signal: GPIO_EMC_07} + - {pin_num: C6, peripheral: SEMC, signal: 'DATA, 08', pin_signal: GPIO_EMC_30} + - {pin_num: C5, peripheral: SEMC, signal: 'DATA, 09', pin_signal: GPIO_EMC_31} + - {pin_num: D5, peripheral: SEMC, signal: 'DATA, 10', pin_signal: GPIO_EMC_32} + - {pin_num: C4, peripheral: SEMC, signal: 'DATA, 11', pin_signal: GPIO_EMC_33} + - {pin_num: D4, peripheral: SEMC, signal: 'DATA, 12', pin_signal: GPIO_EMC_34} + - {pin_num: E5, peripheral: SEMC, signal: 'DATA, 13', pin_signal: GPIO_EMC_35} + - {pin_num: C3, peripheral: SEMC, signal: 'DATA, 14', pin_signal: GPIO_EMC_36} + - {pin_num: E4, peripheral: SEMC, signal: 'DATA, 15', pin_signal: GPIO_EMC_37} + - {pin_num: H3, peripheral: SEMC, signal: 'DM, 0', pin_signal: GPIO_EMC_08} + - {pin_num: D6, peripheral: SEMC, signal: 'DM, 1', pin_signal: GPIO_EMC_38} + - {pin_num: D2, peripheral: SEMC, signal: semc_ras, pin_signal: GPIO_EMC_25} + - {pin_num: D1, peripheral: SEMC, signal: semc_we, pin_signal: GPIO_EMC_28} + - {pin_num: C7, peripheral: SEMC, signal: 'CSX, 0', pin_signal: GPIO_EMC_41} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitSDRAMPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitSDRAMPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_00_SEMC_DATA00, /* GPIO_EMC_00 is configured as SEMC_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_01_SEMC_DATA01, /* GPIO_EMC_01 is configured as SEMC_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_02_SEMC_DATA02, /* GPIO_EMC_02 is configured as SEMC_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_03_SEMC_DATA03, /* GPIO_EMC_03 is configured as SEMC_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_04_SEMC_DATA04, /* GPIO_EMC_04 is configured as SEMC_DATA04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_05_SEMC_DATA05, /* GPIO_EMC_05 is configured as SEMC_DATA05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_06_SEMC_DATA06, /* GPIO_EMC_06 is configured as SEMC_DATA06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_07_SEMC_DATA07, /* GPIO_EMC_07 is configured as SEMC_DATA07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_08_SEMC_DM00, /* GPIO_EMC_08 is configured as SEMC_DM00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_09_SEMC_ADDR00, /* GPIO_EMC_09 is configured as SEMC_ADDR00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_10_SEMC_ADDR01, /* GPIO_EMC_10 is configured as SEMC_ADDR01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_11_SEMC_ADDR02, /* GPIO_EMC_11 is configured as SEMC_ADDR02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_12_SEMC_ADDR03, /* GPIO_EMC_12 is configured as SEMC_ADDR03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_13_SEMC_ADDR04, /* GPIO_EMC_13 is configured as SEMC_ADDR04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_14_SEMC_ADDR05, /* GPIO_EMC_14 is configured as SEMC_ADDR05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_15_SEMC_ADDR06, /* GPIO_EMC_15 is configured as SEMC_ADDR06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_16_SEMC_ADDR07, /* GPIO_EMC_16 is configured as SEMC_ADDR07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_17_SEMC_ADDR08, /* GPIO_EMC_17 is configured as SEMC_ADDR08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_18_SEMC_ADDR09, /* GPIO_EMC_18 is configured as SEMC_ADDR09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_19_SEMC_ADDR11, /* GPIO_EMC_19 is configured as SEMC_ADDR11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_20_SEMC_ADDR12, /* GPIO_EMC_20 is configured as SEMC_ADDR12 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_21_SEMC_BA0, /* GPIO_EMC_21 is configured as SEMC_BA0 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_22_SEMC_BA1, /* GPIO_EMC_22 is configured as SEMC_BA1 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_23_SEMC_ADDR10, /* GPIO_EMC_23 is configured as SEMC_ADDR10 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_24_SEMC_CAS, /* GPIO_EMC_24 is configured as SEMC_CAS */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_25_SEMC_RAS, /* GPIO_EMC_25 is configured as SEMC_RAS */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_26_SEMC_CLK, /* GPIO_EMC_26 is configured as SEMC_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_27_SEMC_CKE, /* GPIO_EMC_27 is configured as SEMC_CKE */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_28_SEMC_WE, /* GPIO_EMC_28 is configured as SEMC_WE */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_30_SEMC_DATA08, /* GPIO_EMC_30 is configured as SEMC_DATA08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_31_SEMC_DATA09, /* GPIO_EMC_31 is configured as SEMC_DATA09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_32_SEMC_DATA10, /* GPIO_EMC_32 is configured as SEMC_DATA10 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_33_SEMC_DATA11, /* GPIO_EMC_33 is configured as SEMC_DATA11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_34_SEMC_DATA12, /* GPIO_EMC_34 is configured as SEMC_DATA12 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_35_SEMC_DATA13, /* GPIO_EMC_35 is configured as SEMC_DATA13 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_36_SEMC_DATA14, /* GPIO_EMC_36 is configured as SEMC_DATA14 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_37_SEMC_DATA15, /* GPIO_EMC_37 is configured as SEMC_DATA15 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_38_SEMC_DM01, /* GPIO_EMC_38 is configured as SEMC_DM01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_41_SEMC_CSX00, /* GPIO_EMC_41 is configured as SEMC_CSX00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitCSIPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: H13, peripheral: CSI, signal: 'csi_data, 09', pin_signal: GPIO_AD_B1_08} + - {pin_num: M13, peripheral: CSI, signal: 'csi_data, 08', pin_signal: GPIO_AD_B1_09} + - {pin_num: L13, peripheral: CSI, signal: 'csi_data, 07', pin_signal: GPIO_AD_B1_10} + - {pin_num: J13, peripheral: CSI, signal: 'csi_data, 06', pin_signal: GPIO_AD_B1_11} + - {pin_num: H12, peripheral: CSI, signal: 'csi_data, 05', pin_signal: GPIO_AD_B1_12} + - {pin_num: H11, peripheral: CSI, signal: 'csi_data, 04', pin_signal: GPIO_AD_B1_13} + - {pin_num: J14, peripheral: CSI, signal: 'csi_data, 02', pin_signal: GPIO_AD_B1_15} + - {pin_num: G12, peripheral: CSI, signal: 'csi_data, 03', pin_signal: GPIO_AD_B1_14} + - {pin_num: L12, peripheral: CSI, signal: csi_pixclk, pin_signal: GPIO_AD_B1_04} + - {pin_num: K12, peripheral: CSI, signal: csi_mclk, pin_signal: GPIO_AD_B1_05} + - {pin_num: J12, peripheral: CSI, signal: csi_vsync, pin_signal: GPIO_AD_B1_06} + - {pin_num: K10, peripheral: CSI, signal: csi_hsync, pin_signal: GPIO_AD_B1_07} + - {pin_num: J11, peripheral: LPI2C1, signal: SCL, pin_signal: GPIO_AD_B1_00, identifier: CSI_I2C_SCL, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + - {pin_num: K11, peripheral: LPI2C1, signal: SDA, pin_signal: GPIO_AD_B1_01, identifier: CSI_I2C_SDA, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + - {pin_num: F11, peripheral: GPIO1, signal: 'gpio_io, 04', pin_signal: GPIO_AD_B0_04} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitCSIPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitCSIPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, /* GPIO_AD_B0_04 is configured as GPIO1_IO04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 is configured as LPI2C1_SCL */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 is configured as LPI2C1_SDA */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_04_CSI_PIXCLK, /* GPIO_AD_B1_04 is configured as CSI_PIXCLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_05_CSI_MCLK, /* GPIO_AD_B1_05 is configured as CSI_MCLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_06_CSI_VSYNC, /* GPIO_AD_B1_06 is configured as CSI_VSYNC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_07_CSI_HSYNC, /* GPIO_AD_B1_07 is configured as CSI_HSYNC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_08_CSI_DATA09, /* GPIO_AD_B1_08 is configured as CSI_DATA09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_09_CSI_DATA08, /* GPIO_AD_B1_09 is configured as CSI_DATA08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_10_CSI_DATA07, /* GPIO_AD_B1_10 is configured as CSI_DATA07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_11_CSI_DATA06, /* GPIO_AD_B1_11 is configured as CSI_DATA06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_12_CSI_DATA05, /* GPIO_AD_B1_12 is configured as CSI_DATA05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_13_CSI_DATA04, /* GPIO_AD_B1_13 is configured as CSI_DATA04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_14_CSI_DATA03, /* GPIO_AD_B1_14 is configured as CSI_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_15_CSI_DATA02, /* GPIO_AD_B1_15 is configured as CSI_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitLCDPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: C8, peripheral: LCDIF, signal: 'lcdif_data, 00', pin_signal: GPIO_B0_04, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: B8, peripheral: LCDIF, signal: 'lcdif_data, 01', pin_signal: GPIO_B0_05, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: A8, peripheral: LCDIF, signal: 'lcdif_data, 02', pin_signal: GPIO_B0_06, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: D7, peripheral: LCDIF, signal: lcdif_clk, pin_signal: GPIO_B0_00, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: A9, peripheral: LCDIF, signal: 'lcdif_data, 03', pin_signal: GPIO_B0_07, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: B9, peripheral: LCDIF, signal: 'lcdif_data, 04', pin_signal: GPIO_B0_08, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: C9, peripheral: LCDIF, signal: 'lcdif_data, 05', pin_signal: GPIO_B0_09, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: D9, peripheral: LCDIF, signal: 'lcdif_data, 06', pin_signal: GPIO_B0_10, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: A10, peripheral: LCDIF, signal: 'lcdif_data, 07', pin_signal: GPIO_B0_11, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: C10, peripheral: LCDIF, signal: 'lcdif_data, 08', pin_signal: GPIO_B0_12, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: D10, peripheral: LCDIF, signal: 'lcdif_data, 09', pin_signal: GPIO_B0_13, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: E10, peripheral: LCDIF, signal: 'lcdif_data, 10', pin_signal: GPIO_B0_14, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: E11, peripheral: LCDIF, signal: 'lcdif_data, 11', pin_signal: GPIO_B0_15, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: A11, peripheral: LCDIF, signal: 'lcdif_data, 12', pin_signal: GPIO_B1_00, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: B11, peripheral: LCDIF, signal: 'lcdif_data, 13', pin_signal: GPIO_B1_01, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: C11, peripheral: LCDIF, signal: 'lcdif_data, 14', pin_signal: GPIO_B1_02, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: D11, peripheral: LCDIF, signal: 'lcdif_data, 15', pin_signal: GPIO_B1_03, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: E7, peripheral: LCDIF, signal: lcdif_enable, pin_signal: GPIO_B0_01, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: E8, peripheral: LCDIF, signal: lcdif_hsync, pin_signal: GPIO_B0_02, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: D8, peripheral: LCDIF, signal: lcdif_vsync, pin_signal: GPIO_B0_03, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull} + - {pin_num: B14, peripheral: GPIO2, signal: 'gpio_io, 31', pin_signal: GPIO_B1_15, slew_rate: Slow} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitLCDPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitLCDPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_00_LCD_CLK, /* GPIO_B0_00 is configured as LCD_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_01_LCD_ENABLE, /* GPIO_B0_01 is configured as LCD_ENABLE */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_02_LCD_HSYNC, /* GPIO_B0_02 is configured as LCD_HSYNC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_03_LCD_VSYNC, /* GPIO_B0_03 is configured as LCD_VSYNC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_04_LCD_DATA00, /* GPIO_B0_04 is configured as LCD_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_05_LCD_DATA01, /* GPIO_B0_05 is configured as LCD_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_06_LCD_DATA02, /* GPIO_B0_06 is configured as LCD_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_07_LCD_DATA03, /* GPIO_B0_07 is configured as LCD_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_08_LCD_DATA04, /* GPIO_B0_08 is configured as LCD_DATA04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_09_LCD_DATA05, /* GPIO_B0_09 is configured as LCD_DATA05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_10_LCD_DATA06, /* GPIO_B0_10 is configured as LCD_DATA06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_11_LCD_DATA07, /* GPIO_B0_11 is configured as LCD_DATA07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_12_LCD_DATA08, /* GPIO_B0_12 is configured as LCD_DATA08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_13_LCD_DATA09, /* GPIO_B0_13 is configured as LCD_DATA09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_14_LCD_DATA10, /* GPIO_B0_14 is configured as LCD_DATA10 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B0_15_LCD_DATA11, /* GPIO_B0_15 is configured as LCD_DATA11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_00_LCD_DATA12, /* GPIO_B1_00 is configured as LCD_DATA12 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_01_LCD_DATA13, /* GPIO_B1_01 is configured as LCD_DATA13 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_02_LCD_DATA14, /* GPIO_B1_02 is configured as LCD_DATA14 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_03_LCD_DATA15, /* GPIO_B1_03 is configured as LCD_DATA15 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_15_GPIO2_IO31, /* GPIO_B1_15 is configured as GPIO2_IO31 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_00_LCD_CLK, /* GPIO_B0_00 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_01_LCD_ENABLE, /* GPIO_B0_01 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_02_LCD_HSYNC, /* GPIO_B0_02 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_03_LCD_VSYNC, /* GPIO_B0_03 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_04_LCD_DATA00, /* GPIO_B0_04 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_05_LCD_DATA01, /* GPIO_B0_05 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_06_LCD_DATA02, /* GPIO_B0_06 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_07_LCD_DATA03, /* GPIO_B0_07 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_08_LCD_DATA04, /* GPIO_B0_08 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_09_LCD_DATA05, /* GPIO_B0_09 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_10_LCD_DATA06, /* GPIO_B0_10 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_11_LCD_DATA07, /* GPIO_B0_11 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_12_LCD_DATA08, /* GPIO_B0_12 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_13_LCD_DATA09, /* GPIO_B0_13 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_14_LCD_DATA10, /* GPIO_B0_14 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B0_15_LCD_DATA11, /* GPIO_B0_15 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_00_LCD_DATA12, /* GPIO_B1_00 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_01_LCD_DATA13, /* GPIO_B1_01 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_02_LCD_DATA14, /* GPIO_B1_02 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_03_LCD_DATA15, /* GPIO_B1_03 PAD functional properties : */ + 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 100K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_15_GPIO2_IO31, /* GPIO_B1_15 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitCANPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: H14, peripheral: CAN2, signal: TX, pin_signal: GPIO_AD_B0_14} + - {pin_num: L10, peripheral: CAN2, signal: RX, pin_signal: GPIO_AD_B0_15} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitCANPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitCANPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_14_FLEXCAN2_TX, /* GPIO_AD_B0_14 is configured as FLEXCAN2_TX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_15_FLEXCAN2_RX, /* GPIO_AD_B0_15 is configured as FLEXCAN2_RX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitENETPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: A7, peripheral: ENET, signal: enet_mdc, pin_signal: GPIO_EMC_40} + - {pin_num: C7, peripheral: ENET, signal: enet_mdio, pin_signal: GPIO_EMC_41} + - {pin_num: B13, peripheral: ENET, signal: enet_ref_clk, pin_signal: GPIO_B1_10} + - {pin_num: E12, peripheral: ENET, signal: 'enet_rx_data, 0', pin_signal: GPIO_B1_04} + - {pin_num: D12, peripheral: ENET, signal: 'enet_rx_data, 1', pin_signal: GPIO_B1_05} + - {pin_num: C12, peripheral: ENET, signal: enet_rx_en, pin_signal: GPIO_B1_06} + - {pin_num: C13, peripheral: ENET, signal: enet_rx_er, pin_signal: GPIO_B1_11} + - {pin_num: B12, peripheral: ENET, signal: 'enet_tx_data, 0', pin_signal: GPIO_B1_07} + - {pin_num: A12, peripheral: ENET, signal: 'enet_tx_data, 1', pin_signal: GPIO_B1_08} + - {pin_num: A13, peripheral: ENET, signal: enet_tx_en, pin_signal: GPIO_B1_09} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitENETPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitENETPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_04_ENET_RX_DATA00, /* GPIO_B1_04 is configured as ENET_RX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_05_ENET_RX_DATA01, /* GPIO_B1_05 is configured as ENET_RX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_06_ENET_RX_EN, /* GPIO_B1_06 is configured as ENET_RX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_07_ENET_TX_DATA00, /* GPIO_B1_07 is configured as ENET_TX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_08_ENET_TX_DATA01, /* GPIO_B1_08 is configured as ENET_TX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_09_ENET_TX_EN, /* GPIO_B1_09 is configured as ENET_TX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_10_ENET_REF_CLK, /* GPIO_B1_10 is configured as ENET_REF_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_11_ENET_RX_ER, /* GPIO_B1_11 is configured as ENET_RX_ER */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_40_ENET_MDC, /* GPIO_EMC_40 is configured as ENET_MDC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_41_ENET_MDIO, /* GPIO_EMC_41 is configured as ENET_MDIO */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitUSDHCPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: J2, peripheral: USDHC1, signal: 'usdhc_data, 3', pin_signal: GPIO_SD_B0_05} + - {pin_num: H2, peripheral: USDHC1, signal: 'usdhc_data, 2', pin_signal: GPIO_SD_B0_04} + - {pin_num: K1, peripheral: USDHC1, signal: 'usdhc_data, 1', pin_signal: GPIO_SD_B0_03} + - {pin_num: J1, peripheral: USDHC1, signal: 'usdhc_data, 0', pin_signal: GPIO_SD_B0_02} + - {pin_num: J4, peripheral: USDHC1, signal: usdhc_cmd, pin_signal: GPIO_SD_B0_00} + - {pin_num: J3, peripheral: USDHC1, signal: usdhc_clk, pin_signal: GPIO_SD_B0_01} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitUSDHCPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitUSDHCPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, /* GPIO_SD_B0_00 is configured as USDHC1_CMD */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, /* GPIO_SD_B0_01 is configured as USDHC1_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, /* GPIO_SD_B0_02 is configured as USDHC1_DATA0 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, /* GPIO_SD_B0_03 is configured as USDHC1_DATA1 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, /* GPIO_SD_B0_04 is configured as USDHC1_DATA2 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, /* GPIO_SD_B0_05 is configured as USDHC1_DATA3 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitHyperFlashPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: L4, peripheral: FLEXSPI, signal: FLEXSPI_A_SCLK, pin_signal: GPIO_SD_B1_07} + - {pin_num: P4, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA2, pin_signal: GPIO_SD_B1_10} + - {pin_num: P3, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA0, pin_signal: GPIO_SD_B1_08} + - {pin_num: N4, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA1, pin_signal: GPIO_SD_B1_09} + - {pin_num: L5, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA3, pin_signal: GPIO_SD_B1_00} + - {pin_num: M5, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA2, pin_signal: GPIO_SD_B1_01} + - {pin_num: M3, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA1, pin_signal: GPIO_SD_B1_02} + - {pin_num: M4, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA0, pin_signal: GPIO_SD_B1_03} + - {pin_num: P2, peripheral: FLEXSPI, signal: FLEXSPI_B_SCLK, pin_signal: GPIO_SD_B1_04} + - {pin_num: L3, peripheral: FLEXSPI, signal: FLEXSPI_A_SS0_B, pin_signal: GPIO_SD_B1_06} + - {pin_num: P5, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA3, pin_signal: GPIO_SD_B1_11} + - {pin_num: N3, peripheral: FLEXSPI, signal: FLEXSPI_A_DQS, pin_signal: GPIO_SD_B1_05} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitHyperFlashPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitHyperFlashPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_00_FLEXSPIB_DATA03, /* GPIO_SD_B1_00 is configured as FLEXSPIB_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_01_FLEXSPIB_DATA02, /* GPIO_SD_B1_01 is configured as FLEXSPIB_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_02_FLEXSPIB_DATA01, /* GPIO_SD_B1_02 is configured as FLEXSPIB_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_03_FLEXSPIB_DATA00, /* GPIO_SD_B1_03 is configured as FLEXSPIB_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_04_FLEXSPIB_SCLK, /* GPIO_SD_B1_04 is configured as FLEXSPIB_SCLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, /* GPIO_SD_B1_05 is configured as FLEXSPIA_DQS */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, /* GPIO_SD_B1_06 is configured as FLEXSPIA_SS0_B */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, /* GPIO_SD_B1_07 is configured as FLEXSPIA_SCLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, /* GPIO_SD_B1_08 is configured as FLEXSPIA_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, /* GPIO_SD_B1_09 is configured as FLEXSPIA_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, /* GPIO_SD_B1_10 is configured as FLEXSPIA_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, /* GPIO_SD_B1_11 is configured as FLEXSPIA_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + +/*********************************************************************************************************************** + * EOF + **********************************************************************************************************************/ diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c new file mode 100644 index 0000000000..d93de620c0 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 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 < 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/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c new file mode 100644 index 0000000000..d912b7045c --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 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; + } + } + + 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 = ADC_ETC_CTRL_EXT0_TRIG_PRIORITY(config->TSC0triggerPriority) | + ADC_ETC_CTRL_EXT1_TRIG_PRIORITY(config->TSC1triggerPriority) | + 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 (config->enableTSCBypass) + { + tmp32 |= ADC_ETC_CTRL_TSC_BYPASS_MASK; + } + if (config->enableTSC0Trigger) + { + tmp32 |= ADC_ETC_CTRL_EXT0_TRIG_ENABLE_MASK; + } + if (config->enableTSC1Trigger) + { + tmp32 |= ADC_ETC_CTRL_EXT1_TRIG_ENABLE_MASK; + } + 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)); + + config->enableTSCBypass = true; + config->enableTSC0Trigger = false; + config->enableTSC1Trigger = false; +#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*/ + config->TSC0triggerPriority = 0U; + config->TSC1triggerPriority = 0U; + 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_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_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_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_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_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_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_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_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_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_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_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_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/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c new file mode 100644 index 0000000000..077b4e01e2 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_aipstz.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.aipstz" +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * brief Configure the privilege level for master. + * + * param base AIPSTZ peripheral base pointer + * param master Masters for AIPSTZ. + * param privilegeConfig Configuration is ORed from aipstz_master_privilege_level_t. + */ +void AIPSTZ_SetMasterPriviledgeLevel(AIPSTZ_Type *base, aipstz_master_t master, uint32_t privilegeConfig) +{ + uint32_t mask = ((uint32_t)master >> 8U) - 1U; + uint32_t shift = (uint32_t)master & 0xFFU; + base->MPR = (base->MPR & (~(mask << shift))) | (privilegeConfig << shift); +} + +/*! + * brief Configure the access for peripheral. + * + * param base AIPSTZ peripheral base pointer + * param master Peripheral for AIPSTZ. + * param accessControl Configuration is ORed from aipstz_peripheral_access_control_t. + */ +void AIPSTZ_SetPeripheralAccessControl(AIPSTZ_Type *base, aipstz_peripheral_t peripheral, uint32_t accessControl) +{ + volatile uint32_t *reg = (uint32_t *)((uint32_t)base + ((uint32_t)peripheral >> 16U)); + uint32_t mask = (((uint32_t)peripheral & 0xFF00U) >> 8U) - 1U; + uint32_t shift = (uint32_t)peripheral & 0xFFU; + + *reg = (*reg & (~(mask << shift))) | ((accessControl & mask) << shift); +} diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c new file mode 100644 index 0000000000..a8f1f29ddb --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/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/nxp/devices/MIMXRT1052/drivers/fsl_bee.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_bee.c new file mode 100644 index 0000000000..d4ffdacfb9 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/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/nxp/devices/MIMXRT1052/drivers/fsl_cache.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c new file mode 100644 index 0000000000..31d6a2479c --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c @@ -0,0 +1,602 @@ +/* + * Copyright 2016-2019 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/nxp/devices/MIMXRT1052/drivers/fsl_clock.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c new file mode 100644 index 0000000000..cb5ca96dab --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c @@ -0,0 +1,1250 @@ +/* + * Copyright 2017 - 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_clock.h" +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.clock" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* To make full use of CM7 hardware FPU, use double instead of uint64_t in clock driver to +achieve better performance, it is depend on the IDE Floating point settings, if double precision is selected +in IDE, clock_64b_t will switch to double type automatically. only support IAR and MDK here */ +#if __FPU_USED + +#if (defined(__ICCARM__)) + +#if (__ARMVFP__ >= __ARMFPV5__) && \ + (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/ +typedef double clock_64b_t; +#else +typedef uint64_t clock_64b_t; +#endif + +#elif (defined(__GNUC__)) + +#if (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/ +typedef double clock_64b_t; +#else +typedef uint64_t clock_64b_t; +#endif + +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) + +#if defined __TARGET_FPU_FPV5_D16 +typedef double clock_64b_t; +#else +typedef uint64_t clock_64b_t; +#endif + +#else +typedef uint64_t clock_64b_t; +#endif + +#else +typedef uint64_t clock_64b_t; +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* External XTAL (OSC) clock frequency. */ +volatile uint32_t g_xtalFreq; +/* External RTC XTAL clock frequency. */ +volatile uint32_t g_rtcXtalFreq; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get the periph clock frequency. + * + * @return Periph clock frequency in Hz. + */ +static uint32_t CLOCK_GetPeriphClkFreq(void); + +/******************************************************************************* + * Code + ******************************************************************************/ + +static uint32_t CLOCK_GetPeriphClkFreq(void) +{ + uint32_t freq; + + /* Periph_clk2_clk ---> Periph_clk */ + if ((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK) != 0U) + { + switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) + { + /* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */ + case CCM_CBCMR_PERIPH_CLK2_SEL(0U): + freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1); + break; + + /* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */ + case CCM_CBCMR_PERIPH_CLK2_SEL(1U): + freq = CLOCK_GetOscFreq(); + break; + + case CCM_CBCMR_PERIPH_CLK2_SEL(2U): + freq = CLOCK_GetPllFreq(kCLOCK_PllSys); + break; + + case CCM_CBCMR_PERIPH_CLK2_SEL(3U): + default: + freq = 0U; + break; + } + + freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U); + } + /* Pre_Periph_clk ---> Periph_clk */ + else + { + switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) + { + /* PLL2 ---> Pre_Periph_clk ---> Periph_clk */ + case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U): + freq = CLOCK_GetPllFreq(kCLOCK_PllSys); + break; + + /* PLL2 PFD2 ---> Pre_Periph_clk ---> Periph_clk */ + case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U): + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2); + break; + + /* PLL2 PFD0 ---> Pre_Periph_clk ---> Periph_clk */ + case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U): + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0); + break; + + /* PLL1 divided(/2) ---> Pre_Periph_clk ---> Periph_clk */ + case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U): + freq = CLOCK_GetPllFreq(kCLOCK_PllArm) / + (((CCM->CACRR & CCM_CACRR_ARM_PODF_MASK) >> CCM_CACRR_ARM_PODF_SHIFT) + 1U); + break; + + default: + freq = 0U; + break; + } + } + + return freq; +} + +/*! + * brief Initialize the external 24MHz clock. + * + * This function supports two modes: + * 1. Use external crystal oscillator. + * 2. Bypass the external crystal oscillator, using input source clock directly. + * + * After this function, please call ref CLOCK_SetXtal0Freq to inform clock driver + * the external clock frequency. + * + * param bypassXtalOsc Pass in true to bypass the external crystal oscillator. + * note This device does not support bypass external crystal oscillator, so + * the input parameter should always be false. + */ +void CLOCK_InitExternalClk(bool bypassXtalOsc) +{ + /* This device does not support bypass XTAL OSC. */ + assert(!bypassXtalOsc); + + CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */ + while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0U) + { + } + CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */ + while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL) + { + } + CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; +} + +/*! + * brief Deinitialize the external 24MHz clock. + * + * This function disables the external 24MHz clock. + * + * After this function, please call ref CLOCK_SetXtal0Freq to set external clock + * frequency to 0. + */ +void CLOCK_DeinitExternalClk(void) +{ + CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */ +} + +/*! + * brief Switch the OSC. + * + * This function switches the OSC source for SoC. + * + * param osc OSC source to switch to. + */ +void CLOCK_SwitchOsc(clock_osc_t osc) +{ + if (osc == kCLOCK_RcOsc) + { + XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_SET_OSC_SEL_MASK; + } + else + { + XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK; + } +} + +/*! + * brief Initialize the RC oscillator 24MHz clock. + */ +void CLOCK_InitRcOsc24M(void) +{ + XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK; +} + +/*! + * brief Power down the RCOSC 24M clock. + */ +void CLOCK_DeinitRcOsc24M(void) +{ + XTALOSC24M->LOWPWR_CTRL &= ~XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK; +} + +/*! + * brief Gets the AHB clock frequency. + * + * return The AHB clock frequency value in hertz. + */ +uint32_t CLOCK_GetAhbFreq(void) +{ + return CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U); +} + +/*! + * brief Gets the SEMC clock frequency. + * + * return The SEMC clock frequency value in hertz. + */ +uint32_t CLOCK_GetSemcFreq(void) +{ + uint32_t freq; + + /* SEMC alternative clock ---> SEMC Clock */ + if ((CCM->CBCDR & CCM_CBCDR_SEMC_CLK_SEL_MASK) != 0U) + { + /* PLL3 PFD1 ---> SEMC alternative clock ---> SEMC Clock */ + if ((CCM->CBCDR & CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK) != 0U) + { + freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1); + } + /* PLL2 PFD2 ---> SEMC alternative clock ---> SEMC Clock */ + else + { + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2); + } + } + /* Periph_clk ---> SEMC Clock */ + else + { + freq = CLOCK_GetPeriphClkFreq(); + } + + freq /= (((CCM->CBCDR & CCM_CBCDR_SEMC_PODF_MASK) >> CCM_CBCDR_SEMC_PODF_SHIFT) + 1U); + + return freq; +} + +/*! + * brief Gets the IPG clock frequency. + * + * return The IPG clock frequency value in hertz. + */ +uint32_t CLOCK_GetIpgFreq(void) +{ + return CLOCK_GetAhbFreq() / (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U); +} + +/*! + * brief Gets the PER clock frequency. + * + * return The PER clock frequency value in hertz. + */ +uint32_t CLOCK_GetPerClkFreq(void) +{ + uint32_t freq; + + /* Osc_clk ---> PER Clock*/ + if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0U) + { + freq = CLOCK_GetOscFreq(); + } + /* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */ + else + { + freq = CLOCK_GetIpgFreq(); + } + + freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U); + + return freq; +} + +/*! + * brief Gets the clock frequency for a specific clock name. + * + * This function checks the current clock configurations and then calculates + * the clock frequency for a specific clock name defined in clock_name_t. + * + * param clockName Clock names defined in clock_name_t + * return Clock frequency value in hertz + */ +uint32_t CLOCK_GetFreq(clock_name_t name) +{ + uint32_t freq; + + switch (name) + { + case kCLOCK_CpuClk: + case kCLOCK_AhbClk: + freq = CLOCK_GetAhbFreq(); + break; + + case kCLOCK_SemcClk: + freq = CLOCK_GetSemcFreq(); + break; + + case kCLOCK_IpgClk: + freq = CLOCK_GetIpgFreq(); + break; + + case kCLOCK_PerClk: + freq = CLOCK_GetPerClkFreq(); + break; + + case kCLOCK_OscClk: + freq = CLOCK_GetOscFreq(); + break; + case kCLOCK_RtcClk: + freq = CLOCK_GetRtcFreq(); + break; + case kCLOCK_ArmPllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllArm); + break; + case kCLOCK_Usb1PllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1); + break; + case kCLOCK_Usb1PllPfd0Clk: + freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0); + break; + case kCLOCK_Usb1PllPfd1Clk: + freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1); + break; + case kCLOCK_Usb1PllPfd2Clk: + freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2); + break; + case kCLOCK_Usb1PllPfd3Clk: + freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3); + break; + case kCLOCK_Usb2PllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2); + break; + case kCLOCK_SysPllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllSys); + break; + case kCLOCK_SysPllPfd0Clk: + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0); + break; + case kCLOCK_SysPllPfd1Clk: + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1); + break; + case kCLOCK_SysPllPfd2Clk: + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2); + break; + case kCLOCK_SysPllPfd3Clk: + freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3); + break; + case kCLOCK_EnetPll0Clk: + freq = CLOCK_GetPllFreq(kCLOCK_PllEnet); + break; + case kCLOCK_EnetPll1Clk: + freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M); + break; + case kCLOCK_AudioPllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllAudio); + break; + case kCLOCK_VideoPllClk: + freq = CLOCK_GetPllFreq(kCLOCK_PllVideo); + break; + default: + freq = 0U; + break; + } + + return freq; +} + +/*! brief Enable USB HS clock. + * + * This function only enables the access to USB HS prepheral, upper layer + * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY + * clock to use USB HS. + * + * param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused. + * param freq USB HS does not care about the clock source, so this parameter is ignored. + * retval true The clock is set successfully. + * retval false The clock source is invalid to get proper USB HS clock. + */ +bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq) +{ + uint32_t i; + CCM->CCGR6 |= CCM_CCGR6_CG0_MASK; + USB1->USBCMD |= USBHS_USBCMD_RST_MASK; + + /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/ + for (i = 0; i < 400000U; i++) + { + __ASM("nop"); + } + PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) | + (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK); + return true; +} + +/*! brief Enable USB HS clock. + * + * This function only enables the access to USB HS prepheral, upper layer + * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY + * clock to use USB HS. + * + * param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused. + * param freq USB HS does not care about the clock source, so this parameter is ignored. + * retval true The clock is set successfully. + * retval false The clock source is invalid to get proper USB HS clock. + */ +bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq) +{ + uint32_t i = 0; + CCM->CCGR6 |= CCM_CCGR6_CG0_MASK; + USB2->USBCMD |= USBHS_USBCMD_RST_MASK; + + /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/ + for (i = 0; i < 400000U; i++) + { + __ASM("nop"); + } + PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) | + (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK); + return true; +} + +/*! brief Enable USB HS PHY PLL clock. + * + * This function enables the internal 480MHz USB PHY PLL clock. + * + * param src USB HS PHY PLL clock source. + * param freq The frequency specified by src. + * retval true The clock is set successfully. + * retval false The clock source is invalid to get proper USB HS clock. + */ +bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq) +{ + const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U}; + if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0U) + { + CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK; + } + else + { + CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll); + } + USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */ + USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK; + + USBPHY1->PWD = 0; + USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | + USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK; + return true; +} + +/*! brief Disable USB HS PHY PLL clock. + * + * This function disables USB HS PHY PLL clock. + */ +void CLOCK_DisableUsbhs0PhyPllClock(void) +{ + CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK; + USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */ +} + +/*! + * brief Initialize the ARM PLL. + * + * This function initialize the ARM PLL with specific settings + * + * param config configuration to set to PLL. + */ +void CLOCK_InitArmPll(const clock_arm_pll_config_t *config) +{ + /* Bypass PLL first */ + CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_ARM_BYPASS_MASK | CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_ARM = + (CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) | + CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider); + + while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK; +} + +/*! + * brief De-initialize the ARM PLL. + */ +void CLOCK_DeinitArmPll(void) +{ + CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK; +} + +/*! + * brief Initialize the System PLL. + * + * This function initializes the System PLL with specific settings + * + * param config Configuration to set to PLL. + */ +void CLOCK_InitSysPll(const clock_sys_pll_config_t *config) +{ + /* Bypass PLL first */ + CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_SYS = + (CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) | + CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider); + + /* Initialize the fractional mode */ + CCM_ANALOG->PLL_SYS_NUM = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator); + CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator); + + /* Initialize the spread spectrum mode */ + CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) | + CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) | + CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop); + + while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK; +} + +/*! + * brief De-initialize the System PLL. + */ +void CLOCK_DeinitSysPll(void) +{ + CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK; +} + +/*! + * brief Initialize the USB1 PLL. + * + * This function initializes the USB1 PLL with specific settings + * + * param config Configuration to set to PLL. + */ +void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config) +{ + /* Bypass PLL first */ + CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) | + CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK | + CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider); + + while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK; +} + +/*! + * brief Deinitialize the USB1 PLL. + */ +void CLOCK_DeinitUsb1Pll(void) +{ + CCM_ANALOG->PLL_USB1 = 0U; +} + +/*! + * brief Initialize the USB2 PLL. + * + * This function initializes the USB2 PLL with specific settings + * + * param config Configuration to set to PLL. + */ +void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config) +{ + /* Bypass PLL first */ + CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_USB2_BYPASS_MASK | CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) | + CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK | + CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider); + + while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK; +} + +/*! + * brief Deinitialize the USB2 PLL. + */ +void CLOCK_DeinitUsb2Pll(void) +{ + CCM_ANALOG->PLL_USB2 = 0U; +} + +/*! + * brief Initializes the Audio PLL. + * + * This function initializes the Audio PLL with specific settings + * + * param config Configuration to set to PLL. + */ +void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config) +{ + uint32_t pllAudio; + uint32_t misc2 = 0; + + /* Bypass PLL first */ + CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_AUDIO_NUM = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator); + CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator); + + /* + * Set post divider: + * + * ------------------------------------------------------------------------ + * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT] | MISC2[AUDIO_DIV] | + * ------------------------------------------------------------------------ + * | 1 | 2 | 0 | + * ------------------------------------------------------------------------ + * | 2 | 1 | 0 | + * ------------------------------------------------------------------------ + * | 4 | 2 | 3 | + * ------------------------------------------------------------------------ + * | 8 | 1 | 3 | + * ------------------------------------------------------------------------ + * | 16 | 0 | 3 | + * ------------------------------------------------------------------------ + */ + pllAudio = + (CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) | + CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider); + + switch (config->postDivider) + { + case 16: + pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0); + misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; + break; + + case 8: + pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1); + misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; + break; + + case 4: + pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2); + misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; + break; + + case 2: + pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1); + break; + + default: + pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2); + break; + } + + CCM_ANALOG->MISC2 = + (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2; + + CCM_ANALOG->PLL_AUDIO = pllAudio; + + while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK; +} + +/*! + * brief De-initialize the Audio PLL. + */ +void CLOCK_DeinitAudioPll(void) +{ + CCM_ANALOG->PLL_AUDIO = (uint32_t)CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK; +} + +/*! + * brief Initialize the video PLL. + * + * This function configures the Video PLL with specific settings + * + * param config configuration to set to PLL. + */ +void CLOCK_InitVideoPll(const clock_video_pll_config_t *config) +{ + uint32_t pllVideo; + uint32_t misc2 = 0; + + /* Bypass PLL first */ + CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(config->src); + + CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator); + CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator); + + /* + * Set post divider: + * + * ------------------------------------------------------------------------ + * | config->postDivider | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] | + * ------------------------------------------------------------------------ + * | 1 | 2 | 0 | + * ------------------------------------------------------------------------ + * | 2 | 1 | 0 | + * ------------------------------------------------------------------------ + * | 4 | 2 | 3 | + * ------------------------------------------------------------------------ + * | 8 | 1 | 3 | + * ------------------------------------------------------------------------ + * | 16 | 0 | 3 | + * ------------------------------------------------------------------------ + */ + pllVideo = + (CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) | + CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider); + + switch (config->postDivider) + { + case 16: + pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0); + misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3); + break; + + case 8: + pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1); + misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3); + break; + + case 4: + pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2); + misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3); + break; + + case 2: + pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1); + break; + + default: + pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2); + break; + } + + CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2; + + CCM_ANALOG->PLL_VIDEO = pllVideo; + + while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; +} + +/*! + * brief De-initialize the Video PLL. + */ +void CLOCK_DeinitVideoPll(void) +{ + CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK; +} + +/*! + * brief Initialize the ENET PLL. + * + * This function initializes the ENET PLL with specific settings. + * + * param config Configuration to set to PLL. + */ +void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config) +{ + uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider); + + CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) | + CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src); + + if (config->enableClkOutput) + { + enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK; + } + + if (config->enableClkOutput25M) + { + enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK; + } + + CCM_ANALOG->PLL_ENET = + (CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) | + enet_pll; + + /* Wait for stable */ + while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL) + { + } + + /* Disable Bypass */ + CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK; +} + +/*! + * brief Deinitialize the ENET PLL. + * + * This function disables the ENET PLL. + */ +void CLOCK_DeinitEnetPll(void) +{ + CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK; +} + +/*! + * brief Get current PLL output frequency. + * + * This function get current output frequency of specific PLL + * + * param pll pll name to get frequency. + * return The PLL output frequency in hertz. + */ +uint32_t CLOCK_GetPllFreq(clock_pll_t pll) +{ + uint32_t freq; + uint32_t divSelect; + clock_64b_t freqTmp; + + const uint32_t enetRefClkFreq[] = { + 25000000U, /* 25M */ + 50000000U, /* 50M */ + 100000000U, /* 100M */ + 125000000U /* 125M */ + }; + + /* check if PLL is enabled */ + if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll)) + { + return 0U; + } + + /* get pll reference clock */ + freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll); + + /* check if pll is bypassed */ + if (CLOCK_IsPllBypassed(CCM_ANALOG, pll)) + { + return freq; + } + + switch (pll) + { + case kCLOCK_PllArm: + freq = ((freq * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >> + CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >> + 1U); + break; + case kCLOCK_PllSys: + /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */ + freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM))); + freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM)); + + if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0U) + { + freq *= 22U; + } + else + { + freq *= 20U; + } + + freq += (uint32_t)freqTmp; + break; + + case kCLOCK_PllUsb1: + freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U)); + break; + + case kCLOCK_PllAudio: + /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */ + divSelect = + (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT; + + freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM))); + freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM)); + + freq = freq * divSelect + (uint32_t)freqTmp; + + /* AUDIO PLL output = PLL output frequency / POSTDIV. */ + + /* + * Post divider: + * + * PLL_AUDIO[POST_DIV_SELECT]: + * 0x00: 4 + * 0x01: 2 + * 0x02: 1 + * + * MISC2[AUDO_DIV]: + * 0x00: 1 + * 0x01: 2 + * 0x02: 1 + * 0x03: 4 + */ + switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK) + { + case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U): + freq = freq >> 2U; + break; + + case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U): + freq = freq >> 1U; + break; + + case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U): + freq = freq >> 0U; + break; + + default: + assert(false); + break; + } + + switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK)) + { + case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1): + freq >>= 2U; + break; + + case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1): + freq >>= 1U; + break; + + case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0): + case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0): + freq >>= 0U; + break; + + default: + assert(false); + break; + } + break; + + case kCLOCK_PllVideo: + /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */ + divSelect = + (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT; + + freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_NUM))); + freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_DENOM)); + freq = freq * divSelect + (uint32_t)freqTmp; + + /* VIDEO PLL output = PLL output frequency / POSTDIV. */ + + /* + * Post divider: + * + * PLL_VIDEO[POST_DIV_SELECT]: + * 0x00: 4 + * 0x01: 2 + * 0x02: 1 + * + * MISC2[VIDEO_DIV]: + * 0x00: 1 + * 0x01: 2 + * 0x02: 1 + * 0x03: 4 + */ + switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK) + { + case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U): + freq = freq >> 2U; + break; + + case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U): + freq = freq >> 1U; + break; + + case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2U): + freq = freq >> 0U; + break; + + default: + assert(false); + break; + } + + switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK) + { + case CCM_ANALOG_MISC2_VIDEO_DIV(3U): + freq >>= 2U; + break; + + case CCM_ANALOG_MISC2_VIDEO_DIV(1U): + freq >>= 1U; + break; + + case CCM_ANALOG_MISC2_VIDEO_DIV(0U): + case CCM_ANALOG_MISC2_VIDEO_DIV(2U): + freq >>= 0U; + break; + + default: + assert(false); + break; + } + break; + case kCLOCK_PllEnet: + divSelect = + (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT; + freq = enetRefClkFreq[divSelect]; + break; + + case kCLOCK_PllEnet25M: + /* ref_enetpll1 if fixed at 25MHz. */ + freq = 25000000UL; + break; + + case kCLOCK_PllUsb2: + freq = (freq * (((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) != 0U) ? 22U : 20U)); + break; + default: + freq = 0U; + break; + } + + return freq; +} + +/*! + * brief Initialize the System PLL PFD. + * + * This function initializes the System PLL PFD. During new value setting, + * the clock output is disabled to prevent glitch. + * + * param pfd Which PFD clock to enable. + * param pfdFrac The PFD FRAC value. + * note It is recommended that PFD settings are kept between 12-35. + */ +void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac) +{ + uint32_t pfdIndex = (uint32_t)pfd; + uint32_t pfd528; + + pfd528 = CCM_ANALOG->PFD_528 & + ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) + << (8UL * pfdIndex))); + + /* Disable the clock output first. */ + CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex)); + + /* Set the new value and enable output. */ + CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex)); +} + +/*! + * brief De-initialize the System PLL PFD. + * + * This function disables the System PLL PFD. + * + * param pfd Which PFD clock to disable. + */ +void CLOCK_DeinitSysPfd(clock_pfd_t pfd) +{ + CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8U * (uint8_t)pfd); +} + +/*! + * brief Initialize the USB1 PLL PFD. + * + * This function initializes the USB1 PLL PFD. During new value setting, + * the clock output is disabled to prevent glitch. + * + * param pfd Which PFD clock to enable. + * param pfdFrac The PFD FRAC value. + * note It is recommended that PFD settings are kept between 12-35. + */ +void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac) +{ + uint32_t pfdIndex = (uint32_t)pfd; + uint32_t pfd480; + + pfd480 = CCM_ANALOG->PFD_480 & + ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) + << (8UL * pfdIndex))); + + /* Disable the clock output first. */ + CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex)); + + /* Set the new value and enable output. */ + CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex)); +} + +/*! + * brief De-initialize the USB1 PLL PFD. + * + * This function disables the USB1 PLL PFD. + * + * param pfd Which PFD clock to disable. + */ +void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd) +{ + CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd); +} + +/*! + * brief Get current System PLL PFD output frequency. + * + * This function get current output frequency of specific System PLL PFD + * + * param pfd pfd name to get frequency. + * return The PFD output frequency in hertz. + */ +uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd) +{ + uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys); + + switch (pfd) + { + case kCLOCK_Pfd0: + freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT); + break; + + case kCLOCK_Pfd1: + freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT); + break; + + case kCLOCK_Pfd2: + freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT); + break; + + case kCLOCK_Pfd3: + freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT); + break; + + default: + freq = 0U; + break; + } + freq *= 18U; + + return freq; +} + +/*! + * brief Get current USB1 PLL PFD output frequency. + * + * This function get current output frequency of specific USB1 PLL PFD + * + * param pfd pfd name to get frequency. + * return The PFD output frequency in hertz. + */ +uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd) +{ + uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1); + + switch (pfd) + { + case kCLOCK_Pfd0: + freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT); + break; + + case kCLOCK_Pfd1: + freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT); + break; + + case kCLOCK_Pfd2: + freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT); + break; + + case kCLOCK_Pfd3: + freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT); + break; + + default: + freq = 0U; + break; + } + freq *= 18U; + + return freq; +} + +/*! brief Enable USB HS PHY PLL clock. + * + * This function enables the internal 480MHz USB PHY PLL clock. + * + * param src USB HS PHY PLL clock source. + * param freq The frequency specified by src. + * retval true The clock is set successfully. + * retval false The clock source is invalid to get proper USB HS clock. + */ +bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq) +{ + const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U}; + CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll); + USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */ + USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK; + + USBPHY2->PWD = 0; + USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | + USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK; + + return true; +} + +/*! brief Disable USB HS PHY PLL clock. + * + * This function disables USB HS PHY PLL clock. + */ +void CLOCK_DisableUsbhs1PhyPllClock(void) +{ + CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK; + USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */ +} diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c new file mode 100644 index 0000000000..8f6bed69b4 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/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/nxp/devices/MIMXRT1052/drivers/fsl_common.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c new file mode 100644 index 0000000000..fd96a955c3 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 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 + +#ifndef __GIC_PRIO_BITS +#if defined(ENABLE_RAM_VECTOR_TABLE) +uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler) +{ +/* 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[irq + 16]; + /* make sure the __VECTOR_RAM is noncachable */ + __VECTOR_RAM[irq + 16] = irqHandler; + + EnableGlobalIRQ(irqMaskValue); + SDK_ISR_EXIT_BARRIER; + + return ret; +} +#endif /* ENABLE_RAM_VECTOR_TABLE. */ +#endif /* __GIC_PRIO_BITS. */ + +#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) +#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] = 1u << intNumber; + EnableIRQ(interrupt); /* also enable interrupt at NVIC */ +} + +void DisableDeepSleepIRQ(IRQn_Type interrupt) +{ + uint32_t intNumber = (uint32_t)interrupt; + + DisableIRQ(interrupt); /* also disable interrupt at NVIC */ + uint32_t index = 0; + + while (intNumber >= 32u) + { + index++; + intNumber -= 32u; + } + + SYSCON->STARTERCLR[index] = 1u << intNumber; +} +#endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */ +#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */ + +void *SDK_Malloc(size_t size, size_t alignbytes) +{ + mem_align_cb_t *p_cb = NULL; + uint32_t alignedsize = SDK_SIZEALIGN(size, alignbytes) + alignbytes + sizeof(mem_align_cb_t); + union + { + void *pointer_value; + uint32_t unsigned_value; + } p_align_addr, p_addr; + + p_addr.pointer_value = malloc(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; + uint32_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); +} + +/*! + * @brief Delay function bases on while loop, every loop includes three instructions. + * + * @param count Counts of loop needed for dalay. + */ +#if defined(SDK_DELAY_USE_DWT) && defined(DWT) +void 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 getCpuCycleCount(void) +{ + return DWT->CYCCNT; +} +#elif defined __XCC__ +extern uint32_t xthal_get_ccount(void); +void enableCpuCycleCounter(void) +{ + /* do nothing */ +} + +uint32_t getCpuCycleCount(void) +{ + return xthal_get_ccount(); +} +#endif + +#ifndef __XCC__ +#if (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT)) +#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 +} +/* 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"); +} +#endif /* defined(__CC_ARM) */ +#endif /* (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT)) */ +#endif /* __XCC__ */ +/*! + * @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 delay_us and + * coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delay_us only supports + * up to 4294967 in current code. If long time delay is needed, please implement a new delay function. + * + * @param delay_us Delay time in unit of microsecond. + * @param coreClock_Hz Core clock frequency with Hz. + */ +void SDK_DelayAtLeastUs(uint32_t delay_us, uint32_t coreClock_Hz) +{ + assert(0U != delay_us); + uint64_t count = USEC_TO_COUNT(delay_us, coreClock_Hz); + assert(count <= UINT32_MAX); + +#if defined(SDK_DELAY_USE_DWT) && defined(DWT) || (defined __XCC__) /* Use DWT for better accuracy */ + + enableCpuCycleCounter(); + /* Calculate the count ticks. */ + count += getCpuCycleCount(); + + if (count > UINT32_MAX) + { + count -= UINT32_MAX; + /* Wait for cyccnt overflow. */ + while (count < getCpuCycleCount()) + { + } + } + + /* Wait for cyccnt reach count value. */ + while (count > 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) || (defined __XCC__) */ +} diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c new file mode 100644 index 0000000000..2eea263e5f --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c @@ -0,0 +1,1395 @@ +/* + * Copyright 2017-2019 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_csi.h" +#if CSI_DRIVER_FRAG_MODE +#include "fsl_cache.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* 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 + +/*! + * @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 = base->CSIDMASA_FB2; + } + else + { + addr = base->CSIDMASA_FB1; + } + + return 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_CSICR1_FCC_MASK; + + if (config->useExtVsync) + { + reg |= CSI_CSICR1_EXT_VSYNC_MASK; + } + + base->CSICR1 = 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) + { + base->CSICR18 |= CSI_CSICR18_PARALLEL24_EN_MASK; + } + + if (kCSI_DataBus16Bit == config->dataBus) + { + base->CSICR3 |= CSI_CSICR3_TWO_8BIT_SENSOR_MASK; + } + + /* Image parameter. */ + base->CSIIMAG_PARA = + (((uint32_t)config->width * (uint32_t)busCyclePerPixel) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) | + ((uint32_t)(config->height) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT); + + /* The CSI frame buffer bus is 8-byte width. */ + base->CSIFBUF_PARA = (uint32_t)((config->linePitch_Bytes - imgWidth_Bytes) / 8U) + << CSI_CSIFBUF_PARA_FBUF_STRIDE_SHIFT; + + /* Enable auto ECC. */ + base->CSICR3 |= CSI_CSICR3_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))) + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + else if (0U == (imgWidth_Bytes % (8U * 8U))) + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + else + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((0U << CSI_CSICR3_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. */ + base->CSICR3 = 0U; + + /* Reset the fame count. */ + base->CSICR3 |= CSI_CSICR3_FRMCNT_RST_MASK; + while (0U != (base->CSICR3 & CSI_CSICR3_FRMCNT_RST_MASK)) + { + } + + /* Clear the RX FIFO. */ + CSI_ClearFifo(base, kCSI_AllFifo); + + /* Reflash DMA. */ + CSI_ReflashFifoDma(base, kCSI_AllFifo); + + /* Clear the status. */ + csisr = base->CSISR; + base->CSISR = csisr; + + /* Set the control registers to default value. */ + base->CSICR1 = CSI_CSICR1_HSYNC_POL_MASK | CSI_CSICR1_EXT_VSYNC_MASK; + base->CSICR2 = 0U; + base->CSICR3 = 0U; +#if defined(CSI_CSICR18_CSI_LCDIF_BUFFER_LINES) + base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU) | CSI_CSICR18_CSI_LCDIF_BUFFER_LINES(0x02U); +#else + base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU); +#endif + base->CSIFBUF_PARA = 0U; + base->CSIIMAG_PARA = 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) +{ + if (0U != index) + { + base->CSIDMASA_FB2 = addr; + } + else + { + base->CSIDMASA_FB1 = 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 = base->CSICR1; + base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK); + + if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo)) + { + mask |= CSI_CSICR1_CLR_RXFIFO_MASK; + } + + if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo)) + { + mask |= CSI_CSICR1_CLR_STATFIFO_MASK; + } + + base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK) | mask; + + /* Wait clear completed. */ + while (0U != (base->CSICR1 & mask)) + { + } + + /* Recover the FCC. */ + base->CSICR1 = 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_CSICR3_DMA_REFLASH_RFF_MASK; + } + + if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo)) + { + cr3 |= CSI_CSICR3_DMA_REFLASH_SFF_MASK; + } + + base->CSICR3 |= cr3; + + /* Wait clear completed. */ + while (0U != (base->CSICR3 & 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_CSICR3_DMA_REQ_EN_RFF_MASK; + } + + if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo)) + { + cr3 |= CSI_CSICR3_DMA_REQ_EN_SFF_MASK; + } + + if (enable) + { + base->CSICR3 |= cr3; + } + else + { + base->CSICR3 &= ~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) +{ + base->CSICR1 |= (mask & CSI_CSICR1_INT_EN_MASK); + base->CSICR3 |= (mask & CSI_CSICR3_INT_EN_MASK); + base->CSICR18 |= ((mask & CSI_CSICR18_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) +{ + base->CSICR1 &= ~(mask & CSI_CSICR1_INT_EN_MASK); + base->CSICR3 &= ~(mask & CSI_CSICR3_INT_EN_MASK); + base->CSICR18 &= ~((mask & CSI_CSICR18_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. + */ + base->CSICR18 = (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | CSI_CSICR18_MASK_OPTION(0) | + CSI_CSICR18_BASEADDR_SWITCH_SEL_MASK | CSI_CSICR18_BASEADDR_SWITCH_EN_MASK; + + /* Load the frame buffer to CSI register, there are at least two empty buffers. */ + base->CSIDMASA_FB1 = CSI_TransferGetEmptyBuffer(handle); + base->CSIDMASA_FB2 = 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 = base->CSICR1; + + base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK)); + + /* Save the empty frame buffer address to queue. */ + CSI_TransferPutEmptyBuffer(handle, frameBuffer); + + base->CSICR1 = 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 = base->CSICR1; + + base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK)); + + *frameBuffer = handle->frameBufferQueue[handle->queueReadIdx]; + + handle->queueReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueReadIdx); + + base->CSICR1 = 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 = base->CSISR; + + /* Clear the error flags. */ + base->CSISR = 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_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) == + (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) + { + ; /* Skip the frames. */ + } + else if (0U != (csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK))) + { + if (0U != (csisr & CSI_CSISR_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; + + 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_CSICR1_FCC_MASK; + + if (config->useExtVsync) + { + reg |= CSI_CSICR1_EXT_VSYNC_MASK; + } + + base->CSICR1 = reg; + + /* No stride. */ + base->CSIFBUF_PARA = 0; + + /* Enable auto ECC. */ + base->CSICR3 |= CSI_CSICR3_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))) + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + else if (0U == (imgWidth_Bytes % (8U * 8U))) + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + else + { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U); + base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((0U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + + base->CSIDMASA_FB1 = config->dmaBufferAddr0; + base->CSIDMASA_FB2 = 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. */ + base->CSIIMAG_PARA = + (((uint32_t)handle->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) | + ((uint32_t)(handle->linePerFrag) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT); + + /* + * Write to memory from first completed frame. + * DMA base addr switch at dma transfer done. + */ + base->CSICR18 = (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | CSI_CSICR18_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 = base->CSISR; + uint32_t dmaBufAddr; + uint16_t line; + pvoid_to_u32_t memSrc; + pvoid_to_u32_t memDest; + + /* Clear the error flags. */ + base->CSISR = 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. */ + base->CSICR3 |= (CSI_CSICR3_DMA_REFLASH_RFF_MASK | CSI_CSICR3_DMA_REQ_EN_RFF_MASK); + CSI_Start(base); + handle->dmaCurLine = 0; + handle->datCurWriteAddr = handle->outputBuffer; + } + else if ((csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) != 0U) + { + if ((csisr & CSI_CSISR_DMA_TSF_DONE_FB1_MASK) == CSI_CSISR_DMA_TSF_DONE_FB1_MASK) + { + dmaBufAddr = base->CSIDMASA_FB1; + } + else + { + dmaBufAddr = base->CSIDMASA_FB2; + } + + 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) +{ + s_csiIsr(CSI, s_csiHandle[0]); + SDK_ISR_EXIT_BARRIER; +} +#endif + +#if defined(CSI0) +void CSI0_DriverIRQHandler(void) +{ + s_csiIsr(CSI, s_csiHandle[0]); + SDK_ISR_EXIT_BARRIER; +} +#endif diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c new file mode 100644 index 0000000000..fa290939bd --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c @@ -0,0 +1,534 @@ +/* + * Copyright 2017-2019, 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); + +/******************************************************************************* + * 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; +} + +/*! + * 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 */ +} + +/*! + * 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 */ +} + +/*! + * 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; + config->powerDownOverVoltageDetection = true; + 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 | DCDC_REG0_PWD_HIGH_VOLT_DET_MASK | DCDC_REG0_PWD_CMP_BATT_DET_MASK | + 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 (config->powerDownOverVoltageDetection) + { + tmp32 |= DCDC_REG0_PWD_HIGH_VOLT_DET_MASK; + } + if (config->powerDownLowVlotageDetection) + { + tmp32 |= DCDC_REG0_PWD_CMP_BATT_DET_MASK; + } + 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)); + + config->enableOverloadDetection = true; + 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_EN_LP_OVERLOAD_SNS_MASK | DCDC_REG0_LP_HIGH_HYS_MASK | + DCDC_REG0_LP_OVERLOAD_FREQ_SEL_MASK | DCDC_REG0_LP_OVERLOAD_THRSH_MASK); + tmp32 |= DCDC_REG0_LP_OVERLOAD_FREQ_SEL(config->countChargingTimePeriod) | + DCDC_REG0_LP_OVERLOAD_THRSH(config->countChargingTimeThreshold); + if (config->enableOverloadDetection) + { + tmp32 |= DCDC_REG0_EN_LP_OVERLOAD_SNS_MASK; + } + 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; +} + +/*! + * 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; + } +} + +/*! + * 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; + * config->controlParameterMagnitude = 2U; + * config->integralProportionalRatio = 2U; + * 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; + config->controlParameterMagnitude = 2U; + config->integralProportionalRatio = 2U; +} + +/*! + * 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. */ + 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; + } + 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 | + DCDC_REG2_LOOPCTRL_DC_R_MASK | DCDC_REG2_LOOPCTRL_DC_C_MASK); + tmp32 |= DCDC_REG2_LOOPCTRL_DC_FF(config->complementFeedForwardStep) | + DCDC_REG2_LOOPCTRL_DC_R(config->controlParameterMagnitude) | + DCDC_REG2_LOOPCTRL_DC_C(config->integralProportionalRatio) | + 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; +} + +/*! + * 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) +{ + 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 settling 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 settling 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 settling 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 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; + + /* 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); + if (config->enableLoadResistor) + { + tmp32 |= DCDC_REG1_REG_RLOAD_SW_MASK; + } + base->REG1 = tmp32; +} + +/*! + * brief Boot DCDC into DCM(discontinous conduction mode). + * + * pwd_zcd=0x0; + * pwd_cmp_offset=0x0; + * dcdc_loopctrl_en_rcscale=0x3 or 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(0x4U) | + 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/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c new file mode 100644 index 0000000000..4477406a73 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c @@ -0,0 +1,1461 @@ +/* + * Copyright 2017-2019 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_dcp.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.dcp" +#endif + +#ifndef DCP_USE_DCACHE +#define DCP_USE_DCACHE 0 +#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) */ + +/*! 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 uint32_t *DCP_FindCacheLine(uint8_t *dcpWorkExt) +{ + while ((uint32_t)dcpWorkExt & (FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1)) + dcpWorkExt++; + return (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 */ + SCB_CleanDCache_by_Addr((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 *)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 *)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 *)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 *)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; + } + +#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U) + else if ((uint32_t)ctxInternal & (FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1)) + { + /* ctx must be cache line aligned when using DCACHE */ + return kStatus_InvalidArgument; + } +#endif + + 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 */ + SCB_CleanDCache_by_Addr((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 */ + SCB_CleanDCache_by_Addr((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 *)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) + { + (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; + /* 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 = (dcp_hash_ctx_internal_t *)(uint32_t)ctx; + 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; + + if (inputSize == 0U) + { + return kStatus_Success; + } + + ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx; + 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; + + ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx; + 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) + SCB_InvalidateDCache_by_Addr(ctx, sizeof(dcp_hash_ctx_t)); +#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) +{ + /* Use extended DCACHE line size aligned structure */ +#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U) + dcp_hash_ctx_t *hashCtx; + uint8_t hashCtxExt[sizeof(dcp_hash_ctx_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U}; + hashCtx = (dcp_hash_ctx_t *)DCP_FindCacheLine(hashCtxExt); +#else + dcp_hash_ctx_t hashCtxStruct = {0}; + dcp_hash_ctx_t *hashCtx = &hashCtxStruct; +#endif + + 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/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c new file mode 100644 index 0000000000..8bfbe6c367 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/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/nxp/devices/MIMXRT1052/drivers/fsl_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c new file mode 100644 index 0000000000..e74334bc5a --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c @@ -0,0 +1,2849 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_edma.h" + +/******************************************************************************* + * 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 = 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 = 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); + + 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 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 type 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 type, 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], type, 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(true); + 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 STCD 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 */ + tcd->SADDR = config->srcAddr; + /* destination address */ + tcd->DADDR = config->destAddr; + /* 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) + { + tcd->DLAST_SGA = (uint32_t)nextTcd; + /* + 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 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 type 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 type, uint32_t linkedChannel) +{ + assert(tcd != NULL); + assert(((uint32_t)tcd & 0x1FU) == 0U); + assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL); + + if (type == 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 (type == 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. */ + handle->header = 0; + handle->tail = 0; + 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)); + + config->destAddr = (uint32_t)(uint32_t *)destAddr; + config->srcAddr = (uint32_t)(uint32_t *)srcAddr; + 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 type 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 type) +{ + assert(config != NULL); + + int16_t srcOffset = 0, destOffset = 0; + + switch (type) + { + 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 */ + 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); + 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 (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd]) + { + /* 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 (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 != 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; + + /* Handle the tcd */ + if (handle->tcdPool != NULL) + { + handle->header = 0; + 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 = handle->base->TCD[handle->channel].DLAST_SGA; + uint32_t sga_index; + int32_t tcds_done; + uint8_t new_header; + + /* Get the offset of the next transfer TCD blocks to be loaded into the eDMA engine. */ + sga -= (uint32_t)handle->tcdPool; + /* 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; + + if (tmpTcdUsed == tmpTcdSize) + { + 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; + } + } + /* 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); + } + + /* clear the DONE bit here is meaningful for below cases: + *1.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.A new TCD has not been loaded to EDMA: + * for the case that transfer request occur in the privious edma callback, this is a case that doesn't + * need scatter gather, so keep DONE bit during the next transfer request will re-install the TCD. + */ + if (transfer_done) + { + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) && !(defined(DMA1)) +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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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_0_16_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 DMA0_1_17_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 DMA0_2_18_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 DMA0_3_19_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 DMA0_4_20_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 DMA0_5_21_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 DMA0_6_22_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 DMA0_7_23_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 DMA0_8_24_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 DMA0_9_25_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 DMA0_10_26_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 DMA0_11_27_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 DMA0_12_28_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 DMA0_13_29_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 DMA0_14_30_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 DMA0_15_31_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; +} + +void DMA1_0_16_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[32]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[48]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_1_17_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[33]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[49]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_2_18_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[34]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[50]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_3_19_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[35]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[51]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_4_20_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[36]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[52]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_5_21_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[37]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[53]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_6_22_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[38]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[54]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_7_23_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[39]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[55]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_8_24_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[40]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[56]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_9_25_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[41]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[57]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_10_26_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[42]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[58]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_11_27_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[43]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[59]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_12_28_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[44]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[60]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_13_29_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[45]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[61]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_14_30_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[46]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[62]); + } + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_15_31_DriverIRQHandler(void) +{ + if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[47]); + } + if ((EDMA_GetChannelStatusFlags(DMA1, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U) + { + EDMA_HandleIRQ(s_EDMAHandle[63]); + } + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + EDMA_HandleIRQ(s_EDMAHandle[0]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA1_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[1]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA2_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[2]); + SDK_ISR_EXIT_BARRIER; +} + +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) +{ + EDMA_HandleIRQ(s_EDMAHandle[4]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA5_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[5]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA6_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[6]); + SDK_ISR_EXIT_BARRIER; +} + +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) +{ + EDMA_HandleIRQ(s_EDMAHandle[8]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA9_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[9]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA10_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[10]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA11_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[11]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA12_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[12]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA13_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[13]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA14_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[14]); + SDK_ISR_EXIT_BARRIER; +} + +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) +{ + EDMA_HandleIRQ(s_EDMAHandle[16]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA17_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[17]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA18_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[18]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA19_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[19]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA20_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[20]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA21_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[21]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA22_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[22]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA23_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[23]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA24_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[24]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA25_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[25]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA26_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[26]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA27_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[27]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA28_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[28]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA29_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[29]); + SDK_ISR_EXIT_BARRIER; +} + +void DMA30_DriverIRQHandler(void) +{ + EDMA_HandleIRQ(s_EDMAHandle[30]); + SDK_ISR_EXIT_BARRIER; +} + +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/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c new file mode 100644 index 0000000000..ab9f63f912 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c @@ -0,0 +1,386 @@ +/* + * Copyright 2017-2019 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(LCDIF_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Pointers to ELCDIF bases for each instance. */ +static LCDIF_Type *const s_elcdifBases[] = LCDIF_BASE_PTRS; + +#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(LCDIF_Type *base) +{ + 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) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + uint32_t instance = ELCDIF_GetInstance(base); + /* Enable the clock. */ + CLOCK_EnableClock(s_elcdifApbClocks[instance]); +#if defined(LCDIF_PERIPH_CLOCKS) + 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->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 = config->bufferAddr; + base->NEXT_BUF = 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) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + uint32_t instance = ELCDIF_GetInstance(base); +/* Disable the clock. */ +#if defined(LCDIF_PERIPH_CLOCKS) + CLOCK_DisableClock(s_elcdifPixClocks[instance]); +#endif + 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) && 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 = config->bufferAddr; + base->AS_NEXT_BUF = 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) && 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/nxp/devices/MIMXRT1052/drivers/fsl_enc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c new file mode 100644 index 0000000000..8117df1332 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 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) +#define ENC_CTRL2_W1C_FLAGS (ENC_CTRL2_SABIRQ_MASK | ENC_CTRL2_ROIRQ_MASK | ENC_CTRL2_RUIRQ_MASK) + +/******************************************************************************* + * 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; + + /* 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; + * 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; +} + +/*! + * 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 (0U != (ENC_CTRL2_SABIRQ_MASK & base->CTRL2)) + { + ret32 |= (uint32_t)kENC_SimultBothPhaseChangeFlag; + } + 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 (0U != ((uint32_t)kENC_SimultBothPhaseChangeFlag & mask)) + { + tmp16 |= ENC_CTRL2_SABIRQ_MASK; + } + 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 (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask)) + { + tmp16 |= ENC_CTRL2_SABIE_MASK; + } + 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 (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask)) + { + tmp16 |= ENC_CTRL2_SABIE_MASK; + } + 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 (0U != (ENC_CTRL2_SABIE_MASK & base->CTRL2)) + { + ret32 |= (uint32_t)kENC_SimultBothPhaseChangeInterruptEnable; + } + 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/nxp/devices/MIMXRT1052/drivers/fsl_enet.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c new file mode 100644 index 0000000000..2e9d229a18 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c @@ -0,0 +1,3389 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 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 Ethernet VLAN header length. */ +#define ENET_FRAME_VLAN_TAGLEN 4U +/*! @brief MDC frequency. */ +#define ENET_MDC_FREQUENCY 2500000U +/*! @brief NanoSecond in one second. */ +#define ENET_NANOSECOND_ONE_SECOND 1000000000U +/*! @brief Define a common clock cycle delays used for time stamp capture. */ +#ifndef ENET_1588TIME_DELAY_COUNT +#define ENET_1588TIME_DELAY_COUNT 10U +#endif + +/*! @brief Define the ENET ring/class bumber . */ +enum +{ + kENET_Ring0 = 0U, /*!< ENET ring/class 0. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + kENET_Ring1 = 1U, /*!< ENET ring/class 1. */ + kENET_Ring2 = 2U /*!< ENET ring/class 2. */ +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +}; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Pointers to enet clocks for each instance. */ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +const clock_ip_name_t s_enetClock[] = ENET_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to enet transmit IRQ number for each instance. */ +static const IRQn_Type s_enetTxIrqId[] = ENET_Transmit_IRQS; +/*! @brief Pointers to enet receive IRQ number for each instance. */ +static const IRQn_Type s_enetRxIrqId[] = ENET_Receive_IRQS; +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! @brief Pointers to enet timestamp IRQ number for each instance. */ +static const IRQn_Type s_enetTsIrqId[] = ENET_1588_Timer_IRQS; +#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G) +/*! @brief Pointers to enet 1588 timestamp IRQ number for each instance. */ +static const IRQn_Type s_enet1588TimerIrqId[] = ENET_1588_Timer_IRQS; +#endif +#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)]; +#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G) +static enet_isr_t s_enet1588TimerIsr[ARRAY_SIZE(s_enetBases)]; +#endif + +/******************************************************************************* + * 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); + +/*! + * @brief Set ENET MAC transmit buffer descriptors. + * + * @param handle The ENET handle pointer. + * @param config The ENET configuration structure. + * @param bufferConfig The ENET buffer configuration. + */ +static void ENET_SetTxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig); + +/*! + * @brief Set ENET MAC receive buffer descriptors. + * + * @param handle The ENET handle pointer. + * @param config The ENET configuration structure. + * @param bufferConfig The ENET buffer configuration. + */ +static void ENET_SetRxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig); + +/*! + * @brief Updates the ENET read buffer descriptors. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param ringId The descriptor ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1. + */ +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId); + +/******************************************************************************* + * 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. + */ +void 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(config->ringNum <= (uint8_t)FSL_FEATURE_ENET_QUEUE); + + /* Initializes the ENET transmit buffer descriptors. */ + ENET_SetTxBufferDescriptors(handle, config, bufferConfig); + + /* Initializes the ENET receive buffer descriptors. */ + ENET_SetRxBufferDescriptors(handle, config, bufferConfig); + + /* Initializes the ENET MAC controller with basic function. */ + ENET_SetMacController(base, handle, config, bufferConfig, macAddr, srcClock_Hz); + + /* Set all buffers or data in handler for data transmit/receive process. */ + ENET_SetHandler(base, handle, config, bufferConfig); +} + +/*! + * brief 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. + */ +void ENET_Init(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + uint32_t instance = ENET_GetInstance(base); + + /* Ungate ENET clock. */ + (void)CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + /* Reset ENET module. */ + ENET_Reset(base); + + 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) +{ + /* Disable interrupt. */ + base->EIMR = 0; + + /* Disable ENET. */ + base->ECR &= ~ENET_ECR_ETHEREN_MASK; +} + +/*! + * brief Deinitializes the ENET module. + + * This function gates the module clock, clears ENET interrupts, and disables the ENET module. + * + * param base ENET peripheral base address. + */ +void ENET_Deinit(ENET_Type *base) +{ + ENET_Down(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disables the clock source. */ + (void)CLOCK_DisableClock(s_enetClock[ENET_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Sets the callback function. + * This API is provided for the application callback required case when ENET + * interrupt is enabled. This API should be called after calling ENET_Init. + * + * param handle ENET handler pointer. Should be provided by application. + * param callback The ENET callback function. + * param userData The callback function parameter. + */ +void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData) +{ + assert(handle != 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]); +} + +#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G) +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 +#endif + +static void ENET_SetHandler(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + uint8_t count; + uint32_t instance = ENET_GetInstance(base); + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Store transfer parameters in handle pointer. */ + (void)memset(handle, 0, sizeof(enet_handle_t)); + + handle->ringNum = + (config->ringNum > (uint8_t)FSL_FEATURE_ENET_QUEUE) ? (uint8_t)FSL_FEATURE_ENET_QUEUE : config->ringNum; + for (count = 0; count < handle->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++; + } + + /* 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 + /* 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)) + { + maxFrameLen = (ENET_FRAME_MAX_FRAMELEN + ENET_FRAME_VLAN_TAGLEN); +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + 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 (config->miiMode == kENET_RgmiiMode) + { + rcr |= ENET_RCR_RGMII_EN_MASK; + rcr &= ~ENET_RCR_MII_MODE_MASK; + } + else + { + rcr &= ~ENET_RCR_RGMII_EN_MASK; +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + rcr |= ENET_RCR_MII_MODE_MASK; + if (config->miiMode == kENET_RmiiMode) + { + rcr |= ENET_RCR_RMII_MODE_MASK; + } +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + /* Speed. */ + if (config->miiSpeed == kENET_MiiSpeed10M) + { + rcr |= ENET_RCR_RMII_10T_MASK; + } +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (config->miiSpeed == kENET_MiiSpeed1000M) + { + ecr |= ENET_ECR_SPEED_MASK; + } + else + { + ecr &= ~ENET_ECR_SPEED_MASK; + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + /* Receive setting for half duplex. */ + if (config->miiDuplex == kENET_MiiHalfDuplex) + { + rcr |= ENET_RCR_DRT_MASK; + } + /* Sets internal loop only for MII mode. */ + if ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlMIILoopEnable)) && + (config->miiMode != kENET_RmiiMode)) + { + rcr |= ENET_RCR_LOOP_MASK; + rcr &= ~ENET_RCR_DRT_MASK; + } + base->RCR = rcr; + + /* Configures MAC transmit controller: duplex mode, mac address insertion. */ + tcr = base->TCR & ~(ENET_TCR_FDEN_MASK | ENET_TCR_ADDINS_MASK); + tcr |= ((kENET_MiiHalfDuplex != config->miiDuplex) ? (uint32_t)ENET_TCR_FDEN_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlMacAddrInsert)) ? (uint32_t)ENET_TCR_ADDINS_MASK : 0U); + base->TCR = tcr; + + /* Configures receive and transmit accelerator. */ + base->TACC = config->txAccelerConfig; + base->RACC = config->rxAccelerConfig; + + /* Sets the pause duration and FIFO threshold for the flow control enabled case. */ + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) + { + uint32_t reemReg; + base->OPD = config->pauseDuration; + reemReg = ENET_RSEM_RX_SECTION_EMPTY(config->rxFifoEmptyThreshold); +#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD + reemReg |= ENET_RSEM_STAT_SECTION_EMPTY(config->rxFifoStatEmptyThreshold); +#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */ + base->RSEM = reemReg; + } + + /* FIFO threshold setting for store and forward enable/disable case. */ + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlStoreAndFwdDisable)) + { + /* Transmit fifo watermark settings. */ + configVal = ((uint32_t)config->txFifoWatermark) & ENET_TFWR_TFWR_MASK; + base->TFWR = configVal; + /* Receive fifo full threshold settings. */ + configVal = ((uint32_t)config->rxFifoFullThreshold) & ENET_RSFL_RX_SECTION_FULL_MASK; + base->RSFL = configVal; + } + else + { + /* Transmit fifo watermark settings. */ + base->TFWR = ENET_TFWR_STRFWD_MASK; + base->RSFL = 0; + } + + /* Enable store and forward when accelerator is enabled */ + if (0U != + (config->txAccelerConfig & ((uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled))) + { + base->TFWR = ENET_TFWR_STRFWD_MASK; + } + if (0U != ((config->rxAccelerConfig & + ((uint32_t)kENET_RxAccelIpCheckEnabled | (uint32_t)kENET_RxAccelProtoCheckEnabled)))) + { + base->RSFL = 0; + } + +/* Initializes the ring 0. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR = (uint32_t)bufferConfig->txBdStartAddrAlign; + base->RDSR = (uint32_t)bufferConfig->rxBdStartAddrAlign; +#endif + base->MRBR = (uint32_t)bufferConfig->rxBuffSizeAlign; + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + const enet_buffer_config_t *buffCfg = bufferConfig; + + if (config->ringNum > 1U) + { + /* Initializes the ring 1. */ + buffCfg++; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR1 = (uint32_t)buffCfg->txBdStartAddrAlign; + base->RDSR1 = (uint32_t)buffCfg->rxBdStartAddrAlign; +#endif + base->MRBR1 = (uint32_t)buffCfg->rxBuffSizeAlign; + /* Enable the DMAC for ring 1 and with no rx classification set. */ + base->DMACFG[0] = ENET_DMACFG_DMA_CLASS_EN_MASK; + } + if (config->ringNum > 2U) + { + /* Initializes the ring 2. */ + buffCfg++; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR2 = (uint32_t)buffCfg->txBdStartAddrAlign; + base->RDSR2 = (uint32_t)buffCfg->rxBdStartAddrAlign; +#endif + base->MRBR2 = (uint32_t)buffCfg->rxBuffSizeAlign; + /* Enable the DMAC for ring 2 and with no rx classification set. */ + base->DMACFG[1] = ENET_DMACFG_DMA_CLASS_EN_MASK; + } + + /* Default the class/ring 1 and 2 are not enabled and the receive classification is disabled + * so we set the default transmit scheme with the round-robin mode. beacuse the legacy bd mode + * only support the round-robin mode. if the avb feature is required, just call the setup avb + * feature API. */ + base->QOS |= ENET_QOS_TX_SCHEME(1); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + /* Configures the Mac address. */ + ENET_SetMacAddr(base, macAddr); + + /* Initialize the SMI if uninitialized. */ + if (!ENET_GetSMI(base)) + { + ENET_SetSMI(base, srcClock_Hz, + ((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 + if (NULL != config->intCoalesceCfg) + { + uint32_t intMask = (ENET_EIMR_TXB_MASK | ENET_EIMR_RXB_MASK); + +#if FSL_FEATURE_ENET_QUEUE > 1 + uint8_t queue = 0; + intMask |= ENET_EIMR_TXB2_MASK | ENET_EIMR_RXB2_MASK | ENET_EIMR_TXB1_MASK | ENET_EIMR_RXB1_MASK; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + /* Clear all buffer interrupts. */ + base->EIMR &= ~intMask; + +/* Set the interrupt coalescence. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + for (queue = 0; queue < (uint8_t)FSL_FEATURE_ENET_QUEUE; queue++) + { + base->TXIC[queue] = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[queue]) | + config->intCoalesceCfg->txCoalesceTimeCount[queue] | ENET_TXIC_ICCS_MASK | + ENET_TXIC_ICEN_MASK; + base->RXIC[queue] = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[queue]) | + config->intCoalesceCfg->rxCoalesceTimeCount[queue] | ENET_RXIC_ICCS_MASK | + ENET_RXIC_ICEN_MASK; + } +#else + base->TXIC = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[0]) | + config->intCoalesceCfg->txCoalesceTimeCount[0] | ENET_TXIC_ICCS_MASK | ENET_TXIC_ICEN_MASK; + base->RXIC = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[0]) | + config->intCoalesceCfg->rxCoalesceTimeCount[0] | ENET_RXIC_ICCS_MASK | ENET_RXIC_ICEN_MASK; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } +#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */ + ENET_EnableInterrupts(base, config->interrupt); + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Sets the 1588 enhanced feature. */ + ecr |= ENET_ECR_EN1588_MASK; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* Enables Ethernet module after all configuration except the buffer descriptor active. */ + ecr |= ENET_ECR_ETHEREN_MASK | ENET_ECR_DBSWP_MASK; + base->ECR = ecr; +} + +static void ENET_SetTxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint16_t count; + uint32_t txBuffSizeAlign; + uint8_t *txBuffer = NULL; + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Check the input parameters. */ + for (ringNum = 0; ringNum < config->ringNum; ringNum++) + { + if (buffCfg->txBdStartAddrAlign != NULL) + { + volatile enet_tx_bd_struct_t *curBuffDescrip = buffCfg->txBdStartAddrAlign; + txBuffSizeAlign = buffCfg->txBuffSizeAlign; + + if (buffCfg->txBufferAlign != NULL) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + txBuffer = + (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBufferAlign, kMEMORY_Local2DMA); +#else + txBuffer = buffCfg->txBufferAlign; +#endif + } + + for (count = 0; count < buffCfg->txBdNumber; count++) + { + if (buffCfg->txBufferAlign != NULL) + { + /* Set data buffer address. */ + curBuffDescrip->buffer = (uint8_t *)((uint32_t)&txBuffer[count * txBuffSizeAlign]); + } + /* Initializes data length. */ + curBuffDescrip->length = 0; + /* Sets the crc. */ + curBuffDescrip->control = ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK; + /* Sets the last buffer descriptor with the wrap flag. */ + if (count == (buffCfg->txBdNumber - 1U)) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_WRAP_MASK; + } + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Enable transmit interrupt for store the transmit timestamp. */ + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK; +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + /* Set the type of the frame when the credit-based scheme is used. */ + curBuffDescrip->controlExtend1 |= (uint16_t)(ENET_BD_FTYPE(ringNum)); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* Increase the index. */ + curBuffDescrip++; + } + } + buffCfg++; + } +} + +static void ENET_SetRxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint16_t count; + uint16_t rxBuffSizeAlign; + uint8_t *rxBuffer; + const enet_buffer_config_t *buffCfg = bufferConfig; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint32_t mask = ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Check the input parameters. */ + for (ringNum = 0; ringNum < config->ringNum; ringNum++) + { + assert(buffCfg->rxBuffSizeAlign >= ENET_RX_MIN_BUFFERSIZE); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +#if FSL_FEATURE_ENET_QUEUE > 1 + if (ringNum == 1U) + { + mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt); + } + else if (ringNum == 2U) + { + mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt); + } + else + { + /* Intentional empty */ + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + if ((buffCfg->rxBdStartAddrAlign != NULL) && (buffCfg->rxBufferAlign != NULL)) + { + volatile enet_rx_bd_struct_t *curBuffDescrip = buffCfg->rxBdStartAddrAlign; + rxBuffSizeAlign = buffCfg->rxBuffSizeAlign; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + rxBuffer = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBufferAlign, kMEMORY_Local2DMA); +#else + rxBuffer = buffCfg->rxBufferAlign; +#endif + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (buffCfg->rxMaintainEnable) + { + /* Invalidate rx buffers before DMA transfer data into them. */ + DCACHE_InvalidateByRange((uint32_t)rxBuffer, ((uint32_t)buffCfg->rxBdNumber * rxBuffSizeAlign)); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + for (count = 0; count < buffCfg->rxBdNumber; count++) + { + /* Set data buffer and the length. */ + curBuffDescrip->buffer = (uint8_t *)((uint32_t)&rxBuffer[count * rxBuffSizeAlign]); + curBuffDescrip->length = 0; + + /* Initializes the buffer descriptors with empty bit. */ + curBuffDescrip->control = ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + /* Sets the last buffer descriptor with the wrap flag. */ + if (count == (buffCfg->rxBdNumber - 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 Activates ENET send for multiple tx rings. + * @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_QUEUE - 1. + * + */ +static void ENET_ActiveSend(ENET_Type *base, uint8_t ringId) +{ + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + 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 + 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. Normally it's the system clock. See clock distribution. + * param isPreambleDisabled The preamble disable flag. + * - true Enables the preamble. + * - false Disables the preamble. + */ +void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled) +{ + assert((srcClock_Hz / (2U * ENET_MDC_FREQUENCY)) != 0U); + + uint32_t clkCycle = 0; + uint32_t speed = 0; + uint32_t mscr = 0; + + /* Calculate the MII speed which controls the frequency of the MDC. */ + speed = srcClock_Hz / (2U * ENET_MDC_FREQUENCY) - 1U; + /* Calculate the hold time on the MDIO output. */ + clkCycle = (10U + ENET_NANOSECOND_ONE_SECOND / srcClock_Hz - 1U) / (ENET_NANOSECOND_ONE_SECOND / srcClock_Hz) - 1U; + /* Build the configuration for MDC/MDIO control. */ + mscr = + ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0U); + base->MSCR = mscr; +} + +/*! + * brief Starts an SMI write command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. Range from 0 ~ 31. + * param operation The write operation. + * param data The data written to PHY. + */ +void ENET_StartSMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_write_t operation, uint32_t data) +{ + uint32_t mmfr = 0; + + /* Build MII write command. */ + mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | + ENET_MMFR_TA(2U) | (data & 0xFFFFU); + base->MMFR = mmfr; +} + +/*! + * brief Starts an SMI (Serial Management Interface) read command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. Range from 0 ~ 31. + * param operation The read operation. + */ +void ENET_StartSMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_read_t operation) +{ + uint32_t mmfr = 0; + + /* Build MII read command. */ + mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | ENET_MMFR_TA(2U); + base->MMFR = mmfr; +} + +#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write command. + * deprecated Do not use this function. It has been superceded by @ref ENET_StartExtC45SMIWriteReg and + * ENET_StartExtC45SMIWriteData. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + * param data The data written to PHY. + */ +void ENET_StartExtC45SMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU); + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write firstly. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr); + base->MMFR = mmfr; + + /* Build MII write command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(data); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read command. + * deprecated Do not use this function. It has been superceded by @ref ENET_StartExtC45SMIWriteReg and + * ENET_StartExtC45SMIReadData. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU); + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write firstly. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr); + base->MMFR = mmfr; + + /* Build MII read command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write register command. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIWriteReg(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO write. + * code + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteData(base, phyAddr, phyReg, data); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * endcode + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + * param data The data written to PHY. + */ +void ENET_StartExtC45SMIWriteData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + + /* Build MII write command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(data); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO read. + * code + * uint32_t data; + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIReadData(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * data = ENET_ReadSMIData(base); + * endcode + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIReadData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + + /* Build MII read command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2); + base->MMFR = mmfr; +} +#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */ + +static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max) +{ + /* 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_QUEUE - 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 is 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 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 update the + * receive buffers if the result is not "kStatus_ENET_RxFrameEmpty". + * + * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * param length The length of the valid frame received. + * 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 that 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 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(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + uint32_t len = 0; + uint32_t offset = 0; + uint16_t control; + bool isLastBuff = false; + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + uint16_t index = rxBdRing->rxGenIdx; + status_t result = kStatus_Success; + uint32_t address; + uint32_t dest; + + /* For data-NULL input, only update the buffer descriptor. */ + if (data == NULL) + { + do + { + /* Update the control flag. */ + control = curBuffDescrip->control; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + + /* Find the last buffer descriptor for the frame. */ + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + break; + } + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } while (index != rxBdRing->rxGenIdx); + } + else + { + while (!isLastBuff) + { +/* A frame on one buffer or several receive buffers are both considered. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + dest = (uint32_t)data + offset; + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* This is a valid frame. */ + isLastBuff = true; + if (length == curBuffDescrip->length) + { + /* Copy the frame to user's buffer without FCS. */ + len = curBuffDescrip->length - offset; + (void)memcpy((uint32_t *)dest, (uint32_t *)address, len); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Get the timestamp if the ts isn't NULL. */ + if (ts != NULL) + { + *ts = curBuffDescrip->timestamp; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + break; + } + else + { + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + } + } + else + { + /* Store a frame on several buffer descriptors. */ + isLastBuff = false; + /* Length check. */ + if (offset >= length) + { + result = kStatus_ENET_RxFrameFail; + break; + } + (void)memcpy((uint32_t *)dest, (uint32_t *)address, handle->rxBuffSizeAlign[ringId]); + offset += handle->rxBuffSizeAlign[ringId]; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + } + + /* Get the current buffer descriptor. */ + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } + } + + return result; +} + +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + volatile enet_rx_bd_struct_t *curBuffDescrip = + handle->rxBdRing[ringId].rxBdBase + handle->rxBdRing[ringId].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. */ + handle->rxBdRing[ringId].rxGenIdx = + ENET_IncreaseIndex(handle->rxBdRing[ringId].rxGenIdx, handle->rxBdRing[ringId].rxRingLen); + + /* 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); + base->RDAR = ENET_RDAR_RDAR_MASK; + break; + } +} + +/*! + * 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. + * + * + * 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(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; + uint32_t address; + status_t result = kStatus_Success; + uint32_t src; + uint32_t configVal; + bool isReturn = false; + + /* Check the frame length. */ + if (length > ENET_FRAME_MAX_FRAMELEN) + { + result = kStatus_ENET_TxFrameOverLen; + } + else + { + /* Check if the transmit buffer is ready. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if ((handle->TxReclaimEnable[ringId]) && !ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* One transmit buffer is enough for one frame. */ + if (handle->txBuffSizeAlign[ringId] >= length) + { + /* Copy data to the buffer for uDMA transfer. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + (void)memcpy((void *)(uint32_t *)address, (const void *)(uint32_t *)(uint32_t)data, length); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + DCACHE_CleanByRange(address, length); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Set data length. */ + curBuffDescrip->length = (uint16_t)length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Increase the buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + /* Add context to frame info ring */ + if (handle->TxReclaimEnable[ringId]) + { + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + txBdRing->txDescUsed++; + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Update the size left to be transmit. */ + sizeleft = length - len; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + src = (uint32_t)data + len; + if (sizeleft > handle->txBuffSizeAlign[ringId]) + { + /* Data copy. */ + (void)memcpy((uint32_t *)address, (uint32_t *)src, handle->txBuffSizeAlign[ringId]); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Data length update. */ + curBuffDescrip->length = handle->txBuffSizeAlign[ringId]; + len += handle->txBuffSizeAlign[ringId]; + /* Sets the control flag. */ + configVal = (uint32_t)curBuffDescrip->control; + configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + curBuffDescrip->control = (uint16_t)configVal; + + if (handle->TxReclaimEnable[ringId]) + { + txBdRing->txDescUsed++; + } + /* Active the transmit buffer descriptor*/ + ENET_ActiveSend(base, ringId); + } + else + { + (void)memcpy((uint32_t *)address, (uint32_t *)src, sizeleft); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, sizeleft); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + curBuffDescrip->length = (uint16_t)sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + + if (handle->TxReclaimEnable[ringId]) + { + /* Add context to frame info ring */ + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + txBdRing->txDescUsed++; + } + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + isReturn = true; + break; + } + /* Increase and get the current buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + 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. + */ +static void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId) +{ + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + 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; + + /* 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 + 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 each 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 */ + } + + /* Clean the txDirty pointer after used */ + if (txDirty != NULL) + { + txDirty = NULL; + } + txBdRing->txDescUsed--; + + /* Update the index. */ + txBdRing->txConsumIdx = ENET_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen); + curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx; + } +} + +/*! + * brief Get a receive buffer pointer of the ENET device for specified ring. + * + * 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_QUEUE - 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) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + assert(handle->rxBdRing[ringId].rxBdBase != NULL); + + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + uint32_t address; + + /* Check if current rx BD is under usage by certain application */ + /* Buffer owner flag, 1: owned by application, 0: owned by driver */ + if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK) == 0U) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK; + } + else + { + return kStatus_ENET_RxFrameFail; + } + +/* A frame on one buffer or several receive buffers are both considered. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + *buffer = (void *)(uint32_t *)address; + *length = curBuffDescrip->length; + + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* This is a valid frame. */ + *isLastBuff = true; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (ts != NULL) + { + *ts = curBuffDescrip->timestamp; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + } + else + { + *isLastBuff = false; + } + + /* Increase current buffer descriptor to the next one. */ + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + return kStatus_Success; +} + +/*! + * brief Release receive buffer descriptor to DMA. + * + * 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_QUEUE - 1. + */ +void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + enet_rx_bd_struct_t *ownBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase; + enet_rx_bd_struct_t *blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + enet_rx_bd_struct_t tempBuffDescrip; + uint16_t index = rxBdRing->rxGenIdx; + bool isReleaseBd = false; + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + + do + { + /* Find the BD for releasing, do nothing if it's not owned by application. */ + if (buffer == ownBuffDescrip->buffer) + { + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)) + { + isReleaseBd = true; + break; + } + } + + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + break; + } + ownBuffDescrip++; + } while (true); + + if (isReleaseBd) + { + /* Find the first BD owned by application after rxBdCurrent, isReleaseBd is true so there's at least one BD is + * owned by application */ + do + { + if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)) + { + break; + } + if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase; + } + else + { + blockBuffDescrip++; + } + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + } while (index != rxBdRing->rxGenIdx); + + /* If the BD ready for releasing isn't the first BD owned by application after rxBdCurrent then exchange the two + * BDs */ + if (blockBuffDescrip != ownBuffDescrip) + { + /* Exchange buffer descriptor content */ + tempBuffDescrip = *ownBuffDescrip; + *ownBuffDescrip = *blockBuffDescrip; + *blockBuffDescrip = tempBuffDescrip; + + /* Maintain the wrap flag */ + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + ownBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK); + blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + else if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + blockBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK); + ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + else + { + /* Intentional empty */ + } + + /* Clears status including the owner flag. */ + blockBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + } + else + { + /* Clears status including the owner flag. */ + ownBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + } + + /* Ensure previous data update is completed with Data Synchronization Barrier before activing Rx BD. */ + __DSB(); + + /* Actives the receive buffer descriptor. */ + base->RDAR = ENET_RDAR_RDAR_MASK; + } +} + +/*! + * brief Transmits an ENET frame for specified ring with zero-copy. + * note The CRC is automatically appended to the data. Input the data + * to send without the CRC. The frame must store in continuous memeory + * 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) +{ + assert(handle != NULL); + assert(data != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + enet_frame_info_t *txDirty = NULL; + uint32_t len = 0; + uint32_t sizeleft = 0; + status_t result = kStatus_Success; + uint8_t *data_temp; + uint32_t configVal; + bool isReturn = false; + + /* Check the frame length. */ + if (length > ENET_FRAME_MAX_FRAMELEN) + { + result = kStatus_ENET_TxFrameOverLen; + } + else + { + /* Check if the transmit buffer is ready. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if (handle->TxReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* One transmit buffer is enough for one frame. */ + if (handle->txBuffSizeAlign[ringId] >= length) + { + /* Copy data to the buffer for uDMA transfer. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + curBuffDescrip->buffer = (uint8_t *)(uint32_t)data; + /* Set data length. */ + curBuffDescrip->length = (uint16_t)length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Increase the buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + /* Add context to frame info ring */ + if (handle->TxReclaimEnable[ringId]) + { + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + txBdRing->txDescUsed++; + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Update the size left to be transmit. */ + sizeleft = length - len; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + data_temp = (uint8_t *)(uint32_t)data + len; + if (sizeleft > handle->txBuffSizeAlign[ringId]) + { + /* Data copy. */ + curBuffDescrip->buffer = data_temp; + /* Data length update. */ + curBuffDescrip->length = handle->txBuffSizeAlign[ringId]; + len += handle->txBuffSizeAlign[ringId]; + /* Sets the control flag. */ + configVal = (uint32_t)curBuffDescrip->control; + configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + curBuffDescrip->control = (uint16_t)configVal; + + if (handle->TxReclaimEnable[ringId]) + { + txBdRing->txDescUsed++; + } + /* Active the transmit buffer descriptor*/ + ENET_ActiveSend(base, ringId); + } + else + { + curBuffDescrip->buffer = data_temp; + curBuffDescrip->length = (uint16_t)sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + + if (handle->TxReclaimEnable[ringId]) + { + /* Add context to frame info ring */ + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + txBdRing->txDescUsed++; + } + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + isReturn = true; + break; + } + /* Increase and get the current buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + + } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)); + + if (isReturn == false) + { + result = kStatus_ENET_TxFrameBusy; + } + } + } + } + return result; +} + +/*! + * brief Set up ENET Tx buffer descriptor, preparing for one frame stores in scattered buffer. + * This function only set one Tx BD everytime calls, all ready data will be sent out with last flag sets or + * gets error. Send frame succeeds with last flag sets, then you can get context from frameInfo in callback. + * note The CRC is automatically appended to the data. Input the data to send without the CRC. And if doesn't + * succeed to call this function, user can't get context in frameInfo of callback. + * + * + * 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, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1. + * param txFlag This function uses timestamp enable flag, last BD flag. + * param context Used by user to handle some events after transmit over. + * retval kStatus_Success Send frame succeed. + * retval kStatus_ENET_TxFrameOverLen Buffer length isn't enough to store data. + * 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. + */ +status_t ENET_SetTxBuffer(ENET_Type *base, + enet_handle_t *handle, + const uint8_t *data, + uint32_t length, + uint8_t ringId, + uint8_t txFlag, + void *context) +{ + assert(handle != NULL); + assert(data != 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]; + enet_frame_info_t *txDirty = NULL; + volatile enet_tx_bd_struct_t *curBuffDescrip; + volatile enet_tx_bd_struct_t *tempBuffDescrip; + status_t result = kStatus_Success; + uint16_t index; + + /* Check the data length. */ + if (handle->txBuffSizeAlign[ringId] < length) + { + result = kStatus_ENET_TxFrameOverLen; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if (handle->TxReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* Check if the transmit buffer is ready or ring with framinfo is full. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* Prepare data address for uDMA transfer. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + curBuffDescrip->buffer = (uint8_t *)(uint32_t)data; + + /* Set data length. */ + curBuffDescrip->length = (uint16_t)length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if ((txFlag & ENET_TX_TIMESTAMP_FLAG) != 0U) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + if (handle->TxReclaimEnable[ringId]) + { + txBdRing->txDescUsed++; + } + /* If BD is full or last flag sets, send out all data */ + if ((txFlag & ENET_TX_LAST_BD_FLAG) != 0U) + { + /* Set all configurated BDs with own flag ready */ + tempBuffDescrip = curBuffDescrip; + index = txBdRing->txGenIdx; + do + { + if ((tempBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK) != 0U) + { + tempBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK); + tempBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + } + index = ENET_IncreaseIndex(index, txBdRing->txRingLen); + tempBuffDescrip = txBdRing->txBdBase + index; + } while (tempBuffDescrip != curBuffDescrip); + + /* 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; + } + } + + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, 0); + } + else + { + curBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + /* Set owner flag, need to set Tx ready for all BDs with this flag after configurating last BD */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK; + } + + /* Increase the buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + } + } + + /* If fails to send whole frame success, need to send out all left ready data in BDs, make sure. */ + if (result != kStatus_Success) + { + tempBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + index = txBdRing->txGenIdx; + do + { + if ((tempBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK) != 0U) + { + tempBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK); + tempBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + } + index = ENET_IncreaseIndex(index, txBdRing->txRingLen); + tempBuffDescrip = txBdRing->txBdBase + index; + } while (index != txBdRing->txGenIdx); + } + + 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); + + 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; + } + } + } + + /* Enable a multicast group address. */ + configVal = 1U; + configVal = configVal << ((crc >> 0x1AU) & 0x1FU); + + if (0U == ((crc >> 0x1FU) & 1U)) + { + base->GALR |= configVal; + } + else + { + base->GAUR |= 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); + + 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; + } + } + } + + /* Set the hash table. */ + configVal = 1U; + configVal = ~(configVal << ((crc >> 0x1AU) & 0x1FU)); + if (0U == ((crc >> 0x1FU) & 1U)) + { + base->GALR &= configVal; + } + else + { + base->GAUR &= 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_QUEUE - 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; + + /* Enables the time stamp interrupt and transmit frame interrupt to + * handle the time-stamp . */ + ENET_EnableInterrupts(base, (ENET_TS_INTERRUPT | ENET_TX_INTERRUPT)); + ENET_DisableInterrupts(base, mask); + + /* Set the IRQ handler when the interrupt is enabled. */ + ENET_SetTsISRHandler(base, ENET_TimeStampIRQHandler); + ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler); +} + +/*! + * 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) +{ + uint16_t count = ENET_1588TIME_DELAY_COUNT; + + /* Get the current PTP time. */ + ptpTime->second = handle->msTimerSecond; + /* Get the nanosecond from the master timer. */ + base->ATCR |= ENET_ATCR_CAPTURE_MASK; + /* Add at least six clock cycle delay to get accurate time. + It's the requirement when the 1588 clock source is slower + than the register clock. + */ + while (0U != (count--)) + { + __NOP(); + } + /* 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); + + uint8_t count = 0; + + for (count = 0; count < (uint8_t)FSL_FEATURE_ENET_QUEUE - 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_FETAURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief The transmit IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +#else +/*! + * brief The transmit IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle) +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +{ + assert(handle != 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 */ + } + } + } +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief The receive IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +#else +/*! + * brief The receive IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle) +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +{ + assert(handle != 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 */ + } + } + SDK_ISR_EXIT_BARRIER; +} + +#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 */ + } + } + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! + * brief the common IRQ handler for the tx/rx/error etc irq handler. + * + * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame0IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + if (0U != (event & ((uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt))) + { +#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 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]); + } + SDK_ISR_EXIT_BARRIER; +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 1). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame1IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + if (0U != (event & ((uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame1Interrupt))) + { + s_enetTxIsr[instance](base, s_ENETHandle[instance], 1); + } + + if (0U != (event & ((uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame1Interrupt))) + { + s_enetRxIsr[instance](base, s_ENETHandle[instance], 1); + } + SDK_ISR_EXIT_BARRIER; +} + +/*! + * brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 2). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame2IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + if (0U != (event & ((uint32_t)kENET_TxBuffer2Interrupt | (uint32_t)kENET_TxFrame2Interrupt))) + { + s_enetTxIsr[instance](base, s_ENETHandle[instance], 2); + } + + if (0U != (event & ((uint32_t)kENET_RxBuffer2Interrupt | (uint32_t)kENET_RxFrame2Interrupt))) + { + s_enetRxIsr[instance](base, s_ENETHandle[instance], 2); + } + SDK_ISR_EXIT_BARRIER; +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +#if defined(ENET) +void ENET_Transmit_IRQHandler(void) +{ + s_enetTxIsr[0](ENET, s_ENETHandle[0]); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_Receive_IRQHandler(void) +{ + s_enetRxIsr[0](ENET, s_ENETHandle[0]); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_Error_IRQHandler(void) +{ + s_enetErrIsr[0](ENET, s_ENETHandle[0]); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_1588_Timer_IRQHandler(void) +{ + s_enetTsIsr[0](ENET, s_ENETHandle[0]); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; + SDK_ISR_EXIT_BARRIER; +} + +#endif + +#if defined(ENET1) +void ENET1_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET1); + SDK_ISR_EXIT_BARRIER; +} +#endif + +#if defined(ENET2) +void ENET2_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET2); + SDK_ISR_EXIT_BARRIER; +} +#endif + +#if defined(CONNECTIVITY__ENET0) +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) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +#endif +#endif +#if defined(CONNECTIVITY__ENET1) +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) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +#endif +#endif +#if FSL_FEATURE_ENET_QUEUE > 1 +#if defined(ENET_1G) +void ENET_1G_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET_1G); +/* Added for ARM errata 838869: storing immediate overlapping exception return operation + * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +void ENET_MAC0_Tx_Rx_Done_0_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(ENET_1G); +/* Added for ARM errata 838869: storing immediate overlapping exception return operation + * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +void ENET_MAC0_Tx_Rx_Done_1_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(ENET_1G); +/* Added for ARM errata 838869: storing immediate overlapping exception return operation + * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +void ENET_1G_1588_Timer_DriverIRQHandler(void) +{ + s_enet1588TimerIsr(ENET_1G, s_ENETHandle[1]); +/* Added for ARM errata 838869: storing immediate overlapping exception return operation + * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif +#endif diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c new file mode 100644 index 0000000000..593cf87a50 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/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/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c new file mode 100644 index 0000000000..682dae7492 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c @@ -0,0 +1,3564 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2020 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 + +#define IDEAL_SP_LOW (750U) +#define IDEAL_SP_MID (800U) +#define IDEAL_SP_HIGH (875U) +#define IDEAL_SP_FACTOR (1000U) + +#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_CANFD_BAUDRATE (8000000U) +#define MAX_CAN_BAUDRATE (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 + +#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_RxMbNotUs |