From a834f4e143ff647e7677dc60ab57ee5883f3ac8f Mon Sep 17 00:00:00 2001 From: Emekcan Date: Wed, 17 Aug 2022 14:21:42 +0100 Subject: [PATCH] Add rpmsg driver for corstone1000 Adds rpmsg driver to communicate with external system in corstone1000 platform. Upstream-Status: Pending Signed-off-by: Emekcan Aras Signed-off-by: Rui Miguel Silva --- drivers/rpmsg/Kconfig | 10 ++ drivers/rpmsg/Makefile | 1 + drivers/rpmsg/rpmsg_arm_mailbox.c | 164 ++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 drivers/rpmsg/rpmsg_arm_mailbox.c diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index d3795860f5c0..fc6916d7b523 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -81,4 +81,14 @@ config RPMSG_VIRTIO select RPMSG_NS select VIRTIO +config RPMSG_ARM + tristate "ARM RPMSG driver" + select RPMSG + depends on HAS_IOMEM + depends on MAILBOX + help + Say y here to enable support for rpmsg lient driver which is built + around mailbox client using Arm MHUv2.1 as physical medium.This + driver enables communication which remote processor using MHU. + endmenu diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 58e3b382e316..6bdcc69688b2 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_RPMSG) += rpmsg_core.o +obj-$(CONFIG_RPMSG_ARM) += rpmsg_arm_mailbox.o obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o diff --git a/drivers/rpmsg/rpmsg_arm_mailbox.c b/drivers/rpmsg/rpmsg_arm_mailbox.c new file mode 100644 index 000000000000..4a80102669f6 --- /dev/null +++ b/drivers/rpmsg/rpmsg_arm_mailbox.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpmsg client driver using mailbox client interface + * + * Copyright (C) 2019 ARM Ltd. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rpmsg_internal.h" +#include + +#define RPMSG_NAME "arm_rpmsg" +#define RPMSG_ADDR_ANY 0xFFFFFFFF + +struct arm_channel { + struct rpmsg_endpoint ept; + struct mbox_client cl; + struct mbox_chan *mbox; +}; + +#define arm_channel_from_rpmsg(_ept) container_of(_ept, struct arm_channel, ept) +#define arm_channel_from_mbox(_ept) container_of(_ept, struct arm_channel, cl) + + +static void arm_msg_rx_handler(struct mbox_client *cl, void *mssg) +{ + struct arm_mhuv2_mbox_msg *msg = mssg; + struct arm_channel* channel = arm_channel_from_mbox(cl); + int err = channel->ept.cb(channel->ept.rpdev, msg->data, 4, channel->ept.priv, RPMSG_ADDR_ANY); + if(err) { + printk("ARM Mailbox: Endpoint callback failed with error: %d", err); + } +} + + +static void arm_destroy_ept(struct rpmsg_endpoint *ept) +{ + struct arm_channel *channel = arm_channel_from_rpmsg(ept); + mbox_free_channel(channel->mbox); + kfree(channel); +} + +static int arm_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct arm_channel *channel = arm_channel_from_rpmsg(ept); + + mbox_send_message(channel->mbox, data); + return 0; +} + +static int arm_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dest) +{ + struct arm_mhuv2_mbox_msg msg; + struct arm_channel *channel = arm_channel_from_rpmsg(ept); + msg.data = data; + msg.len = len; + mbox_send_message(channel->mbox, &msg); + return 0; +} + + +static const struct rpmsg_endpoint_ops arm_endpoint_ops = { + .destroy_ept = arm_destroy_ept, + .send = arm_send, + .sendto = arm_sendto, +}; + + +static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev, + rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo) +{ + struct arm_channel *channel; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + + // Initialize rpmsg endpoint + kref_init(&channel->ept.refcount); + channel->ept.rpdev = rpdev; + channel->ept.cb = cb; + channel->ept.priv = priv; + channel->ept.ops = &arm_endpoint_ops; + + // Initialize mailbox client + channel->cl.dev = rpdev->dev.parent; + channel->cl.rx_callback = arm_msg_rx_handler; + channel->cl.tx_done = NULL; /* operate in blocking mode */ + channel->cl.tx_block = true; + channel->cl.tx_tout = 500; /* by half a second */ + channel->cl.knows_txdone = false; /* depending upon protocol */ + + channel->mbox = mbox_request_channel_byname(&channel->cl, chinfo.name); + if (IS_ERR_OR_NULL(channel->mbox)) { + printk("RPMsg ARM: Cannot get channel by name: '%s'\n", chinfo.name); + return -1; + } + + return &channel->ept; +} + +static const struct rpmsg_device_ops arm_device_ops = { + .create_ept = arm_create_ept, +}; + + +static void arm_release_device(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + + kfree(rpdev); +} + + +static int client_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpmsg_device *rpdev; + + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + /* Assign callbacks for rpmsg_device */ + rpdev->ops = &arm_device_ops; + + /* Assign public information to the rpmsg_device */ + memcpy(rpdev->id.name, RPMSG_NAME, strlen(RPMSG_NAME)); + + rpdev->dev.parent = dev; + rpdev->dev.release = arm_release_device; + + return rpmsg_chrdev_register_device(rpdev); +} + +static const struct of_device_id client_of_match[] = { + { .compatible = "arm,client", .data = NULL }, + { /* Sentinel */ }, +}; + +static struct platform_driver client_driver = { + .driver = { + .name = "arm-mhu-client", + .of_match_table = client_of_match, + }, + .probe = client_probe, +}; + +module_platform_driver(client_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ARM RPMSG Driver"); +MODULE_AUTHOR("Tushar Khandelwal ");