media: allegro: rework mbox handling

Add a send/notify abstraction for the mailbox and separate the message
handling in the driver from the code to read and write message to the
mailbox.

This untangles how mails are written into the MCU's SRAM and signaled to
the MCU from the protocol between the driver and the firmware.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Michael Tretter 2020-07-13 16:42:18 +02:00 committed by Mauro Carvalho Chehab
parent f2f475e4c5
commit 94dc765602

View File

@ -105,9 +105,11 @@ struct allegro_buffer {
struct list_head head;
};
struct allegro_dev;
struct allegro_channel;
struct allegro_mbox {
struct allegro_dev *dev;
unsigned int head;
unsigned int tail;
unsigned int data;
@ -134,8 +136,8 @@ struct allegro_dev {
struct completion init_complete;
/* The mailbox interface */
struct allegro_mbox mbox_command;
struct allegro_mbox mbox_status;
struct allegro_mbox *mbox_command;
struct allegro_mbox *mbox_status;
/*
* The downstream driver limits the users to 64 users, thus I can use
@ -583,12 +585,20 @@ static void allegro_free_buffer(struct allegro_dev *dev,
* Mailbox interface to send messages to the MCU.
*/
static int allegro_mbox_init(struct allegro_dev *dev,
struct allegro_mbox *mbox,
unsigned int base, size_t size)
static void allegro_mcu_interrupt(struct allegro_dev *dev);
static void allegro_handle_message(struct allegro_dev *dev,
union mcu_msg_response *msg);
static struct allegro_mbox *allegro_mbox_init(struct allegro_dev *dev,
unsigned int base, size_t size)
{
struct allegro_mbox *mbox;
mbox = devm_kmalloc(&dev->plat_dev->dev, sizeof(*mbox), GFP_KERNEL);
if (!mbox)
return -EINVAL;
return ERR_PTR(-ENOMEM);
mbox->dev = dev;
mbox->head = base;
mbox->tail = base + 0x4;
@ -599,7 +609,7 @@ static int allegro_mbox_init(struct allegro_dev *dev,
regmap_write(dev->sram, mbox->head, 0);
regmap_write(dev->sram, mbox->tail, 0);
return 0;
return mbox;
}
static int allegro_mbox_write(struct allegro_dev *dev,
@ -713,9 +723,50 @@ static ssize_t allegro_mbox_read(struct allegro_dev *dev,
return size;
}
static void allegro_mcu_interrupt(struct allegro_dev *dev)
/**
* allegro_mbox_send() - Send a message via the mailbox
* @mbox: the mailbox which is used to send the message
* @msg: the message to send
*/
static int allegro_mbox_send(struct allegro_mbox *mbox, void *msg)
{
regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0));
struct allegro_dev *dev = mbox->dev;
struct mcu_msg_header *header = msg;
ssize_t size = sizeof(*header) + header->length;
int err;
err = allegro_mbox_write(dev, mbox, msg, size);
if (err)
goto out;
allegro_mcu_interrupt(dev);
out:
return err;
}
/**
* allegro_mbox_notify() - Notify the mailbox about a new message
* @mbox: The allegro_mbox to notify
*/
static void allegro_mbox_notify(struct allegro_mbox *mbox)
{
struct allegro_dev *dev = mbox->dev;
union mcu_msg_response *msg;
ssize_t size;
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return;
size = allegro_mbox_read(dev, mbox, msg, sizeof(*msg));
if (size < 0)
goto out;
allegro_handle_message(dev, msg);
out:
kfree(msg);
}
static void allegro_mcu_send_init(struct allegro_dev *dev,
@ -736,8 +787,7 @@ static void allegro_mcu_send_init(struct allegro_dev *dev,
msg.l2_cache[1] = -1;
msg.l2_cache[2] = -1;
allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
allegro_mcu_interrupt(dev);
allegro_mbox_send(dev->mbox_command, &msg);
}
static u32 v4l2_pixelformat_to_mcu_format(u32 pixelformat)
@ -946,8 +996,7 @@ static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
fill_create_channel_param(channel, &msg.param);
allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
allegro_mcu_interrupt(dev);
allegro_mbox_send(dev->mbox_command, &msg);
return 0;
}
@ -964,8 +1013,7 @@ static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev,
msg.channel_id = channel->mcu_channel_id;
allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
allegro_mcu_interrupt(dev);
allegro_mbox_send(dev->mbox_command, &msg);
return 0;
}
@ -991,8 +1039,7 @@ static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
/* copied to mcu_msg_encode_frame_response */
msg.stream_id = stream_id;
allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
allegro_mcu_interrupt(dev);
allegro_mbox_send(dev->mbox_command, &msg);
return 0;
}
@ -1021,8 +1068,7 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
msg.ep2 = 0x0;
msg.ep2_v = to_mcu_addr(dev, msg.ep2);
allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
allegro_mcu_interrupt(dev);
allegro_mbox_send(dev->mbox_command, &msg);
return 0;
}
@ -1084,12 +1130,8 @@ static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel,
buffer++;
}
err = allegro_mbox_write(dev, &dev->mbox_command, msg, size);
if (err)
goto out;
allegro_mcu_interrupt(dev);
err = allegro_mbox_send(dev->mbox_command, msg);
out:
kfree(msg);
return err;
}
@ -1681,51 +1723,28 @@ allegro_handle_encode_frame(struct allegro_dev *dev,
return 0;
}
static int allegro_receive_message(struct allegro_dev *dev)
static void allegro_handle_message(struct allegro_dev *dev,
union mcu_msg_response *msg)
{
union mcu_msg_response *msg;
ssize_t size;
int err = 0;
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
size = allegro_mbox_read(dev, &dev->mbox_status, msg, sizeof(*msg));
if (size < sizeof(msg->header)) {
v4l2_err(&dev->v4l2_dev,
"invalid mbox message (%zd): must be at least %zu\n",
size, sizeof(msg->header));
err = -EINVAL;
goto out;
}
switch (msg->header.type) {
case MCU_MSG_TYPE_INIT:
err = allegro_handle_init(dev, &msg->init);
allegro_handle_init(dev, &msg->init);
break;
case MCU_MSG_TYPE_CREATE_CHANNEL:
err = allegro_handle_create_channel(dev, &msg->create_channel);
allegro_handle_create_channel(dev, &msg->create_channel);
break;
case MCU_MSG_TYPE_DESTROY_CHANNEL:
err = allegro_handle_destroy_channel(dev,
&msg->destroy_channel);
allegro_handle_destroy_channel(dev, &msg->destroy_channel);
break;
case MCU_MSG_TYPE_ENCODE_FRAME:
err = allegro_handle_encode_frame(dev, &msg->encode_frame);
allegro_handle_encode_frame(dev, &msg->encode_frame);
break;
default:
v4l2_warn(&dev->v4l2_dev,
"%s: unknown message %s\n",
__func__, msg_type_name(msg->header.type));
err = -EINVAL;
break;
}
out:
kfree(msg);
return err;
}
static irqreturn_t allegro_hardirq(int irq, void *data)
@ -1746,7 +1765,7 @@ static irqreturn_t allegro_irq_thread(int irq, void *data)
{
struct allegro_dev *dev = data;
allegro_receive_message(dev);
allegro_mbox_notify(dev->mbox_status);
return IRQ_HANDLED;
}
@ -1895,6 +1914,11 @@ static int allegro_mcu_reset(struct allegro_dev *dev)
return allegro_mcu_wait_for_sleep(dev);
}
static void allegro_mcu_interrupt(struct allegro_dev *dev)
{
regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0));
}
static void allegro_destroy_channel(struct allegro_channel *channel)
{
struct allegro_dev *dev = channel->dev;
@ -2887,10 +2911,15 @@ static int allegro_mcu_hw_init(struct allegro_dev *dev,
{
int err;
allegro_mbox_init(dev, &dev->mbox_command,
info->mailbox_cmd, info->mailbox_size);
allegro_mbox_init(dev, &dev->mbox_status,
info->mailbox_status, info->mailbox_size);
dev->mbox_command = allegro_mbox_init(dev, info->mailbox_cmd,
info->mailbox_size);
dev->mbox_status = allegro_mbox_init(dev, info->mailbox_status,
info->mailbox_size);
if (!dev->mbox_command || !dev->mbox_status) {
v4l2_err(&dev->v4l2_dev,
"failed to initialize mailboxes\n");
return -EIO;
}
allegro_mcu_enable_interrupts(dev);