[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>
This commit is contained in:
parent
8ed4ae144f
commit
f849afb5ca
|
@ -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"
|
||||
|
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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')
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue