mbox: Add NXP MU as a MBOX device
Add a MBOX driver wrapper around the NXP MU, simular to the existing wrapper around the NXP S32 MRU. This allows Zephyr IPC to work based on the MU, on a number of NXP boards. Also update the SHA of NXP HAL to enable the Kconfig for this driver. Signed-off-by: Yicheng Li <yichengli@google.com>
This commit is contained in:
parent
f2069530ee
commit
6ead139b4b
|
@ -459,6 +459,10 @@ zephyr_udc0: &usbhs {
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&mbox {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Disable this node if not using USB and need another MPU region */
|
||||
&sram1 {
|
||||
status = "okay";
|
||||
|
|
|
@ -7,4 +7,5 @@ zephyr_library()
|
|||
zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_NRFX_IPC mbox_nrfx_ipc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_S32_MRU mbox_nxp_s32_mru.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_IMX_MU mbox_nxp_imx_mu.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_ANDES_PLIC_SW mbox_andes_plic_sw.c)
|
||||
|
|
|
@ -13,6 +13,7 @@ if MBOX
|
|||
# overridden (by defining symbols in multiple locations)
|
||||
source "drivers/mbox/Kconfig.nrfx"
|
||||
source "drivers/mbox/Kconfig.nxp_s32"
|
||||
source "drivers/mbox/Kconfig.nxp_imx"
|
||||
source "drivers/mbox/Kconfig.andes"
|
||||
|
||||
config MBOX_INIT_PRIORITY
|
||||
|
|
9
drivers/mbox/Kconfig.nxp_imx
Normal file
9
drivers/mbox/Kconfig.nxp_imx
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright 2022 NXP
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config MBOX_NXP_IMX_MU
|
||||
bool "NXP i.MX Message Unit (MU) driver"
|
||||
default y
|
||||
depends on DT_HAS_NXP_MBOX_IMX_MU_ENABLED
|
||||
help
|
||||
Driver for NXP i.MX Message Unit.
|
179
drivers/mbox/mbox_nxp_imx_mu.c
Normal file
179
drivers/mbox/mbox_nxp_imx_mu.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Wrapper of the i.MX Message Unit driver into Zephyr's MBOX model.
|
||||
*/
|
||||
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/mbox.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
#include <fsl_mu.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(nxp_mbox_imx_mu);
|
||||
|
||||
#define DT_DRV_COMPAT nxp_mbox_imx_mu
|
||||
|
||||
#define MU_MAX_CHANNELS 4
|
||||
#define MU_MBOX_SIZE sizeof(uint32_t)
|
||||
|
||||
struct nxp_imx_mu_data {
|
||||
mbox_callback_t cb[MU_MAX_CHANNELS];
|
||||
void *user_data[MU_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct nxp_imx_mu_config {
|
||||
MU_Type *base;
|
||||
};
|
||||
|
||||
static int nxp_imx_mu_send(const struct device *dev, uint32_t channel,
|
||||
const struct mbox_msg *msg)
|
||||
{
|
||||
uint32_t __aligned(4) data32;
|
||||
const struct nxp_imx_mu_config *cfg = dev->config;
|
||||
|
||||
if (channel >= MU_MAX_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Signalling mode. */
|
||||
if (msg == NULL) {
|
||||
return MU_TriggerInterrupts(
|
||||
cfg->base, kMU_GenInt0InterruptTrigger);
|
||||
}
|
||||
|
||||
/* Data transfer mode. */
|
||||
if (msg->size != MU_MBOX_SIZE) {
|
||||
/* We can only send this many bytes at a time. */
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* memcpy to avoid issues when msg->data is not word-aligned. */
|
||||
memcpy(&data32, msg->data, msg->size);
|
||||
MU_SendMsg(cfg->base, channel, data32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nxp_imx_mu_register_callback(const struct device *dev, uint32_t channel,
|
||||
mbox_callback_t cb, void *user_data)
|
||||
{
|
||||
struct nxp_imx_mu_data *data = dev->data;
|
||||
|
||||
if (channel >= MU_MAX_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->cb[channel] = cb;
|
||||
data->user_data[channel] = user_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nxp_imx_mu_mtu_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
return MU_MBOX_SIZE;
|
||||
}
|
||||
|
||||
static uint32_t nxp_imx_mu_max_channels_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
return MU_MAX_CHANNELS;
|
||||
}
|
||||
|
||||
static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel,
|
||||
bool enable)
|
||||
{
|
||||
struct nxp_imx_mu_data *data = dev->data;
|
||||
const struct nxp_imx_mu_config *cfg = dev->config;
|
||||
|
||||
if (channel >= MU_MAX_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if (data->cb[channel] == NULL) {
|
||||
LOG_WRN("Enabling channel without a registered callback");
|
||||
}
|
||||
MU_EnableInterrupts(cfg->base,
|
||||
kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable |
|
||||
kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable |
|
||||
kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable |
|
||||
kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable);
|
||||
} else {
|
||||
MU_DisableInterrupts(cfg->base,
|
||||
kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable |
|
||||
kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable |
|
||||
kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable |
|
||||
kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mbox_driver_api nxp_imx_mu_driver_api = {
|
||||
.send = nxp_imx_mu_send,
|
||||
.register_callback = nxp_imx_mu_register_callback,
|
||||
.mtu_get = nxp_imx_mu_mtu_get,
|
||||
.max_channels_get = nxp_imx_mu_max_channels_get,
|
||||
.set_enabled = nxp_imx_mu_set_enabled,
|
||||
};
|
||||
|
||||
#define MU_INSTANCE_DEFINE(idx) \
|
||||
static struct nxp_imx_mu_data nxp_imx_mu_##idx##_data; \
|
||||
static struct nxp_imx_mu_config nxp_imx_mu_##idx##_config = { \
|
||||
.base = (MU_Type *)DT_INST_REG_ADDR(idx), \
|
||||
}; \
|
||||
\
|
||||
void MU_##idx##_IRQHandler(void); \
|
||||
static int nxp_imx_mu_##idx##_init(const struct device *dev) \
|
||||
{ \
|
||||
ARG_UNUSED(dev); \
|
||||
MU_Init(nxp_imx_mu_##idx##_config.base); \
|
||||
IRQ_CONNECT(DT_INST_IRQN(idx), \
|
||||
DT_INST_IRQ(idx, priority), \
|
||||
MU_##idx##_IRQHandler, \
|
||||
NULL, \
|
||||
0); \
|
||||
irq_enable(DT_INST_IRQN(idx)); \
|
||||
return 0; \
|
||||
} \
|
||||
DEVICE_DT_INST_DEFINE(idx, nxp_imx_mu_##idx##_init, NULL, \
|
||||
&nxp_imx_mu_##idx##_data, &nxp_imx_mu_##idx##_config, \
|
||||
POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \
|
||||
&nxp_imx_mu_driver_api)
|
||||
|
||||
#define MU_IRQ_HANDLER(idx) \
|
||||
static uint32_t mu_##idx##_received_data; \
|
||||
void MU_##idx##_IRQHandler(void) \
|
||||
{ \
|
||||
const struct device *dev = DEVICE_DT_INST_GET(idx); \
|
||||
const struct nxp_imx_mu_data *data = dev->data; \
|
||||
const struct nxp_imx_mu_config *config = dev->config; \
|
||||
int channel = 0; \
|
||||
struct mbox_msg msg; \
|
||||
struct mbox_msg *callback_msg_ptr = NULL; \
|
||||
uint32_t flag = MU_GetStatusFlags(config->base); \
|
||||
\
|
||||
if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag) { \
|
||||
mu_##idx##_received_data = \
|
||||
MU_ReceiveMsgNonBlocking(config->base, 0); \
|
||||
msg.data = (const void *)&mu_##idx##_received_data; \
|
||||
msg.size = MU_MBOX_SIZE; \
|
||||
callback_msg_ptr = &msg; \
|
||||
} else if ((flag & kMU_GenInt0Flag) == kMU_GenInt0Flag) { \
|
||||
MU_ClearStatusFlags(config->base, kMU_GenInt0Flag); \
|
||||
callback_msg_ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
if (data->cb[channel]) { \
|
||||
data->cb[channel](dev, channel, \
|
||||
data->user_data[channel], \
|
||||
callback_msg_ptr); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MU_INST(idx) \
|
||||
MU_INSTANCE_DEFINE(idx); \
|
||||
MU_IRQ_HANDLER(idx);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MU_INST)
|
|
@ -546,6 +546,15 @@
|
|||
#address-cells = <3>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
mbox:mbox@110000 {
|
||||
compatible = "nxp,mbox-imx-mu";
|
||||
reg = <0x110000 0x100>;
|
||||
interrupts = <34 0>;
|
||||
rx-channels = <4>;
|
||||
#mbox-cells = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&flexspi {
|
||||
|
|
29
dts/bindings/mbox/nxp,mbox-imx-mu.yaml
Normal file
29
dts/bindings/mbox/nxp,mbox-imx-mu.yaml
Normal file
|
@ -0,0 +1,29 @@
|
|||
description: |
|
||||
NXP i.MX Message Unit as Zephyr MBOX
|
||||
|
||||
compatible: "nxp,mbox-imx-mu"
|
||||
|
||||
include: [base.yaml, mailbox-controller.yaml]
|
||||
|
||||
properties:
|
||||
interrupts:
|
||||
required: true
|
||||
|
||||
rx-channels:
|
||||
type: int
|
||||
enum: [1, 2, 3, 4]
|
||||
description: |
|
||||
Number of receive channels enabled on this instance.
|
||||
Setting this value to N, will enable channels 0 to N-1, consecutively.
|
||||
It should be set by the receiver core coupled with this MU instance.
|
||||
|
||||
For example, if receiver A wants to Rx on channels 0 to 3, then A must
|
||||
set rx-channels of muA as follows:
|
||||
|
||||
mruA {
|
||||
rx-channels = <4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
mbox-cells:
|
||||
- channel
|
|
@ -12,6 +12,8 @@ if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
|
|||
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
|
||||
elseif("${BOARD}" STREQUAL "adp_xc7k_ae350")
|
||||
set(BOARD_REMOTE "adp_xc7k_ae350")
|
||||
elseif("${BOARD}" STREQUAL "mimxrt595_evk_cm33")
|
||||
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
|
||||
else()
|
||||
message(FATAL_ERROR "${BOARD} is not supported for this sample")
|
||||
endif()
|
||||
|
|
1
samples/drivers/mbox/boards/mimxrt595_evk_cm33.conf
Normal file
1
samples/drivers/mbox/boards/mimxrt595_evk_cm33.conf
Normal file
|
@ -0,0 +1 @@
|
|||
CONFIG_MBOX_NXP_IMX_MU=y
|
|
@ -2,7 +2,10 @@ sample:
|
|||
name: MBOX IPC sample
|
||||
tests:
|
||||
sample.drivers.mbox:
|
||||
platform_allow: nrf5340dk_nrf5340_cpuapp adp_xc7k_ae350
|
||||
platform_allow:
|
||||
- nrf5340dk_nrf5340_cpuapp
|
||||
- adp_xc7k_ae350
|
||||
- mimxrt595_evk_cm33
|
||||
integration_platforms:
|
||||
- nrf5340dk_nrf5340_cpuapp
|
||||
tags: mbox
|
||||
|
|
Loading…
Reference in a new issue