Parcourir la source

[DM/FEATURE] Support hardware mailbox (#9599)

* [DM/FEATURE] Support hardware mailbox
* [MAILBOX/PIC] Add PIC Mailbox drivers.

The mailbox device(s) may be instantiated in one of three equivalent way:

Device Tree node, eg.:

```dts
interrupt-controller@0 {
	interrupt-controller;
	#interrupt-cells = <1>;
};

pic_mailbox@10000 {
	compatible = "rt-thread,pic-mailbox";
	reg = <0x10000 0x100>;
	position = <0>;
	interrupts = <34>;
	peer-interrupts = <35>;
	uid = <0>;
	#mbox-cells = <1>;
};
```
Signed-off-by: GuEe-GUI <2991707448@qq.com>
GUI il y a 5 mois
Parent
commit
f849afb5ca

+ 1 - 0
components/drivers/Kconfig

@@ -21,6 +21,7 @@ rsource "touch/Kconfig"
 rsource "graphic/Kconfig"
 rsource "hwcrypto/Kconfig"
 rsource "wlan/Kconfig"
+rsource "mailbox/Kconfig"
 rsource "phye/Kconfig"
 rsource "block/Kconfig"
 rsource "nvme/Kconfig"

+ 77 - 0
components/drivers/include/drivers/mailbox.h

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2023-09-23     GuEe-GUI     first version
+ */
+
+#ifndef __MAILBOX_H__
+#define __MAILBOX_H__
+
+#include <rtdef.h>
+#include <drivers/ofw.h>
+
+struct rt_mbox_chan;
+struct rt_mbox_client;
+struct rt_mbox_controller_ops;
+
+struct rt_mbox_controller
+{
+    rt_list_t list;
+
+    struct rt_device *dev;
+
+    const struct rt_mbox_controller_ops *ops;
+
+    rt_size_t num_chans;
+    struct rt_mbox_chan *chans;
+};
+
+struct rt_mbox_controller_ops
+{
+    rt_err_t (*request)(struct rt_mbox_chan *);
+    void (*release)(struct rt_mbox_chan *);
+    rt_err_t (*send)(struct rt_mbox_chan *, const void *data);
+    rt_bool_t (*peek)(struct rt_mbox_chan *);
+    int (*ofw_parse)(struct rt_mbox_controller *, struct rt_ofw_cell_args *);
+};
+
+struct rt_mbox_chan
+{
+    struct rt_mbox_controller *ctrl;
+    struct rt_mbox_client *client;
+
+    void *data;
+    rt_bool_t complete;
+    struct rt_timer timer;
+    struct rt_spinlock lock;
+
+    void *priv;
+};
+
+struct rt_mbox_client
+{
+    struct rt_device *dev;
+
+    void (*rx_callback)(struct rt_mbox_client *, void *data);
+    void (*tx_prepare)(struct rt_mbox_client *, const void *data);
+    void (*tx_done)(struct rt_mbox_client *, const void *data, rt_err_t err);
+};
+
+rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl);
+rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl);
+
+rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data,
+        rt_uint32_t timeout_ms);
+void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err);
+rt_bool_t rt_mbox_peek(struct rt_mbox_chan *chan);
+rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data);
+
+struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index);
+struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name);
+rt_err_t rt_mbox_release(struct rt_mbox_chan *chan);
+
+#endif /* __MAILBOX_H__ */

+ 12 - 8
components/drivers/include/rtdevice.h

@@ -45,19 +45,23 @@ extern "C" {
 #include "drivers/core/power_domain.h"
 #include "drivers/platform.h"
 
+#ifdef RT_USING_MBOX
+#include "drivers/mailbox.h"
+#endif /* RT_USING_MBOX */
+
 #ifdef RT_USING_BLK
 #include "drivers/blk.h"
-#endif
+#endif /* RT_USING_BLK */
 
 #ifdef RT_USING_DMA
 #include "drivers/dma.h"
-#endif
+#endif /* RT_USING_DMA */
 
 #include "drivers/iio.h"
 
 #ifdef RT_USING_NVME
 #include "drivers/nvme.h"
-#endif
+#endif /* RT_USING_NVME */
 
 #ifdef RT_USING_OFW
 #include "drivers/ofw.h"
@@ -69,26 +73,26 @@ extern "C" {
 
 #ifdef RT_USING_PHYE
 #include "drivers/phye.h"
-#endif
+#endif /* RT_USING_PHYE */
 
 #ifdef RT_USING_PIC
 #include "drivers/pic.h"
-#endif
+#endif /* RT_USING_PIC */
 
 #ifdef RT_USING_SCSI
 #include "drivers/scsi.h"
-#endif
+#endif /* RT_USING_SCSI */
 
 #ifdef RT_MFD_SYSCON
 #include "drivers/syscon.h"
-#endif
+#endif /* RT_MFD_SYSCON */
 #endif /* RT_USING_DM */
 
 #ifdef RT_USING_RTC
 #include "drivers/dev_rtc.h"
 #ifdef RT_USING_ALARM
 #include "drivers/dev_alarm.h"
-#endif
+#endif /* RT_USING_ALARM */
 #endif /* RT_USING_RTC */
 
 #ifdef RT_USING_SPI

+ 14 - 0
components/drivers/mailbox/Kconfig

@@ -0,0 +1,14 @@
+menuconfig RT_USING_MBOX
+    bool "Using Hardware Mailbox device drivers"
+    depends on RT_USING_DM
+    depends on RT_USING_OFW
+    default n
+
+config RT_MBOX_PIC
+    bool "RT-Thread PIC Mailbox"
+    depends on RT_USING_MBOX
+    default y
+
+if RT_USING_MBOX
+    osource "$(SOC_DM_MBOX_DIR)/Kconfig"
+endif

+ 18 - 0
components/drivers/mailbox/SConscript

@@ -0,0 +1,18 @@
+from building import *
+
+group = []
+
+if not GetDepend(['RT_USING_MBOX']):
+    Return('group')
+
+cwd = GetCurrentDir()
+CPPPATH = [cwd + '/../include']
+
+src = ['mailbox.c']
+
+if GetDepend(['RT_MBOX_PIC']):
+    src += ['mailbox-pic.c']
+
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 280 - 0
components/drivers/mailbox/mailbox-pic.c

@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2023-09-23     GuEe-GUI     first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "mailbox.pic"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+/*
+ * RT-Thread PIC Mailbox device driver
+ *
+ * The mailbox device(s) may be instantiated in one of three equivalent way:
+ *
+ * Device Tree node, eg.:
+ *
+ *      interrupt-controller@0 {
+ *          interrupt-controller;
+ *          #interrupt-cells = <1>;
+ *      };
+ *
+ *      pic_mailbox@10000 {
+ *          compatible = "rt-thread,pic-mailbox";
+ *          reg = <0x10000 0x100>;
+ *          position = <0>;
+ *          interrupts = <34>;
+ *          peer-interrupts = <35>;
+ *          uid = <0>;
+ *          #mbox-cells = <1>;
+ *      };
+ */
+
+#define MAILBOX_IMASK       0x00
+#define MAILBOX_ISTATE      0x04
+#define MAILBOX_MSG(n)      (0x08 + (n) * 4)
+
+struct pic_mbox
+{
+    struct rt_mbox_controller parent;
+
+    void *regs;
+    void *peer_regs;
+
+    int position;
+    int chans_nr;
+    int irq;
+    int peer_hwirq;
+    struct rt_pic *pic;
+
+    struct rt_spinlock lock;
+};
+
+#define raw_to_pic_mbox(raw) rt_container_of(raw, struct pic_mbox, parent)
+
+static rt_err_t pic_mbox_request(struct rt_mbox_chan *chan)
+{
+    int index = chan - chan->ctrl->chans;
+    struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
+
+    HWREG32(pic_mbox->regs + MAILBOX_IMASK) &= ~RT_BIT(index);
+
+    return RT_EOK;
+}
+
+static void pic_mbox_release(struct rt_mbox_chan *chan)
+{
+    int index = chan - chan->ctrl->chans;
+    struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
+
+    HWREG32(pic_mbox->regs + MAILBOX_IMASK) |= RT_BIT(index);
+}
+
+static rt_err_t pic_mbox_send(struct rt_mbox_chan *chan, const void *data)
+{
+    rt_ubase_t level;
+    int index = chan - chan->ctrl->chans;
+    struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
+
+    while (HWREG32(pic_mbox->peer_regs + MAILBOX_ISTATE) & RT_BIT(index))
+    {
+        rt_thread_yield();
+    }
+
+    level = rt_spin_lock_irqsave(&pic_mbox->lock);
+
+    HWREG32(pic_mbox->regs + MAILBOX_MSG(index)) = *(rt_uint32_t *)data;
+    HWREG32(pic_mbox->peer_regs + MAILBOX_ISTATE) |= RT_BIT(index);
+    rt_hw_wmb();
+
+    rt_pic_irq_set_state_raw(pic_mbox->pic, pic_mbox->peer_hwirq,
+            RT_IRQ_STATE_PENDING, RT_TRUE);
+
+    rt_spin_unlock_irqrestore(&pic_mbox->lock, level);
+
+    return RT_EOK;
+}
+
+static const struct rt_mbox_controller_ops pic_mbox_ops =
+{
+    .request = pic_mbox_request,
+    .release = pic_mbox_release,
+    .send = pic_mbox_send,
+};
+
+static void pic_mbox_isr(int irqno, void *param)
+{
+    rt_uint32_t isr;
+    struct pic_mbox *pic_mbox = param;
+
+    isr = HWREG32(pic_mbox->regs + MAILBOX_ISTATE);
+
+    for (int idx = 0; idx < 32; ++idx)
+    {
+        rt_uint32_t msg;
+
+        if (!(RT_BIT(idx) & isr))
+        {
+            continue;
+        }
+
+        rt_hw_rmb();
+        msg = HWREG32(pic_mbox->peer_regs + MAILBOX_MSG(idx));
+
+        rt_mbox_recv(&pic_mbox->parent.chans[idx], &msg);
+    }
+
+    HWREG32(pic_mbox->regs + MAILBOX_ISTATE) &= ~isr;
+}
+
+static void pic_mbox_free_resource(struct pic_mbox *pic_mbox)
+{
+    if (pic_mbox->regs && pic_mbox->peer_regs)
+    {
+        if (pic_mbox->peer_regs > pic_mbox->regs)
+        {
+            rt_iounmap(pic_mbox->regs);
+        }
+        else
+        {
+            rt_iounmap(pic_mbox->peer_regs);
+        }
+    }
+
+    rt_free(pic_mbox);
+}
+
+static rt_err_t pic_mbox_probe(struct rt_platform_device *pdev)
+{
+    rt_err_t err;
+    rt_uint64_t size;
+    rt_uint32_t value;
+    char dev_name[RT_NAME_MAX];
+    struct rt_ofw_node *pic_np;
+    struct rt_device *dev = &pdev->parent;
+    struct pic_mbox *pic_mbox = rt_calloc(1, sizeof(*pic_mbox));
+
+    if (!pic_mbox)
+    {
+        return -RT_ENOMEM;
+    }
+
+    if ((err = rt_dm_dev_get_address(dev, 0, RT_NULL, &size)))
+    {
+        goto _fail;
+    }
+
+    if ((err = rt_dm_dev_prop_read_u32(dev, "position", &value)))
+    {
+        goto _fail;
+    }
+
+    if (!value)
+    {
+        pic_mbox->regs = rt_dm_dev_iomap(dev, 0);
+
+        if (!pic_mbox->regs)
+        {
+            goto _fail;
+        }
+
+        pic_mbox->peer_regs = pic_mbox->regs + size / 2;
+    }
+    else
+    {
+        pic_mbox->peer_regs = rt_dm_dev_iomap(dev, 0);
+
+        if (!pic_mbox->peer_regs)
+        {
+            goto _fail;
+        }
+
+        pic_mbox->regs = pic_mbox->peer_regs + size / 2;
+    }
+
+    pic_mbox->irq = rt_dm_dev_get_irq(dev, 0);
+
+    if (pic_mbox->irq < 0)
+    {
+        err = pic_mbox->irq;
+
+        goto _fail;
+    }
+
+    if ((err = rt_dm_dev_prop_read_u32(dev, "peer-interrupts", &value)))
+    {
+        goto _fail;
+    }
+    pic_mbox->peer_hwirq = value;
+
+    if ((err = rt_dm_dev_prop_read_u32(dev, "uid", &value)))
+    {
+        goto _fail;
+    }
+
+    if (!(pic_np = rt_ofw_find_irq_parent(dev->ofw_node, RT_NULL)))
+    {
+        goto _fail;
+    }
+    pic_mbox->pic = rt_ofw_data(pic_np);
+    rt_ofw_node_put(pic_np);
+
+    rt_spin_lock_init(&pic_mbox->lock);
+
+    pic_mbox->parent.dev = dev;
+    pic_mbox->parent.num_chans = 32;
+    pic_mbox->parent.ops = &pic_mbox_ops;
+
+    if ((err = rt_mbox_controller_register(&pic_mbox->parent)))
+    {
+        goto _fail;
+    }
+
+    rt_snprintf(dev_name, sizeof(dev_name), "pic-mbox%d", value);
+    rt_hw_interrupt_install(pic_mbox->irq, pic_mbox_isr, pic_mbox, dev_name);
+    rt_hw_interrupt_umask(pic_mbox->irq);
+
+    return RT_EOK;
+
+_fail:
+    pic_mbox_free_resource(pic_mbox);
+
+    return err;
+}
+
+static rt_err_t pic_mbox_remove(struct rt_platform_device *pdev)
+{
+    struct pic_mbox *pic_mbox = pdev->parent.user_data;
+
+    rt_pic_detach_irq(pic_mbox->irq, pic_mbox);
+
+    rt_mbox_controller_unregister(&pic_mbox->parent);
+
+    pic_mbox_free_resource(pic_mbox);
+
+    return RT_EOK;
+}
+
+static const struct rt_ofw_node_id pic_mbox_ofw_ids[] =
+{
+    { .compatible = "rt-thread,pic-mailbox" },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver pic_mbox_driver =
+{
+    .name = "mailbox-pic",
+    .ids = pic_mbox_ofw_ids,
+
+    .probe = pic_mbox_probe,
+    .remove = pic_mbox_remove,
+};
+RT_PLATFORM_DRIVER_EXPORT(pic_mbox_driver);

+ 348 - 0
components/drivers/mailbox/mailbox.c

@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2023-09-23     GuEe-GUI     first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define DBG_TAG "rtdm.mailbox"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <drivers/ofw.h>
+#include <drivers/mailbox.h>
+#include <drivers/platform.h>
+#include <drivers/core/rtdm.h>
+
+static struct rt_spinlock mbox_ops_lock = {};
+static rt_list_t mbox_nodes = RT_LIST_OBJECT_INIT(mbox_nodes);
+
+static void mbox_chan_timeout(void *param);
+
+rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl)
+{
+    int len;
+    struct rt_mbox_chan *chan;
+    char timer_name[RT_NAME_MAX];
+
+    if (!ctrl || !ctrl->dev || !ctrl->ops || !ctrl->num_chans)
+    {
+        return -RT_EINVAL;
+    }
+
+    ctrl->chans = rt_calloc(ctrl->num_chans, sizeof(struct rt_mbox_chan));
+
+    if (!ctrl->chans)
+    {
+        return -RT_ENOMEM;
+    }
+
+    len = rt_snprintf(timer_name, sizeof(timer_name), "%s-",
+            rt_dm_dev_get_name(ctrl->dev));
+
+    RT_ASSERT(len < sizeof(timer_name));
+
+    chan = &ctrl->chans[0];
+
+    for (int i = 0; i < ctrl->num_chans; ++i, ++chan)
+    {
+        chan->ctrl = ctrl;
+        rt_spin_lock_init(&chan->lock);
+
+        rt_snprintf(&timer_name[len], sizeof(timer_name) - len, "%d", i);
+        rt_timer_init(&chan->timer, timer_name, mbox_chan_timeout, chan,
+                0, RT_TIMER_FLAG_ONE_SHOT);
+    }
+
+    rt_list_init(&ctrl->list);
+    rt_dm_dev_bind_fwdata(ctrl->dev, RT_NULL, ctrl);
+
+    rt_spin_lock(&mbox_ops_lock);
+
+    rt_list_insert_after(&mbox_nodes, &ctrl->list);
+
+    rt_spin_unlock(&mbox_ops_lock);
+
+    return RT_EOK;
+}
+
+rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl)
+{
+    struct rt_mbox_chan *chan;
+
+    if (!ctrl)
+    {
+        return -RT_EINVAL;
+    }
+
+    rt_spin_lock(&mbox_ops_lock);
+
+    rt_dm_dev_unbind_fwdata(ctrl->dev, RT_NULL);
+    rt_list_remove(&ctrl->list);
+
+    rt_spin_unlock(&mbox_ops_lock);
+
+    chan = &ctrl->chans[0];
+
+    for (int i = ctrl->num_chans - 1; i >= 0; --i, ++chan)
+    {
+        rt_mbox_release(&ctrl->chans[i]);
+    }
+
+    rt_free(ctrl->chans);
+
+    return RT_EOK;
+}
+
+rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data,
+        rt_uint32_t timeout_ms)
+{
+    rt_err_t err;
+    rt_ubase_t level;
+    rt_bool_t timer_go = RT_FALSE;
+    struct rt_mbox_client *client;
+    struct rt_mbox_controller *ctrl;
+
+    if (!chan || !data)
+    {
+        return -RT_EINVAL;
+    }
+
+    ctrl = chan->ctrl;
+    client = chan->client;
+
+    level = rt_spin_lock_irqsave(&chan->lock);
+
+    if (client->tx_prepare)
+    {
+        client->tx_prepare(client, data);
+    }
+
+    chan->complete = RT_FALSE;
+    err = ctrl->ops->send(chan, data);
+
+    if (!err)
+    {
+        chan->data = (void *)data;
+
+        if (timeout_ms != RT_WAITING_FOREVER)
+        {
+            rt_tick_t tick = rt_tick_from_millisecond(timeout_ms);
+
+            rt_timer_control(&chan->timer, RT_TIMER_CTRL_SET_TIME, &tick);
+
+            timer_go = RT_TRUE;
+        }
+    }
+    else
+    {
+        chan->complete = RT_TRUE;
+    }
+
+    rt_spin_unlock_irqrestore(&chan->lock, level);
+
+    if (timer_go)
+    {
+        rt_timer_start(&chan->timer);
+    }
+
+    return err;
+}
+
+void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err)
+{
+    void *data;
+    rt_ubase_t level;
+
+    level = rt_spin_lock_irqsave(&chan->lock);
+
+    data = chan->data;
+    chan->data = RT_NULL;
+
+    rt_spin_unlock_irqrestore(&chan->lock, level);
+
+    if (chan->client->tx_done)
+    {
+        chan->client->tx_done(chan->client, data, err);
+    }
+
+    chan->complete = RT_TRUE;
+}
+
+static void mbox_chan_timeout(void *param)
+{
+    rt_err_t err = RT_EOK;
+    struct rt_mbox_chan *chan = param;
+
+    if (!chan->complete)
+    {
+        err = -RT_ETIMEOUT;
+    }
+
+    rt_mbox_send_done(chan, err);
+}
+
+rt_bool_t rt_mbox_peek(struct rt_mbox_chan *chan)
+{
+    if (chan && chan->ctrl->ops->peek)
+    {
+        return chan->ctrl->ops->peek(chan);
+    }
+
+    return RT_FALSE;
+}
+
+rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data)
+{
+    if (!chan || !data)
+    {
+        return -RT_EINVAL;
+    }
+
+    if (chan->client->rx_callback)
+    {
+        chan->client->rx_callback(chan->client, data);
+    }
+
+    return RT_EOK;
+}
+
+static int mbox_controller_ofw_parse_default(struct rt_mbox_controller *ctrl,
+        struct rt_ofw_cell_args *args)
+{
+    if (args->args_count != 1)
+    {
+        return -RT_EINVAL;
+    }
+
+    return args->args[0];
+}
+
+struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index)
+{
+    rt_err_t err;
+    struct rt_ofw_cell_args args;
+    struct rt_ofw_node *np, *ctrl_np;
+    struct rt_mbox_controller *ctrl;
+    struct rt_mbox_chan *chan = RT_NULL;
+
+    if (!client && index < 0)
+    {
+        return rt_err_ptr(-RT_EINVAL);
+    }
+
+    np = client->dev->ofw_node;
+
+    rt_spin_lock(&mbox_ops_lock);
+
+    err = rt_ofw_parse_phandle_cells(np, "mboxes", "#mbox-cells", index, &args);
+
+    if (err)
+    {
+        chan = rt_err_ptr(err);
+        goto _out_lock;
+    }
+
+    ctrl_np = args.data;
+
+    if (!rt_ofw_data(ctrl_np))
+    {
+        rt_platform_ofw_request(ctrl_np);
+    }
+
+    ctrl = rt_ofw_data(ctrl_np);
+    rt_ofw_node_put(ctrl_np);
+
+    if (ctrl)
+    {
+        int index;
+
+        if (ctrl->ops->ofw_parse)
+        {
+            index = ctrl->ops->ofw_parse(ctrl, &args);
+        }
+        else
+        {
+            index = mbox_controller_ofw_parse_default(ctrl, &args);
+        }
+
+        if (index >= 0)
+        {
+            chan = &ctrl->chans[index];
+        }
+        else
+        {
+            LOG_E("Parse chan from %s error = %s",
+                    rt_dm_dev_get_name(ctrl->dev), rt_strerror(index));
+
+            chan = rt_err_ptr(index);
+            goto _out_lock;
+        }
+
+        if (ctrl->ops->request)
+        {
+            rt_err_t err = ctrl->ops->request(chan);
+
+            if (err)
+            {
+                LOG_E("Request chan[%d] from %s error = %s",
+                        index, rt_dm_dev_get_name(ctrl->dev), rt_strerror(err));
+
+                rt_mbox_release(chan);
+                chan = rt_err_ptr(err);
+            }
+        }
+
+        chan->client = client;
+    }
+    else
+    {
+        chan = rt_err_ptr(-RT_ENOSYS);
+    }
+
+_out_lock:
+    rt_spin_unlock(&mbox_ops_lock);
+
+    return chan;
+}
+
+struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name)
+{
+    int index;
+    struct rt_ofw_node *np;
+
+    if (!client || !name)
+    {
+        return rt_err_ptr(-RT_EINVAL);
+    }
+
+    np = client->dev->ofw_node;
+    index = rt_ofw_prop_index_of_string(np, "mbox-names", name);
+
+    if (index < 0)
+    {
+        return RT_NULL;
+    }
+
+    return rt_mbox_request_by_index(client, index);
+}
+
+rt_err_t rt_mbox_release(struct rt_mbox_chan *chan)
+{
+    if (chan)
+    {
+        chan->ctrl->ops->release(chan);
+    }
+    else
+    {
+        return -RT_EINVAL;
+    }
+
+    return RT_EOK;
+}