2024-01-31 00:00:00 +08:00
|
|
|
/*
|
|
|
|
* Copyright 2024 NXP
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*
|
|
|
|
* Wrapper of NXP Mailbox driver for Zephyr's MBOX model.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zephyr/devicetree.h>
|
|
|
|
#include <zephyr/drivers/mbox.h>
|
2024-02-23 22:21:58 +08:00
|
|
|
#include <zephyr/irq.h>
|
2024-01-31 00:00:00 +08:00
|
|
|
#include <zephyr/sys/util_macro.h>
|
|
|
|
#include <fsl_mailbox.h>
|
|
|
|
|
|
|
|
#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(nxp_mbox_mailbox);
|
|
|
|
|
|
|
|
#define DT_DRV_COMPAT nxp_mbox_mailbox
|
|
|
|
|
|
|
|
#define MAILBOX_MAX_CHANNELS 4
|
|
|
|
#define MAILBOX_MBOX_SIZE 3
|
|
|
|
|
|
|
|
#if (defined(LPC55S69_cm33_core0_SERIES) || defined(LPC55S69_cm33_core1_SERIES))
|
|
|
|
#ifdef LPC55S69_cm33_core0_SERIES
|
|
|
|
#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core0
|
|
|
|
#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core1
|
|
|
|
#else
|
|
|
|
#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core1
|
|
|
|
#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core0
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#if defined(__CM4_CMSIS_VERSION)
|
|
|
|
#define MAILBOX_ID_THIS_CPU kMAILBOX_CM4
|
|
|
|
#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM0Plus
|
|
|
|
#else
|
|
|
|
#define MAILBOX_ID_THIS_CPU kMAILBOX_CM0Plus
|
|
|
|
#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM4
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define GENIRQ_SHIFT (28U)
|
|
|
|
#define GEN0_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 3U) /*!< General interrupt 3. */
|
|
|
|
#define GEN1_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 2U) /*!< General interrupt 2. */
|
|
|
|
#define GEN2_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 1U) /*!< General interrupt 1. */
|
|
|
|
#define GEN3_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 0U) /*!< General interrupt 0. */
|
|
|
|
|
|
|
|
#define DATA_MASK BIT_MASK(24U)
|
|
|
|
#define DATAIRQ_SHIFT (24U)
|
|
|
|
#define DATA0_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 3U) /*!< Data interrupt 3. */
|
|
|
|
#define DATA1_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 2U) /*!< Data interrupt 2. */
|
|
|
|
#define DATA2_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 1U) /*!< Data interrupt 1. */
|
|
|
|
#define DATA3_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 0U) /*!< Data interrupt 0. */
|
|
|
|
|
|
|
|
struct nxp_mailbox_data {
|
|
|
|
mbox_callback_t cb[MAILBOX_MAX_CHANNELS];
|
|
|
|
void *user_data[MAILBOX_MAX_CHANNELS];
|
|
|
|
bool channel_enable[MAILBOX_MAX_CHANNELS];
|
|
|
|
uint32_t received_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nxp_mailbox_config {
|
|
|
|
MAILBOX_Type *base;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void mailbox_isr(const struct device *dev)
|
|
|
|
{
|
|
|
|
struct nxp_mailbox_data *data = dev->data;
|
|
|
|
const struct nxp_mailbox_config *config = dev->config;
|
|
|
|
mailbox_cpu_id_t cpu_id;
|
|
|
|
|
|
|
|
cpu_id = MAILBOX_ID_THIS_CPU;
|
|
|
|
|
|
|
|
volatile uint32_t mailbox_value = MAILBOX_GetValue(config->base, cpu_id);
|
|
|
|
uint32_t flags = mailbox_value & (~DATA_MASK);
|
|
|
|
|
|
|
|
/* Clear or the interrupt gets called intermittently */
|
|
|
|
MAILBOX_ClearValueBits(config->base, cpu_id, mailbox_value);
|
|
|
|
|
|
|
|
for (int i_channel = 0; i_channel < MAILBOX_MAX_CHANNELS; i_channel++) {
|
|
|
|
/* Continue to next channel if channel is not enabled */
|
|
|
|
if (!data->channel_enable[i_channel]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & (DATA0_IRQ_TRIGGER >> i_channel))) {
|
|
|
|
data->received_data = mailbox_value & DATA_MASK;
|
|
|
|
struct mbox_msg msg = {(const void *)&data->received_data,
|
|
|
|
MAILBOX_MBOX_SIZE};
|
|
|
|
|
|
|
|
if (data->cb[i_channel]) {
|
|
|
|
data->cb[i_channel](dev, i_channel, data->user_data[i_channel],
|
|
|
|
&msg);
|
|
|
|
}
|
|
|
|
} else if ((flags & (GEN0_IRQ_TRIGGER >> i_channel))) {
|
|
|
|
if (data->cb[i_channel]) {
|
|
|
|
data->cb[i_channel](dev, i_channel, data->user_data[i_channel],
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
barrier_dsync_fence_full();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nxp_mailbox_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg)
|
|
|
|
{
|
|
|
|
uint32_t __aligned(4) data32;
|
|
|
|
const struct nxp_mailbox_config *cfg = dev->config;
|
|
|
|
|
|
|
|
if (channel >= MAILBOX_MAX_CHANNELS) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Signalling mode. */
|
|
|
|
if (msg == NULL) {
|
|
|
|
MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU, GEN0_IRQ_TRIGGER >> channel);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Data transfer mode. */
|
|
|
|
if (msg->size != MAILBOX_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);
|
|
|
|
|
|
|
|
MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU,
|
|
|
|
(DATA0_IRQ_TRIGGER >> channel) | (data32 & DATA_MASK));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nxp_mailbox_register_callback(const struct device *dev, uint32_t channel,
|
|
|
|
mbox_callback_t cb, void *user_data)
|
|
|
|
{
|
|
|
|
struct nxp_mailbox_data *data = dev->data;
|
|
|
|
|
|
|
|
if (channel >= MAILBOX_MAX_CHANNELS) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->cb[channel] = cb;
|
|
|
|
data->user_data[channel] = user_data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nxp_mailbox_mtu_get(const struct device *dev)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
|
|
|
return MAILBOX_MBOX_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t nxp_mailbox_max_channels_get(const struct device *dev)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
return MAILBOX_MAX_CHANNELS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nxp_mailbox_set_enabled(const struct device *dev, uint32_t channel, bool enable)
|
|
|
|
{
|
|
|
|
struct nxp_mailbox_data *data = dev->data;
|
|
|
|
|
|
|
|
if (channel >= MAILBOX_MAX_CHANNELS) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->channel_enable[channel] = enable;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct mbox_driver_api nxp_mailbox_driver_api = {
|
|
|
|
.send = nxp_mailbox_send,
|
|
|
|
.register_callback = nxp_mailbox_register_callback,
|
|
|
|
.mtu_get = nxp_mailbox_mtu_get,
|
|
|
|
.max_channels_get = nxp_mailbox_max_channels_get,
|
|
|
|
.set_enabled = nxp_mailbox_set_enabled,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAILBOX_INSTANCE_DEFINE(idx) \
|
|
|
|
static struct nxp_mailbox_data nxp_mailbox_##idx##_data; \
|
|
|
|
const static struct nxp_mailbox_config nxp_mailbox_##idx##_config = { \
|
|
|
|
.base = (MAILBOX_Type *)DT_INST_REG_ADDR(idx), \
|
|
|
|
}; \
|
|
|
|
static int nxp_mailbox_##idx##_init(const struct device *dev) \
|
|
|
|
{ \
|
|
|
|
ARG_UNUSED(dev); \
|
|
|
|
MAILBOX_Init(nxp_mailbox_##idx##_config.base); \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), mailbox_isr, \
|
|
|
|
DEVICE_DT_INST_GET(idx), 0); \
|
|
|
|
irq_enable(DT_INST_IRQN(idx)); \
|
|
|
|
return 0; \
|
|
|
|
} \
|
|
|
|
DEVICE_DT_INST_DEFINE(idx, nxp_mailbox_##idx##_init, NULL, &nxp_mailbox_##idx##_data, \
|
|
|
|
&nxp_mailbox_##idx##_config, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \
|
|
|
|
&nxp_mailbox_driver_api)
|
|
|
|
|
|
|
|
#define MAILBOX_INST(idx) MAILBOX_INSTANCE_DEFINE(idx);
|
|
|
|
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(MAILBOX_INST)
|