diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index 3121e871f93..8c9b2eeb232 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -1,6 +1,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_QUARK_SE ipm_quark_se.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index 1b8142871b3..069da7a96c1 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -23,3 +23,55 @@ config IPM_MCUX depends on IPM && HAS_MCUX help Driver for MCUX mailbox + +config IPM_IMX + bool "IMX IPM driver" + default n + depends on IPM && HAS_IMX_HAL + help + Driver for NXP i.MX messaging unit + +choice + prompt "IMX IPM max data size" + default IPM_IMX_MAX_DATA_SIZE_16 + depends on IPM_IMX + help + Select maximum message size for NXP i.MX messaging unit. + +config IPM_IMX_MAX_DATA_SIZE_4 + bool "4 bytes" + help + There will be four message types with ids 0, 1, 2 or 3 + and a maximum size of 4 bytes each. + +config IPM_IMX_MAX_DATA_SIZE_8 + bool "8 bytes" + help + There will be two message types with ids 0 or 1 + and a maximum size of 8 bytes each. + +config IPM_IMX_MAX_DATA_SIZE_16 + bool "16 bytes" + help + There will be a single message type with id 0 + and a maximum size of 16 bytes. + +endchoice + +config IPM_IMX_MAX_DATA_SIZE + int + range 4 16 + # omit prompt to signify a "hidden" option + 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 + +config IPM_IMX_MAX_ID_VAL + int + range 0 3 + # omit prompt to signify a "hidden" option + 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 diff --git a/drivers/ipm/ipm_imx.c b/drivers/ipm/ipm_imx.c new file mode 100644 index 00000000000..f4ded0a6384 --- /dev/null +++ b/drivers/ipm/ipm_imx.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define MU(config) ((MU_Type *)config->base) + +#if ((CONFIG_IPM_IMX_MAX_DATA_SIZE % 4) != 0) +#error CONFIG_IPM_IMX_MAX_DATA_SIZE is invalid +#endif + +#define IMX_IPM_DATA_REGS (CONFIG_IPM_IMX_MAX_DATA_SIZE / 4) + +struct imx_mu_config { + MU_Type *base; + void (*irq_config_func)(struct device *dev); +}; + +struct imx_mu_data { + ipm_callback_t callback; + void *callback_ctx; +}; + +static void imx_mu_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + const struct imx_mu_config *config = dev->config->config_info; + MU_Type *base = MU(config); + struct imx_mu_data *data = dev->driver_data; + u32_t data32[IMX_IPM_DATA_REGS]; + u32_t status_reg; + s32_t id; + s32_t i; + bool all_registers_full; + + status_reg = base->SR >>= MU_SR_RFn_SHIFT; + + for (id = CONFIG_IPM_IMX_MAX_ID_VAL; id >= 0; id--) { + if (status_reg & 0x1U) { + /* + * Check if all receive registers are full. If not, + * it is violation of the protocol (status register + * are set earlier than all receive registers). + * Do not read any of the registers in such situation. + */ + all_registers_full = true; + for (i = 0; i < IMX_IPM_DATA_REGS; i++) { + if (!MU_IsRxFull(base, + (id * IMX_IPM_DATA_REGS) + i)) { + all_registers_full = false; + break; + } + } + if (all_registers_full) { + for (i = 0; i < IMX_IPM_DATA_REGS; i++) { + MU_ReceiveMsg(base, + (id * IMX_IPM_DATA_REGS) + i, + &data32[i]); + } + + if (data->callback) { + data->callback(data->callback_ctx, + (u32_t)id, + &data32[0]); + } + } + } + status_reg >>= IMX_IPM_DATA_REGS; + } + + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F + * Store immediate overlapping exception return operation + * might vector to incorrect interrupt + */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +static int imx_mu_ipm_send(struct device *dev, int wait, u32_t id, + const void *data, int size) +{ + const struct imx_mu_config *config = dev->config->config_info; + MU_Type *base = MU(config); + u32_t data32[IMX_IPM_DATA_REGS]; + mu_status_t status; + int i; + + if (id > CONFIG_IPM_IMX_MAX_ID_VAL) { + return -EINVAL; + } + + if (size > CONFIG_IPM_IMX_MAX_DATA_SIZE) { + return -EMSGSIZE; + } + + /* Actual message is passing using 32 bits registers */ + memcpy(data32, data, size); + + for (i = 0; i < IMX_IPM_DATA_REGS; i++) { + status = MU_TrySendMsg(base, id * IMX_IPM_DATA_REGS + i, + data32[i]); + if (status == kStatus_MU_TxNotEmpty) { + return -EBUSY; + } + } + + if (wait) { + while (!MU_IsTxEmpty(base, + (id * IMX_IPM_DATA_REGS) + IMX_IPM_DATA_REGS - 1)) { + } + } + + return 0; +} + +static int imx_mu_ipm_max_data_size_get(struct device *dev) +{ + ARG_UNUSED(dev); + + return CONFIG_IPM_IMX_MAX_DATA_SIZE; +} + +static u32_t imx_mu_ipm_max_id_val_get(struct device *dev) +{ + ARG_UNUSED(dev); + + return CONFIG_IPM_IMX_MAX_ID_VAL; +} + +static void imx_mu_ipm_register_callback(struct device *dev, + ipm_callback_t cb, + void *context) +{ + struct imx_mu_data *driver_data = dev->driver_data; + + driver_data->callback = cb; + driver_data->callback_ctx = context; +} + +static int imx_mu_ipm_set_enabled(struct device *dev, int enable) +{ + const struct imx_mu_config *config = dev->config->config_info; + MU_Type *base = MU(config); + +#if CONFIG_IPM_IMX_MAX_DATA_SIZE_4 + if (enable) { + MU_EnableRxFullInt(base, 0U); + MU_EnableRxFullInt(base, 1U); + MU_EnableRxFullInt(base, 2U); + MU_EnableRxFullInt(base, 3U); + } else { + MU_DisableRxFullInt(base, 0U); + MU_DisableRxFullInt(base, 1U); + MU_DisableRxFullInt(base, 2U); + MU_DisableRxFullInt(base, 3U); + } +#elif CONFIG_IPM_IMX_MAX_DATA_SIZE_8 + if (enable) { + MU_EnableRxFullInt(base, 1U); + MU_EnableRxFullInt(base, 3U); + } else { + MU_DisableRxFullInt(base, 1U); + MU_DisableRxFullInt(base, 3U); + } +#elif CONFIG_IPM_IMX_MAX_DATA_SIZE_16 + if (enable) { + MU_EnableRxFullInt(base, 3U); + } else { + MU_DisableRxFullInt(base, 3U); + } +#else +#error "CONFIG_IPM_IMX_MAX_DATA_SIZE_n is not set" +#endif + + return 0; +} + +static int imx_mu_init(struct device *dev) +{ + const struct imx_mu_config *config = dev->config->config_info; + + MU_Init(MU(config)); + config->irq_config_func(dev); + + return 0; +} + +static const struct ipm_driver_api imx_mu_driver_api = { + .send = imx_mu_ipm_send, + .register_callback = imx_mu_ipm_register_callback, + .max_data_size_get = imx_mu_ipm_max_data_size_get, + .max_id_val_get = imx_mu_ipm_max_id_val_get, + .set_enabled = imx_mu_ipm_set_enabled +}; + +/* Config MU */ + +static void imx_mu_config_func_b(struct device *dev); + +static const struct imx_mu_config imx_mu_b_config = { + .base = (MU_Type *)DT_IPM_IMX_MU_B_BASE_ADDRESS, + .irq_config_func = imx_mu_config_func_b, +}; + +static struct imx_mu_data imx_mu_b_data; + +DEVICE_AND_API_INIT(mu_b, DT_IPM_IMX_MU_B_NAME, + &imx_mu_init, + &imx_mu_b_data, &imx_mu_b_config, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &imx_mu_driver_api); + +static void imx_mu_config_func_b(struct device *dev) +{ + IRQ_CONNECT(DT_IPM_IMX_MU_B_IRQ, + DT_IPM_IMX_MU_B_IRQ_PRI, + imx_mu_isr, DEVICE_GET(mu_b), 0); + + irq_enable(DT_IPM_IMX_MU_B_IRQ); +} diff --git a/dts/bindings/arm/nxp,imx-mu.yaml b/dts/bindings/arm/nxp,imx-mu.yaml new file mode 100644 index 00000000000..70cf8ec457d --- /dev/null +++ b/dts/bindings/arm/nxp,imx-mu.yaml @@ -0,0 +1,44 @@ +# +# Copyright (c) 2018, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: IMX MESSAGING UNIT +version: 0.1 + +description: > + This binding gives a base representation of the i.MX Messaging Unit + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "nxp,imx-mu" + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define + + label: + type: string + category: required + description: Human readable string describing the device (used by Zephyr for API name) + generation: define + + rdc: + type: int + category: required + description: Set the RDC permission for this peripheral + generation: define + +... diff --git a/ext/hal/nxp/imx/drivers/CMakeLists.txt b/ext/hal/nxp/imx/drivers/CMakeLists.txt index 2a30b651bc6..7fd034c0d6c 100644 --- a/ext/hal/nxp/imx/drivers/CMakeLists.txt +++ b/ext/hal/nxp/imx/drivers/CMakeLists.txt @@ -13,3 +13,4 @@ endif() zephyr_sources_ifdef(CONFIG_UART_IMX uart_imx.c) zephyr_sources_ifdef(CONFIG_GPIO_IMX gpio_imx.c) zephyr_sources_ifdef(CONFIG_I2C_IMX i2c_imx.c) +zephyr_sources_ifdef(CONFIG_IPM_IMX mu_imx.c)