mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25:19 +00:00
mailbox and remoteproc
This commit is contained in:
parent
ea57961469
commit
ec62e8fc7b
6 changed files with 125 additions and 67 deletions
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
chosen {
|
chosen {
|
||||||
stdout-path = "serial0:2000000n8";
|
stdout-path = "serial0:2000000n8";
|
||||||
bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4 dyndbg=\"file bl808_remoteproc.c +p; module bflb_ipc +p; file mailbox.c +p; file rpmsg-net.c +p;\"";
|
//bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4 dyndbg=\"file bl808_remoteproc.c +p; module bflb_ipc +p; file mailbox.c +p; file rpmsg-net.c +p;\"";
|
||||||
//bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4 dyndbg=\"file rpmsg-net.c +p;\"";
|
bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4 dyndbg=\"file rpmsg-net.c +p;\"";
|
||||||
linux,initrd-start = <0x0 0x52000000>;
|
linux,initrd-start = <0x0 0x52000000>;
|
||||||
linux,initrd-end = <0x0 0x52941784>;
|
linux,initrd-end = <0x0 0x52941784>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -172,7 +172,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
rproc: rproc@22054000 {
|
rproc: rproc@22054000 {
|
||||||
compatible = "bflb,bl808-rproc";
|
compatible = "bflb,bflb-rproc";
|
||||||
reg = <0x22054000 0x4000>;
|
reg = <0x22054000 0x4000>;
|
||||||
memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>;
|
memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>;
|
||||||
mboxes = <&ipclic BFLB_IPC_TARGET_M0 BFLB_IPC_MBOX_VIRTIO BFLB_IPC_MBOX_VIRTIO_OP_KICK>,
|
mboxes = <&ipclic BFLB_IPC_TARGET_M0 BFLB_IPC_MBOX_VIRTIO BFLB_IPC_MBOX_VIRTIO_OP_KICK>,
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <linux/bflb-mailbox.h>
|
||||||
#include <dt-bindings/mailbox/bflb-ipc.h>
|
#include <dt-bindings/mailbox/bflb-ipc.h>
|
||||||
|
|
||||||
/* IPC Register offsets */
|
/* IPC Register offsets */
|
||||||
|
@ -65,8 +66,7 @@ static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mboxctlr)
|
||||||
|
|
||||||
static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device)
|
static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device)
|
||||||
{
|
{
|
||||||
pr_debug("%s: source: %u, device: %u\n", __func__, source, device);
|
// dev_dbg("%s: source: %u, device: %u\n", __func__, source, device);
|
||||||
|
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device)
|
||||||
static void bflb_ipc_dump_regs(struct bflb_ipc *ipc)
|
static void bflb_ipc_dump_regs(struct bflb_ipc *ipc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
dev_dbg(ipc->dev, "base %px %d\n", ipc->base[i], i);
|
dev_dbg(ipc->dev, "base %px %d\n", ipc->base[i], i);
|
||||||
dev_dbg(ipc->dev, "ISWR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISWR));
|
dev_dbg(ipc->dev, "ISWR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISWR));
|
||||||
|
@ -90,7 +91,8 @@ static void bflb_ipc_dump_regs(struct bflb_ipc *ipc)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct mbox_chan *bflb_mbox_find_chan(struct bflb_ipc *ipc, struct bflb_ipc_chan_info *chaninfo) {
|
struct mbox_chan *bflb_mbox_find_chan(struct bflb_ipc *ipc, struct bflb_ipc_chan_info *chaninfo)
|
||||||
|
{
|
||||||
struct bflb_ipc_chan_info *mchan;
|
struct bflb_ipc_chan_info *mchan;
|
||||||
struct mbox_controller *mboxctlr = &ipc->mboxctlr;
|
struct mbox_controller *mboxctlr = &ipc->mboxctlr;
|
||||||
struct mbox_chan *chan;
|
struct mbox_chan *chan;
|
||||||
|
@ -99,8 +101,6 @@ struct mbox_chan *bflb_mbox_find_chan(struct bflb_ipc *ipc, struct bflb_ipc_chan
|
||||||
|
|
||||||
dev = ipc->dev;
|
dev = ipc->dev;
|
||||||
|
|
||||||
//dev_dbg(dev, "%s Find Chan %d %d %d\n", __func__, chaninfo->cpu_id, chaninfo->service_id, chaninfo->op_id);
|
|
||||||
|
|
||||||
for (chan_id = 0; chan_id < mboxctlr->num_chans; chan_id++) {
|
for (chan_id = 0; chan_id < mboxctlr->num_chans; chan_id++) {
|
||||||
chan = &ipc->chans[chan_id];
|
chan = &ipc->chans[chan_id];
|
||||||
mchan = chan->con_priv;
|
mchan = chan->con_priv;
|
||||||
|
@ -127,36 +127,32 @@ static void bflb_mbox_rx_irq_fn(int from_cpu, struct bflb_ipc *ipc)
|
||||||
{
|
{
|
||||||
struct mbox_chan *chan;
|
struct mbox_chan *chan;
|
||||||
struct bflb_ipc_chan_info bflbchan;
|
struct bflb_ipc_chan_info bflbchan;
|
||||||
|
struct bflb_mbox_msg msg;
|
||||||
|
u32 sig_op;
|
||||||
|
|
||||||
/* update this when we support LP */
|
/* update this when we support LP */
|
||||||
u32 sig_op = readl(ipc->base[1] + IPC_REG_ILSHR);
|
sig_op = readl(ipc->base[1] + IPC_REG_ILSHR);
|
||||||
u32 param = readl(ipc->base[1] + IPC_REG_ILSLR);
|
msg.param = readl(ipc->base[1] + IPC_REG_ILSLR);
|
||||||
|
|
||||||
WARN_ON(sig_op == 0);
|
WARN_ON(sig_op == 0);
|
||||||
|
|
||||||
|
|
||||||
bflbchan.cpu_id = from_cpu;
|
bflbchan.cpu_id = from_cpu;
|
||||||
bflbchan.service_id = (sig_op >> 16) & 0xFFFF;
|
bflbchan.service_id = (sig_op >> 16) & 0xFFFF;
|
||||||
bflbchan.op_id = sig_op & 0xFFFF;
|
bflbchan.op_id = sig_op & 0xFFFF;
|
||||||
|
|
||||||
|
|
||||||
chan = bflb_mbox_find_chan(ipc, &bflbchan);
|
chan = bflb_mbox_find_chan(ipc, &bflbchan);
|
||||||
if (IS_ERR(chan)) {
|
if (IS_ERR(chan)) {
|
||||||
dev_err(ipc->dev, "no channel for signal cpu_id: %d service: %d op: %d\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id);
|
dev_err(ipc->dev, "no channel for signal cpu_id: %d service: %d op: %d\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(ipc->dev, "Got MBOX Signal cpu: %d service %d op %d param %x\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param);
|
dev_dbg(ipc->dev, "Got MBOX Signal cpu: %d service %d op %d param %x\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, msg.param);
|
||||||
|
|
||||||
mbox_chan_received_data(chan, param);
|
mbox_chan_received_data(chan, &msg);
|
||||||
|
|
||||||
dev_info(ipc->dev, "bflb_mbox_rx\r\n");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when we get a interupt back on our TX IRQ.
|
/* called when we get a interupt back on our TX IRQ.
|
||||||
* This is usualy a EOI interupt
|
* This is a EOI interupt
|
||||||
*/
|
*/
|
||||||
static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc)
|
static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc)
|
||||||
{
|
{
|
||||||
|
@ -164,6 +160,7 @@ static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc)
|
||||||
struct bflb_ipc_chan_info bflbchan;
|
struct bflb_ipc_chan_info bflbchan;
|
||||||
|
|
||||||
u32 sig_op = readl(ipc->base[2] + IPC_REG_ILSHR);
|
u32 sig_op = readl(ipc->base[2] + IPC_REG_ILSHR);
|
||||||
|
u32 param = readl(ipc->base[2] + IPC_REG_ILSLR);
|
||||||
|
|
||||||
bflbchan.cpu_id = from_cpu;
|
bflbchan.cpu_id = from_cpu;
|
||||||
bflbchan.service_id = (sig_op >> 16) & 0xFFFF;
|
bflbchan.service_id = (sig_op >> 16) & 0xFFFF;
|
||||||
|
@ -171,15 +168,17 @@ static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc)
|
||||||
|
|
||||||
chan = bflb_mbox_find_chan(ipc, &bflbchan);
|
chan = bflb_mbox_find_chan(ipc, &bflbchan);
|
||||||
if (IS_ERR(chan)) {
|
if (IS_ERR(chan)) {
|
||||||
dev_err(ipc->dev, "no channel for EOI signal cpu_id: %d service: %d op: %d\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id);
|
dev_err(ipc->dev, "no channel for EOI signal cpu_id: %d service: %d op: %d Param: %d $$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(ipc->dev, "Got MBOX EOI Signal cpu: %d service %d op %d\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id);
|
dev_dbg(ipc->dev, "Got MBOX EOI Signal cpu: %d service %d op %d Param: %d $$$$$$$$$$$$$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param);
|
||||||
|
|
||||||
|
/* clear the IPC_REG_ILSLR and IPC_REG_ILSHR */
|
||||||
|
writel(0, ipc->base[2] + IPC_REG_ILSLR);
|
||||||
|
writel(0, ipc->base[2] + IPC_REG_ILSHR);
|
||||||
|
|
||||||
mbox_chan_txdone(chan, 0);
|
mbox_chan_txdone(chan, 0);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t bflb_ipc_irq_fn(int irq, void *data)
|
static irqreturn_t bflb_ipc_irq_fn(int irq, void *data)
|
||||||
|
@ -263,47 +262,61 @@ static const struct irq_domain_ops bflb_ipc_irq_ops = {
|
||||||
.xlate = bflb_ipc_domain_xlate,
|
.xlate = bflb_ipc_domain_xlate,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* JH: Figure out if M0 has processed the last signal sent
|
#if 0
|
||||||
* by checking if the High/Low registers are cleared
|
/* Shouldn't actually be fail as we clear the High/Low registers in a EOI
|
||||||
|
* but this protects if we screw up our mailbox handling
|
||||||
*/
|
*/
|
||||||
static bool bflb_ipc_mbox_can_send(struct mbox_chan *chan)
|
static bool bflb_ipc_mbox_can_send(struct mbox_chan *chan)
|
||||||
{
|
{
|
||||||
struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox);
|
struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox);
|
||||||
|
|
||||||
u32 mbox_high = readl(ipc->base[2] + IPC_REG_ILSHR);
|
/* check the low register first as we clear that last in our EOI, so this
|
||||||
|
* should protected to a limited extent
|
||||||
|
*/
|
||||||
u32 mbox_low = readl(ipc->base[2] + IPC_REG_ILSLR);
|
u32 mbox_low = readl(ipc->base[2] + IPC_REG_ILSLR);
|
||||||
|
u32 mbox_high = readl(ipc->base[2] + IPC_REG_ILSHR);
|
||||||
|
|
||||||
dev_dbg(ipc->dev, "%s: low: 0x%08x high: 0x%08x\r\n", __func__, mbox_low, mbox_high);
|
|
||||||
|
if (mbox_low | mbox_high)
|
||||||
|
dev_warn_ratelimited(ipc->dev, "%s: low: 0x%08x high: 0x%08x\r\n", __func__, mbox_low, mbox_high);
|
||||||
|
|
||||||
|
writel(0, ipc->base[2] + IPC_REG_ILSLR);
|
||||||
|
writel(0, ipc->base[2] + IPC_REG_ILSHR);
|
||||||
|
|
||||||
return !(mbox_low | mbox_high);
|
return !(mbox_low | mbox_high);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data)
|
static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data)
|
||||||
{
|
{
|
||||||
struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox);
|
struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox);
|
||||||
struct bflb_ipc_chan_info *mchan = chan->con_priv;
|
struct bflb_ipc_chan_info *mchan = chan->con_priv;
|
||||||
int *param = data;
|
struct bflb_mbox_msg *msg = data;
|
||||||
u32 tmpVal = (mchan->service_id << 16) | (mchan->op_id & 0xFFFF);
|
u32 tmpVal = (mchan->service_id << 16) | (mchan->op_id & 0xFFFF);
|
||||||
|
|
||||||
dev_dbg(ipc->dev, "%s: cpu: %d singal: %d op: %d (0x%x) param: %d\n", __func__, mchan->cpu_id, mchan->service_id, mchan->op_id, tmpVal, *param);
|
#if 0
|
||||||
|
if (!bflb_ipc_mbox_can_send(chan))
|
||||||
|
return -EBUSY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dev_dbg(ipc->dev, "%s %d: cpu: %d singal: %d op: %d (0x%x) param: %d", __func__, msg->id, mchan->cpu_id, mchan->service_id, mchan->op_id, tmpVal, msg->param);
|
||||||
|
|
||||||
// /* write our signal number to high register */
|
// /* write our signal number to high register */
|
||||||
writel(tmpVal, ipc->base[2] + IPC_REG_ILSHR);
|
writel(tmpVal, ipc->base[2] + IPC_REG_ILSHR);
|
||||||
// /* write our data to low register */
|
// /* write our data to low register */
|
||||||
writel(*param, ipc->base[2] + IPC_REG_ILSLR);
|
writel(msg->param, ipc->base[2] + IPC_REG_ILSLR);
|
||||||
|
|
||||||
/* and now kick the remote processor */
|
/* and now kick the remote processor */
|
||||||
writel((1 << BFLB_IPC_DEVICE_MBOX_TX), ipc->base[2] + IPC_REG_ISWR);
|
writel((1 << BFLB_IPC_DEVICE_MBOX_TX), ipc->base[2] + IPC_REG_ISWR);
|
||||||
dev_dbg(ipc->dev, "%s: done\r\n", __func__);
|
dev_dbg(ipc->dev, "%s %d: done param: %d", __func__, msg->id, msg->param);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bflb_ipc_mbox_shutdown(struct mbox_chan *chan)
|
static void bflb_ipc_mbox_shutdown(struct mbox_chan *chan)
|
||||||
{
|
{
|
||||||
pr_debug("%s\n", __func__);
|
struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox);
|
||||||
|
|
||||||
|
dev_dbg(ipc->dev, "%s\n", __func__);
|
||||||
chan->con_priv = NULL;
|
chan->con_priv = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +333,7 @@ static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mboxctlr,
|
||||||
dev_dbg(dev, "%s\n", __func__);
|
dev_dbg(dev, "%s\n", __func__);
|
||||||
|
|
||||||
if (ph->args_count != 3) {
|
if (ph->args_count != 3) {
|
||||||
pr_debug("invalid number of arguments");
|
dev_err(dev, "invalid number of arguments");
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,21 +346,20 @@ static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mboxctlr,
|
||||||
else if (mchan->cpu_id == ph->args[0] &&
|
else if (mchan->cpu_id == ph->args[0] &&
|
||||||
mchan->service_id == ph->args[1] &&
|
mchan->service_id == ph->args[1] &&
|
||||||
mchan->op_id == ph->args[2]) {
|
mchan->op_id == ph->args[2]) {
|
||||||
pr_debug("channel already in use %d %d %d", ph->args[0], ph->args[1], ph->args[2]);
|
dev_err(dev, "channel already in use %d %d %d", ph->args[0], ph->args[1], ph->args[2]);
|
||||||
return ERR_PTR(-EBUSY);
|
return ERR_PTR(-EBUSY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan_id >= mboxctlr->num_chans) {
|
if (chan_id >= mboxctlr->num_chans) {
|
||||||
pr_debug("no free channels");
|
dev_err(dev, "no free channels");
|
||||||
return ERR_PTR(-EBUSY);
|
return ERR_PTR(-EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
mchan = devm_kzalloc(dev, sizeof(*mchan), GFP_KERNEL);
|
mchan = devm_kzalloc(dev, sizeof(*mchan), GFP_KERNEL);
|
||||||
if (!mchan) {
|
if (!mchan)
|
||||||
pr_debug("no memory for channel");
|
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
|
||||||
mchan->cpu_id = ph->args[0];
|
mchan->cpu_id = ph->args[0];
|
||||||
mchan->service_id = ph->args[1];
|
mchan->service_id = ph->args[1];
|
||||||
mchan->op_id = ph->args[2];
|
mchan->op_id = ph->args[2];
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/remoteproc.h>
|
#include <linux/remoteproc.h>
|
||||||
#include <linux/mailbox_client.h>
|
#include <linux/mailbox_client.h>
|
||||||
|
#include <linux/mailbox_controller.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/bflb-mailbox.h>
|
||||||
#include "remoteproc_internal.h"
|
#include "remoteproc_internal.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,8 +234,6 @@ static int bflb_rproc_stop(struct rproc *rproc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <linux/mailbox_controller.h>
|
|
||||||
|
|
||||||
/* kick the virtqueue to let M0 know there is a update to the vring */
|
/* kick the virtqueue to let M0 know there is a update to the vring */
|
||||||
static void bflb_rproc_send_kick(struct rproc *rproc, int vqid)
|
static void bflb_rproc_send_kick(struct rproc *rproc, int vqid)
|
||||||
{
|
{
|
||||||
|
@ -241,27 +241,51 @@ static void bflb_rproc_send_kick(struct rproc *rproc, int vqid)
|
||||||
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
||||||
struct bflb_mbox *mb = &drproc->mbox_tx;
|
struct bflb_mbox *mb = &drproc->mbox_tx;
|
||||||
struct mbox_chan *chan = mb->chan;
|
struct mbox_chan *chan = mb->chan;
|
||||||
|
struct bflb_mbox_msg *msg;
|
||||||
int ret;
|
int ret;
|
||||||
|
int i;
|
||||||
|
static int count;
|
||||||
|
|
||||||
|
/* just for debugging atm */
|
||||||
|
count++;
|
||||||
|
|
||||||
|
msg = kzalloc(sizeof(struct bflb_mbox_msg), GFP_KERNEL);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* we need a small delay before kicking the other side
|
||||||
|
* (I assume to allow the ring to update/flush etc?)
|
||||||
|
* without this, we get lots of "empty ring" messages on the
|
||||||
|
* other side
|
||||||
|
*/
|
||||||
|
mdelay(1);
|
||||||
|
|
||||||
|
msg->param = vqid;
|
||||||
|
msg->id = count;
|
||||||
/* Kick the other CPU to let it know the vrings are updated */
|
/* Kick the other CPU to let it know the vrings are updated */
|
||||||
dev_info(dev, "%s Mailbox: %s %d", __func__, mb->name, vqid);
|
dev_dbg(dev, "%s %d Mailbox: %s %d", __func__, msg->id, mb->name, msg->param);
|
||||||
ret = mbox_send_message(chan, &vqid);
|
/* we occasionally get a EOI timeout, so retry upto 3 times */
|
||||||
if (!ret) {
|
for (i = 0; i < 3; i++) {
|
||||||
dev_err(dev, "%s Mailbox %s sending %d Failed: %d", __func__, mb->name, vqid, ret);
|
ret = mbox_send_message(chan, msg);
|
||||||
} else {
|
if (ret >= 0)
|
||||||
dev_info(dev, "%s Mailbox %s done %d size: %d free: %d: %d", __func__, mb->name, vqid, chan->msg_count, chan->msg_free, ret);
|
goto done;
|
||||||
|
dev_warn(dev, "%s %d Mailbox %s sending %d Failed: %d - Retrying %d", __func__, msg->id, mb->name, msg->param, ret, i);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
dev_dbg(dev, "%s %d Mailbox %s done %d: %d", __func__, msg->id, mb->name, msg->param, ret);
|
||||||
|
kfree(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void bflb_rproc_recv_kick(struct work_struct *work)
|
static void bflb_rproc_recv_kick(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct bflb_mbox *mb = container_of(work, struct bflb_mbox, vq_work);
|
struct bflb_mbox *mb = container_of(work, struct bflb_mbox, vq_work);
|
||||||
struct rproc *rproc = dev_get_drvdata(mb->client.dev);
|
struct rproc *rproc = dev_get_drvdata(mb->client.dev);
|
||||||
|
|
||||||
dev_info(rproc->dev.parent, "%s mailbox: %s: %d", __func__, mb->name, mb->vq_id);
|
dev_dbg(rproc->dev.parent, "%s mailbox: %s: %d", __func__, mb->name, mb->vq_id);
|
||||||
|
|
||||||
|
/* not a bad thing if there is no messages, probably
|
||||||
|
* means that the previous ring kick processed the message
|
||||||
|
*/
|
||||||
if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
|
if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
|
||||||
dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
|
dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
|
||||||
}
|
}
|
||||||
|
@ -274,12 +298,11 @@ static void bflb_rproc_rx_mbox_callback(struct mbox_client *client, void *data)
|
||||||
struct rproc *rproc = dev_get_drvdata(dev);
|
struct rproc *rproc = dev_get_drvdata(dev);
|
||||||
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
||||||
struct bflb_mbox *mb = &drproc->mbox_rx;
|
struct bflb_mbox *mb = &drproc->mbox_rx;
|
||||||
|
struct bflb_mbox_msg *msg = data;
|
||||||
|
|
||||||
mb->vq_id = (int)data;
|
mb->vq_id = msg->param;
|
||||||
|
|
||||||
dev_info(dev, "%s mailbox %s: %d", __func__, mb->name, mb->vq_id);
|
|
||||||
|
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s mailbox %s: %d", __func__, mb->name, mb->vq_id);
|
||||||
|
|
||||||
queue_work(drproc->workqueue, &mb->vq_work);
|
queue_work(drproc->workqueue, &mb->vq_work);
|
||||||
mbox_chan_txdone(mb->chan, 0);
|
mbox_chan_txdone(mb->chan, 0);
|
||||||
|
@ -318,7 +341,8 @@ static const struct rproc_ops bflb_rproc_ops = {
|
||||||
.get_loaded_rsc_table = bflb_rproc_get_loaded_rsc_table,
|
.get_loaded_rsc_table = bflb_rproc_get_loaded_rsc_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bflb_rproc_setup_mbox(struct rproc *rproc) {
|
static int bflb_rproc_setup_mbox(struct rproc *rproc)
|
||||||
|
{
|
||||||
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv;
|
||||||
|
|
||||||
struct bflb_mbox *tx_bflb_mbox = &drproc->mbox_tx;
|
struct bflb_mbox *tx_bflb_mbox = &drproc->mbox_tx;
|
||||||
|
@ -335,7 +359,7 @@ static int bflb_rproc_setup_mbox(struct rproc *rproc) {
|
||||||
/* request the TX mailboxs */
|
/* request the TX mailboxs */
|
||||||
tx_mbox_cl->dev = dev->parent;
|
tx_mbox_cl->dev = dev->parent;
|
||||||
tx_mbox_cl->tx_block = true;
|
tx_mbox_cl->tx_block = true;
|
||||||
tx_mbox_cl->tx_tout = 100;
|
tx_mbox_cl->tx_tout = 200;
|
||||||
strncpy(tx_bflb_mbox->name, "virtio-tx", sizeof(tx_bflb_mbox->name));
|
strncpy(tx_bflb_mbox->name, "virtio-tx", sizeof(tx_bflb_mbox->name));
|
||||||
tx_bflb_mbox->chan = mbox_request_channel_byname(tx_mbox_cl, "virtio-tx");
|
tx_bflb_mbox->chan = mbox_request_channel_byname(tx_mbox_cl, "virtio-tx");
|
||||||
if (IS_ERR(tx_bflb_mbox->chan)) {
|
if (IS_ERR(tx_bflb_mbox->chan)) {
|
||||||
|
@ -397,6 +421,8 @@ static int bflb_rproc_probe(struct platform_device *pdev)
|
||||||
drproc = rproc->priv;
|
drproc = rproc->priv;
|
||||||
drproc->rproc = rproc;
|
drproc->rproc = rproc;
|
||||||
rproc->has_iommu = false;
|
rproc->has_iommu = false;
|
||||||
|
rproc->sysfs_read_only = true;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, rproc);
|
platform_set_drvdata(pdev, rproc);
|
||||||
|
|
||||||
drproc->workqueue = create_workqueue(dev_name(dev));
|
drproc->workqueue = create_workqueue(dev_name(dev));
|
||||||
|
@ -456,7 +482,7 @@ static int bflb_rproc_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = {
|
static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = {
|
||||||
{ .compatible = "bflb,bl808-rproc", },
|
{ .compatible = "bflb,bflb-rproc", },
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, davinci_rproc_of_match);
|
MODULE_DEVICE_TABLE(of, davinci_rproc_of_match);
|
||||||
|
@ -465,7 +491,7 @@ static struct platform_driver bflb_rproc_driver = {
|
||||||
.probe = bflb_rproc_probe,
|
.probe = bflb_rproc_probe,
|
||||||
.remove = bflb_rproc_remove,
|
.remove = bflb_rproc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "bl808-rproc",
|
.name = "bflb-rproc",
|
||||||
.of_match_table = of_match_ptr(davinci_rproc_of_match),
|
.of_match_table = of_match_ptr(davinci_rproc_of_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,7 +92,8 @@ static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len)
|
||||||
* Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not
|
* Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not
|
||||||
* hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM.
|
* hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM.
|
||||||
*/
|
*/
|
||||||
ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size);
|
/* for bl808, we only have a few small buffers, and a slow M0 CPU, so lets use rpmsg_send */
|
||||||
|
ret = rpmsg_send(rpdev->ept, (void *)buf, msg_size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
|
dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
19
include/linux/bflb-mailbox.h
Normal file
19
include/linux/bflb-mailbox.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
||||||
|
/*
|
||||||
|
* BL808 mailbox message format
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 The Asahi Linux Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_BFLB_MAILBOX_H_
|
||||||
|
#define _LINUX_BFLB_MAILBOX_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* encodes a single 32bit message sent over the single channel */
|
||||||
|
struct bflb_mbox_msg {
|
||||||
|
u32 param;
|
||||||
|
u32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue