drivers: mbox: Initial support for RZ/G3S
Add MBOX driver support for Renesas RZ/G3S Signed-off-by: Phuc Pham <phuc.pham.xr@bp.renesas.com> Signed-off-by: Binh Nguyen <binh.nguyen.xw@renesas.com>
This commit is contained in:
parent
37ae587b64
commit
857fa96cf4
6 changed files with 404 additions and 0 deletions
|
@ -20,3 +20,4 @@ zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_BELLBOARD_TX mbox_nrf_bellboard_tx.
|
|||
zephyr_library_sources_ifdef(CONFIG_MBOX_STM32_HSEM mbox_stm32_hsem.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_IVSHMEM mbox_ivshmem.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_TI_OMAP_MAILBOX mbox_ti_omap.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_RENESAS_RZ_MHU mbox_renesas_rz_mhu.c)
|
||||
|
|
|
@ -24,6 +24,7 @@ source "drivers/mbox/Kconfig.stm32_hsem"
|
|||
source "drivers/mbox/Kconfig.esp32"
|
||||
source "drivers/mbox/Kconfig.ivshmem"
|
||||
source "drivers/mbox/Kconfig.ti_omap"
|
||||
source "drivers/mbox/Kconfig.renesas_rz"
|
||||
|
||||
|
||||
config MBOX_INIT_PRIORITY
|
||||
|
|
24
drivers/mbox/Kconfig.renesas_rz
Normal file
24
drivers/mbox/Kconfig.renesas_rz
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config MBOX_RENESAS_RZ_MHU
|
||||
bool "Renesas RZ MHU Driver"
|
||||
default y
|
||||
depends on DT_HAS_RENESAS_RZ_MHU_MBOX_ENABLED
|
||||
select USE_RZ_FSP_MHU
|
||||
help
|
||||
Enable the RZ MHU driver.
|
||||
|
||||
if MBOX_RENESAS_RZ_MHU
|
||||
|
||||
config MBOX_BUSY_WAIT_TIMEOUT_US
|
||||
int "MBOX send api timeout in microseconds"
|
||||
default 10
|
||||
help
|
||||
This option specifies the timeout duration for the `mbox_send` API to busy-wait for the
|
||||
remote processor to consume the previous message before sending a new one. If the
|
||||
message is not consumed within this time, `mbox_send` will return an error.
|
||||
Setting this value to 0 or a negative number will cause `mbox_send` to wait indefinitely
|
||||
until the previous message is consumed before sending a new one.
|
||||
|
||||
endif
|
329
drivers/mbox/mbox_renesas_rz_mhu.c
Normal file
329
drivers/mbox/mbox_renesas_rz_mhu.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Renesas Electronics Corporation
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT renesas_rz_mhu_mbox
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/mbox.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "r_mhu_ns.h"
|
||||
|
||||
LOG_MODULE_REGISTER(mbox_renesas_rz_mhu, CONFIG_MBOX_LOG_LEVEL);
|
||||
|
||||
/* Global dummy value required for FSP driver implementation */
|
||||
#define MHU_SHM_START_ADDR 0
|
||||
const uint32_t *const __mhu_shmem_start = (uint32_t *)MHU_SHM_START_ADDR;
|
||||
|
||||
/* FSP interrupt handlers. */
|
||||
void mhu_ns_int_isr(void);
|
||||
|
||||
static volatile uint32_t callback_msg;
|
||||
static void mhu_ns_callback(mhu_callback_args_t *p_args)
|
||||
{
|
||||
callback_msg = p_args->msg;
|
||||
}
|
||||
|
||||
struct mbox_rz_mhu_config {
|
||||
const mhu_api_t *fsp_api;
|
||||
uint16_t mhu_ch_size;
|
||||
/* Number of supported channels */
|
||||
uint32_t num_channels;
|
||||
/* TX channels mask */
|
||||
uint32_t tx_mask;
|
||||
/* RX channels mask */
|
||||
uint32_t rx_mask;
|
||||
};
|
||||
|
||||
struct mbox_rz_mhu_data {
|
||||
const struct device *dev;
|
||||
mhu_ns_instance_ctrl_t *fsp_ctrl;
|
||||
mhu_cfg_t *fsp_cfg;
|
||||
mbox_callback_t cb;
|
||||
void *user_data;
|
||||
uint32_t channel_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return true if the channel of the MBOX device is an inbound channel.
|
||||
*/
|
||||
static inline bool is_rx_channel_valid(const struct device *dev, uint32_t ch)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
|
||||
return ((ch < config->num_channels) && (config->rx_mask & BIT(ch)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return true if the channel of the MBOX device is an outbound channel.
|
||||
*/
|
||||
static inline bool is_tx_channel_valid(const struct device *dev, uint32_t ch)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
|
||||
return ((ch < config->num_channels) && (config->tx_mask & BIT(ch)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt handler
|
||||
*/
|
||||
static void mbox_rz_mhu_isr(const struct device *dev)
|
||||
{
|
||||
struct mbox_rz_mhu_data *data = dev->data;
|
||||
struct mbox_msg msg;
|
||||
|
||||
mhu_ns_int_isr();
|
||||
if (data->cb && data->fsp_cfg->p_shared_memory) {
|
||||
uint32_t local_msg = callback_msg;
|
||||
|
||||
msg.data = &local_msg;
|
||||
|
||||
/* On the receiving end, the size of the message is always 4 bytes since the FSP MHU
|
||||
* driver requires the message to be of type uint32_t
|
||||
*/
|
||||
msg.size = sizeof(local_msg);
|
||||
|
||||
data->cb(dev, data->channel_id, data->user_data, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to send a message over the MBOX device.
|
||||
*/
|
||||
static int mbox_rz_mhu_send(const struct device *dev, mbox_channel_id_t channel_id,
|
||||
const struct mbox_msg *msg)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
struct mbox_rz_mhu_data *data = dev->data;
|
||||
fsp_err_t fsp_err = FSP_SUCCESS;
|
||||
|
||||
/* FSP driver implementation requires the message to be of type uint32_t */
|
||||
uint32_t message = 0;
|
||||
|
||||
if (!is_tx_channel_valid(dev, channel_id)) {
|
||||
if (!is_rx_channel_valid(dev, channel_id)) {
|
||||
/* Channel is neither RX nor TX */
|
||||
LOG_ERR("Invalid MBOX channel number: %d", channel_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel is a RX channel, but this function only accepts TX */
|
||||
LOG_ERR("Channel ID %d is a RX channel, but only TX channels are allowed",
|
||||
channel_id);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (msg != NULL) {
|
||||
/* Maximum size allowed is 4 bytes */
|
||||
if (msg->size > config->mhu_ch_size) {
|
||||
LOG_ERR("Size %d is not valid. Maximum size is 4 bytes", msg->size);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
if (msg->data && msg->size) {
|
||||
/* Copy message */
|
||||
memcpy(&message, msg->data, msg->size);
|
||||
} else {
|
||||
/* Clear Message */
|
||||
message = 0;
|
||||
}
|
||||
} else {
|
||||
message = 0;
|
||||
}
|
||||
|
||||
if (data->fsp_cfg->p_shared_memory) {
|
||||
|
||||
#if CONFIG_MBOX_BUSY_WAIT_TIMEOUT_US > 0
|
||||
/* The FSP MHU "msgSend" API continuously polls until the
|
||||
* previous message is consumed before sending a new one. To avoid
|
||||
* blocking indefinitely, we need to check if the remote clears the message
|
||||
* within the allowed time before sending a new one
|
||||
*/
|
||||
if (MHU_SEND_TYPE_MSG == data->fsp_ctrl->send_type) {
|
||||
if (data->fsp_ctrl->p_regs->MSG_INT_STSn != 0) {
|
||||
k_busy_wait(CONFIG_MBOX_BUSY_WAIT_TIMEOUT_US);
|
||||
if (data->fsp_ctrl->p_regs->MSG_INT_STSn != 0) {
|
||||
LOG_ERR("Remote is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data->fsp_ctrl->p_regs->RSP_INT_STSn != 0) {
|
||||
k_busy_wait(CONFIG_MBOX_BUSY_WAIT_TIMEOUT_US);
|
||||
if (data->fsp_ctrl->p_regs->RSP_INT_STSn != 0) {
|
||||
LOG_ERR("Remote is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Send message to shared memory, this will also invoke interrupt on the receiving
|
||||
* core
|
||||
*/
|
||||
fsp_err = config->fsp_api->msgSend(data->fsp_ctrl, message);
|
||||
}
|
||||
|
||||
if (fsp_err) {
|
||||
LOG_ERR("Message send failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register a callback function on a channel for incoming messages.
|
||||
*/
|
||||
static int mbox_rz_mhu_reg_callback(const struct device *dev, mbox_channel_id_t channel_id,
|
||||
mbox_callback_t cb, void *user_data)
|
||||
{
|
||||
struct mbox_rz_mhu_data *data = dev->data;
|
||||
|
||||
if (!is_rx_channel_valid(dev, channel_id)) {
|
||||
if (!is_tx_channel_valid(dev, channel_id)) {
|
||||
/* Channel is neither RX nor TX */
|
||||
LOG_ERR("Invalid MBOX channel number: %d", channel_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel is a TX channel, but this function only accepts RX */
|
||||
LOG_ERR("Channel ID %d is a TX channel, but only RX channels are allowed",
|
||||
channel_id);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (!cb) {
|
||||
LOG_ERR("Must provide callback");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->cb = cb;
|
||||
data->user_data = user_data;
|
||||
data->channel_id = channel_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the module.
|
||||
*/
|
||||
static int mbox_rz_mhu_init(const struct device *dev)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
struct mbox_rz_mhu_data *data = dev->data;
|
||||
fsp_err_t fsp_err = FSP_SUCCESS;
|
||||
|
||||
fsp_err = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
|
||||
|
||||
if (fsp_err) {
|
||||
LOG_ERR("MBOX initialization failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable (disable) interrupts and callbacks for inbound channels.
|
||||
*/
|
||||
static int mbox_rz_mhu_set_enabled(const struct device *dev, mbox_channel_id_t channel_id,
|
||||
bool enabled)
|
||||
{
|
||||
if (!is_rx_channel_valid(dev, channel_id)) {
|
||||
if (!is_tx_channel_valid(dev, channel_id)) {
|
||||
/* Channel is neither RX nor TX */
|
||||
LOG_ERR("Invalid MBOX channel number: %d", channel_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel is a TX channel, but this function only accepts RX */
|
||||
LOG_ERR("Channel ID %d is a TX channel, but only RX channels are allowed",
|
||||
channel_id);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ARG_UNUSED(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the maximum number of bytes possible in an outbound message.
|
||||
*/
|
||||
static int mbox_rz_mhu_mtu_get(const struct device *dev)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
|
||||
return config->mhu_ch_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the maximum number of channels.
|
||||
*/
|
||||
static uint32_t mbox_rz_mhu_max_channels_get(const struct device *dev)
|
||||
{
|
||||
const struct mbox_rz_mhu_config *config = dev->config;
|
||||
|
||||
return config->num_channels;
|
||||
}
|
||||
|
||||
static DEVICE_API(mbox, mbox_rz_mhu_driver_api) = {
|
||||
.send = mbox_rz_mhu_send,
|
||||
.register_callback = mbox_rz_mhu_reg_callback,
|
||||
.mtu_get = mbox_rz_mhu_mtu_get,
|
||||
.max_channels_get = mbox_rz_mhu_max_channels_get,
|
||||
.set_enabled = mbox_rz_mhu_set_enabled,
|
||||
};
|
||||
|
||||
/*
|
||||
* ************************* DRIVER REGISTER SECTION ***************************
|
||||
*/
|
||||
|
||||
#define MHU_RZG_IRQ_CONNECT(idx, irq_name, isr) \
|
||||
do { \
|
||||
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, irq_name, irq), \
|
||||
DT_INST_IRQ_BY_NAME(idx, irq_name, priority), isr, \
|
||||
DEVICE_DT_INST_GET(idx), 0); \
|
||||
irq_enable(DT_INST_IRQ_BY_NAME(idx, irq_name, irq)); \
|
||||
} while (0)
|
||||
|
||||
#define MHU_RZG_CONFIG_FUNC(idx) MHU_RZG_IRQ_CONNECT(idx, mhuns, mbox_rz_mhu_isr);
|
||||
|
||||
#define MHU_RZG_INIT(idx) \
|
||||
static mhu_ns_instance_ctrl_t g_mhu_ns##idx##_ctrl; \
|
||||
static mhu_cfg_t g_mhu_ns##idx##_cfg = { \
|
||||
.channel = DT_INST_PROP(idx, channel), \
|
||||
.rx_ipl = DT_INST_IRQ_BY_NAME(idx, mhuns, priority), \
|
||||
.rx_irq = DT_INST_IRQ_BY_NAME(idx, mhuns, irq), \
|
||||
.p_callback = mhu_ns_callback, \
|
||||
.p_context = NULL, \
|
||||
.p_shared_memory = (void *)COND_CODE_1(DT_INST_NODE_HAS_PROP(idx, shared_memory), \
|
||||
(DT_REG_ADDR(DT_INST_PHANDLE(idx, shared_memory))), (NULL)), \
|
||||
}; \
|
||||
static const struct mbox_rz_mhu_config mbox_rz_mhu_config_##idx = { \
|
||||
.fsp_api = &g_mhu_ns_on_mhu_ns, \
|
||||
.mhu_ch_size = 4, \
|
||||
.num_channels = DT_INST_PROP(idx, channels_count), \
|
||||
.tx_mask = DT_INST_PROP(idx, tx_mask), \
|
||||
.rx_mask = DT_INST_PROP(idx, rx_mask), \
|
||||
}; \
|
||||
static struct mbox_rz_mhu_data mbox_rz_mhu_data_##idx = { \
|
||||
.dev = DEVICE_DT_INST_GET(idx), \
|
||||
.fsp_ctrl = &g_mhu_ns##idx##_ctrl, \
|
||||
.fsp_cfg = &g_mhu_ns##idx##_cfg, \
|
||||
}; \
|
||||
static int mbox_rz_mhu_init_##idx(const struct device *dev) \
|
||||
{ \
|
||||
MHU_RZG_CONFIG_FUNC(idx) \
|
||||
return mbox_rz_mhu_init(dev); \
|
||||
} \
|
||||
DEVICE_DT_INST_DEFINE(idx, mbox_rz_mhu_init_##idx, NULL, &mbox_rz_mhu_data_##idx, \
|
||||
&mbox_rz_mhu_config_##idx, PRE_KERNEL_1, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &mbox_rz_mhu_driver_api)
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MHU_RZG_INIT);
|
45
dts/bindings/mbox/renesas,rz-mhu-mbox.yaml
Normal file
45
dts/bindings/mbox/renesas,rz-mhu-mbox.yaml
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Renesas MHU MBOX
|
||||
|
||||
compatible: "renesas,rz-mhu-mbox"
|
||||
|
||||
include: [base.yaml, mailbox-controller.yaml]
|
||||
|
||||
properties:
|
||||
channel:
|
||||
type: int
|
||||
required: true
|
||||
description: the channel number of the underlying MHU unit used for MBOX.
|
||||
|
||||
reg:
|
||||
required: true
|
||||
|
||||
interrupts:
|
||||
required: true
|
||||
|
||||
tx-mask:
|
||||
type: int
|
||||
required: true
|
||||
description: TX supported channels mask
|
||||
|
||||
rx-mask:
|
||||
type: int
|
||||
required: true
|
||||
description: RX supported channels mask
|
||||
|
||||
channels-count:
|
||||
type: int
|
||||
required: true
|
||||
description: number of channels supported for a MBOX instance.
|
||||
|
||||
shared-memory:
|
||||
type: phandle
|
||||
description: |
|
||||
Reference to the shared memory region that is going
|
||||
to be used for the buffer communication between
|
||||
MHU units. No data will be transmitted if not set.
|
||||
|
||||
mbox-cells:
|
||||
- channel
|
|
@ -187,6 +187,10 @@ config USE_RZ_FSP_EXT_IRQ
|
|||
bool
|
||||
help
|
||||
Enable RZ FSP External IRQ driver
|
||||
config USE_RZ_FSP_MHU
|
||||
bool
|
||||
help
|
||||
Enable RZ FSP MHU driver
|
||||
|
||||
config USE_RZ_FSP_CPG
|
||||
bool
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue