From 850ec7e0d907155154d07dcf7fe462cb8361748b Mon Sep 17 00:00:00 2001 From: Chris Trowbridge Date: Tue, 15 Feb 2022 17:08:47 -0500 Subject: [PATCH] drivers: ipm: Add support for NXP i.MX rev2 MU With a number of the i.MX SoCs (e.g., the i.MX8M Plus), NXP has moved to supporting the integrated Cortex-M cores with the MCUXpresso SDK (MCUX). As a result, certain Zephyr drivers (such as the IPM driver) need to be updated to utlize this new MCUX-based SDK. This change adds support for the MCUX Messaging Unit driver pulled in by this PR: https://github.com/zephyrproject-rtos/hal_nxp/pull/130 Additionally, this change enables the new IPM_IMX_REV2 config for the mimx8ml8_m7 SoC target which utilizes this new revision of the driver. Signed-off-by: Chris Trowbridge --- drivers/ipm/CMakeLists.txt | 1 + drivers/ipm/Kconfig | 13 +- drivers/ipm/ipm_imx.c | 132 +++++++++++++++++- .../mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 | 4 + 4 files changed, 144 insertions(+), 6 deletions(-) diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index 632ee78b01d7..cc0687be5c63 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c) zephyr_library_sources_ifdef(CONFIG_IPM_IMX ipm_imx.c) +zephyr_library_sources_ifdef(CONFIG_IPM_IMX_REV2 ipm_imx.c) zephyr_library_sources_ifdef(CONFIG_IPM_MHU ipm_mhu.c) zephyr_library_sources_ifdef(CONFIG_IPM_STM32_IPCC ipm_stm32_ipcc.c) zephyr_library_sources_ifdef(CONFIG_IPM_NRFX ipm_nrfx_ipc.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index 84929656e406..9fc0b957733e 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -20,10 +20,17 @@ config IPM_IMX help Driver for NXP i.MX messaging unit +config IPM_IMX_REV2 + bool "IMX IPM driver (rev 2)" + depends on HAS_MCUX + depends on !IPM_IMX + help + Rev 2 driver for NXP i.MX messaging unit (MCUX-based) + choice prompt "IMX IPM max data size" default IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX + depends on IPM_IMX || IPM_IMX_REV2 help Select maximum message size for NXP i.MX messaging unit. @@ -53,7 +60,7 @@ config IPM_IMX_MAX_DATA_SIZE default 4 if IPM_IMX_MAX_DATA_SIZE_4 default 8 if IPM_IMX_MAX_DATA_SIZE_8 default 16 if IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX + depends on IPM_IMX || IPM_IMX_REV2 config IPM_IMX_MAX_ID_VAL int @@ -61,7 +68,7 @@ config IPM_IMX_MAX_ID_VAL default 3 if IPM_IMX_MAX_DATA_SIZE_4 default 1 if IPM_IMX_MAX_DATA_SIZE_8 default 0 if IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX + depends on IPM_IMX || IPM_IMX_REV2 config IPM_MHU bool "IPM MHU driver" diff --git a/drivers/ipm/ipm_imx.c b/drivers/ipm/ipm_imx.c index d27df57ec5a0..52ed43396bb0 100644 --- a/drivers/ipm/ipm_imx.c +++ b/drivers/ipm/ipm_imx.c @@ -11,7 +11,11 @@ #include #include #include +#if IS_ENABLED(CONFIG_IPM_IMX_REV2) +#include "fsl_mu.h" +#else #include +#endif #define MU(config) ((MU_Type *)config->base) @@ -31,6 +35,64 @@ struct imx_mu_data { void *user_data; }; +#if IS_ENABLED(CONFIG_IPM_IMX_REV2) +/*! + * @brief Check RX full status. + * + * This function checks the specific receive register full status. + * + * @param base Register base address for the module. + * @param index RX register index to check. + * @retval true RX register is full. + * @retval false RX register is not full. + */ +static inline bool MU_IsRxFull(MU_Type *base, uint32_t index) +{ + switch (index) { + case 0: + return (bool)(MU_GetStatusFlags(base) & kMU_Rx0FullFlag); + case 1: + return (bool)(MU_GetStatusFlags(base) & kMU_Rx1FullFlag); + case 2: + return (bool)(MU_GetStatusFlags(base) & kMU_Rx2FullFlag); + case 3: + return (bool)(MU_GetStatusFlags(base) & kMU_Rx3FullFlag); + default: + /* This shouldn't happen */ + assert(false); + return false; + } +} + +/*! + * @brief Check TX empty status. + * + * This function checks the specific transmit register empty status. + * + * @param base Register base address for the module. + * @param index TX register index to check. + * @retval true TX register is empty. + * @retval false TX register is not empty. + */ +static inline bool MU_IsTxEmpty(MU_Type *base, uint32_t index) +{ + switch (index) { + case 0: + return (bool)(MU_GetStatusFlags(base) & kMU_Tx0EmptyFlag); + case 1: + return (bool)(MU_GetStatusFlags(base) & kMU_Tx1EmptyFlag); + case 2: + return (bool)(MU_GetStatusFlags(base) & kMU_Tx2EmptyFlag); + case 3: + return (bool)(MU_GetStatusFlags(base) & kMU_Tx3EmptyFlag); + default: + /* This shouldn't happen */ + assert(false); + return false; + } +} +#endif + static void imx_mu_isr(const struct device *dev) { const struct imx_mu_config *config = dev->config; @@ -62,9 +124,14 @@ static void imx_mu_isr(const struct device *dev) } if (all_registers_full) { for (i = 0; i < IMX_IPM_DATA_REGS; i++) { +#if IS_ENABLED(CONFIG_IPM_IMX_REV2) + data32[i] = MU_ReceiveMsg(base, + (id * IMX_IPM_DATA_REGS) + i); +#else MU_ReceiveMsg(base, (id * IMX_IPM_DATA_REGS) + i, &data32[i]); +#endif } if (data->callback) { @@ -79,9 +146,13 @@ static void imx_mu_isr(const struct device *dev) /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F * Store immediate overlapping exception return operation - * might vector to incorrect interrupt + * might vector to incorrect interrupt. For Cortex-M7, if + * core speed much faster than peripheral register write + * speed, the peripheral interrupt flags may be still set + * after exiting ISR, this results to the same error similar + * with errata 838869. */ -#if defined __CORTEX_M && (__CORTEX_M == 4U) +#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U)) __DSB(); #endif } @@ -92,7 +163,9 @@ static int imx_mu_ipm_send(const struct device *dev, int wait, uint32_t id, const struct imx_mu_config *config = dev->config; MU_Type *base = MU(config); uint32_t data32[IMX_IPM_DATA_REGS]; +#if !IS_ENABLED(CONFIG_IPM_IMX_REV2) mu_status_t status; +#endif int i; if (id > CONFIG_IPM_IMX_MAX_ID_VAL) { @@ -106,6 +179,27 @@ static int imx_mu_ipm_send(const struct device *dev, int wait, uint32_t id, /* Actual message is passing using 32 bits registers */ memcpy(data32, data, size); +#if IS_ENABLED(CONFIG_IPM_IMX_REV2) + if (wait) { + for (i = 0; i < IMX_IPM_DATA_REGS; i++) { + MU_SendMsgNonBlocking(base, id * IMX_IPM_DATA_REGS + i, + data32[i]); + } + while (!MU_IsTxEmpty(base, + (id * IMX_IPM_DATA_REGS) + IMX_IPM_DATA_REGS - 1)) { + } + } else { + for (i = 0; i < IMX_IPM_DATA_REGS; i++) { + if (MU_IsTxEmpty(base, id * IMX_IPM_DATA_REGS + i)) { + MU_SendMsg(base, id * IMX_IPM_DATA_REGS + i, + data32[i]); + } else { + return -EBUSY; + } + } + } + +#else for (i = 0; i < IMX_IPM_DATA_REGS; i++) { status = MU_TrySendMsg(base, id * IMX_IPM_DATA_REGS + i, data32[i]); @@ -119,6 +213,7 @@ static int imx_mu_ipm_send(const struct device *dev, int wait, uint32_t id, (id * IMX_IPM_DATA_REGS) + IMX_IPM_DATA_REGS - 1)) { } } +#endif return 0; } @@ -151,7 +246,37 @@ static int imx_mu_ipm_set_enabled(const struct device *dev, int enable) { const struct imx_mu_config *config = dev->config; MU_Type *base = MU(config); - +#if IS_ENABLED(CONFIG_IPM_IMX_REV2) +#if CONFIG_IPM_IMX_MAX_DATA_SIZE_4 + if (enable) { + MU_EnableInterrupts(base, kMU_Rx0FullInterruptEnable); + MU_EnableInterrupts(base, kMU_Rx1FullInterruptEnable); + MU_EnableInterrupts(base, kMU_Rx2FullInterruptEnable); + MU_EnableInterrupts(base, kMU_Rx3FullInterruptEnable); + } else { + MU_DisableInterrupts(base, kMU_Rx0FullInterruptEnable); + MU_DisableInterrupts(base, kMU_Rx1FullInterruptEnable); + MU_DisableInterrupts(base, kMU_Rx2FullInterruptEnable); + MU_DisableInterrupts(base, kMU_Rx3FullInterruptEnable); + } +#elif CONFIG_IPM_IMX_MAX_DATA_SIZE_8 + if (enable) { + MU_EnableInterrupts(base, kMU_Rx1FullInterruptEnable); + MU_EnableInterrupts(base, kMU_Rx3FullInterruptEnable); + } else { + MU_DisableInterrupts(base, kMU_Rx1FullInterruptEnable); + MU_DisableInterrupts(base, kMU_Rx3FullInterruptEnable); + } +#elif CONFIG_IPM_IMX_MAX_DATA_SIZE_16 + if (enable) { + MU_EnableInterrupts(base, kMU_Rx3FullInterruptEnable); + } else { + MU_DisableInterrupts(base, kMU_Rx3FullInterruptEnable); + } +#else +#error "CONFIG_IPM_IMX_MAX_DATA_SIZE_n is not set" +#endif +#else #if CONFIG_IPM_IMX_MAX_DATA_SIZE_4 if (enable) { MU_EnableRxFullInt(base, 0U); @@ -180,6 +305,7 @@ static int imx_mu_ipm_set_enabled(const struct device *dev, int enable) } #else #error "CONFIG_IPM_IMX_MAX_DATA_SIZE_n is not set" +#endif #endif return 0; diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 index 2240ab3c4cb1..e3aa8c55c52a 100644 --- a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 +++ b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 @@ -34,6 +34,10 @@ config UART_MCUX_IUART endif # SERIAL +config IPM_IMX_REV2 + default y + depends on IPM + if CODE_ITCM config FLASH_SIZE