summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGUI <[email protected]>2024-11-25 11:00:04 +0800
committerGitHub <[email protected]>2024-11-25 11:00:04 +0800
commitf849afb5ca40f4843d86d6bd55253b2db57a7ad4 (patch)
tree5ea0287d22459c1df3753d29a2247fc336fb0347
parent8ed4ae144fda951d7a3f5ffbfbf810b1ce1bf2c8 (diff)
[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 <[email protected]>
-rwxr-xr-xcomponents/drivers/Kconfig1
-rw-r--r--components/drivers/include/drivers/mailbox.h77
-rw-r--r--components/drivers/include/rtdevice.h20
-rw-r--r--components/drivers/mailbox/Kconfig14
-rwxr-xr-xcomponents/drivers/mailbox/SConscript18
-rw-r--r--components/drivers/mailbox/mailbox-pic.c280
-rw-r--r--components/drivers/mailbox/mailbox.c348
7 files changed, 750 insertions, 8 deletions
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index 0d950cd354..783215f026 100755
--- a/components/drivers/Kconfig
+++ b/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"
diff --git a/components/drivers/include/drivers/mailbox.h b/components/drivers/include/drivers/mailbox.h
new file mode 100644
index 0000000000..954cd628e6
--- /dev/null
+++ b/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__ */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index ceb02485e3..aa56b6820c 100644
--- a/components/drivers/include/rtdevice.h
+++ b/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
diff --git a/components/drivers/mailbox/Kconfig b/components/drivers/mailbox/Kconfig
new file mode 100644
index 0000000000..9531d3a2dd
--- /dev/null
+++ b/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
diff --git a/components/drivers/mailbox/SConscript b/components/drivers/mailbox/SConscript
new file mode 100755
index 0000000000..f26a44b0ce
--- /dev/null
+++ b/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')
diff --git a/components/drivers/mailbox/mailbox-pic.c b/components/drivers/mailbox/mailbox-pic.c
new file mode 100644
index 0000000000..187abe0122
--- /dev/null
+++ b/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);
diff --git a/components/drivers/mailbox/mailbox.c b/components/drivers/mailbox/mailbox.c
new file mode 100644
index 0000000000..84b9f11247
--- /dev/null
+++ b/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;
+}