linux-imx/drivers/rpmsg/imx_rpmsg_pingpong.c
Richard Zhu 1cd9e0aaf0 rpmsg: imx: add the initial imx rpmsg support
Based on "virtio_rpmsg_bus" driver, This patch-set is used to set up
the communication mechanism between A core and M core on i.MX AMP SOCs.

Add the initial imx rpmsg support glue driver and one pingpong demo,
demonstrated the data transactions between A core and remote M core.
Distributed framework is used in IMX RPMSG implementation, refer to the
following requirements:
  - The CAN functions contained in M core and RTOS should be ready and
    complete functional in 50ms after AMP system is turned on.
  - Partition reset. System wouldn't be stalled by the exceptions (e.x
    the reset triggered by the system hang) occurred at the other side.
    And the RPMSG mechanism should be recovered automactilly after the
    partition reset is completed.
In this scenario, the M core and RTOS would be kicked off by bootloader
firstly, then A core and Linux would be loaded later. Both M core/RTOS
and A core/Linux are running independly.

One physical memory region used to store the vring is mandatory required
to pre-reserved and well-knowned by both A core and M core

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
2023-10-30 16:10:26 +08:00

101 lines
2.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/rpmsg.h>
#define MSG "hello world!"
static int rpmsg_pingpong_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
int err;
unsigned int rpmsg_pingpong;
/* reply */
rpmsg_pingpong = *(unsigned int *)data;
pr_info("get %d (src: 0x%x)\n", rpmsg_pingpong, src);
/* pingpongs should not live forever */
if (rpmsg_pingpong > 100) {
dev_info(&rpdev->dev, "goodbye!\n");
return 0;
}
rpmsg_pingpong++;
err = rpmsg_sendto(rpdev->ept, (void *)(&rpmsg_pingpong), 4, src);
if (err)
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
return err;
}
static int rpmsg_pingpong_probe(struct rpmsg_device *rpdev)
{
int err;
unsigned int rpmsg_pingpong;
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
rpdev->src, rpdev->dst);
/*
* send a message to our remote processor, and tell remote
* processor about this channel
*/
err = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
if (err) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
return err;
}
rpmsg_pingpong = 0;
err = rpmsg_sendto(rpdev->ept, (void *)(&rpmsg_pingpong),
4, rpdev->dst);
if (err) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
return err;
}
return 0;
}
static void rpmsg_pingpong_remove(struct rpmsg_device *rpdev)
{
dev_info(&rpdev->dev, "rpmsg pingpong driver is removed\n");
}
static struct rpmsg_device_id rpmsg_driver_pingpong_id_table[] = {
{ .name = "rpmsg-openamp-demo-channel" },
{ .name = "rpmsg-openamp-demo-channel-1" },
{ },
};
static struct rpmsg_driver rpmsg_pingpong_driver = {
.drv.name = KBUILD_MODNAME,
.drv.owner = THIS_MODULE,
.id_table = rpmsg_driver_pingpong_id_table,
.probe = rpmsg_pingpong_probe,
.callback = rpmsg_pingpong_cb,
.remove = rpmsg_pingpong_remove,
};
static int __init init(void)
{
return register_rpmsg_driver(&rpmsg_pingpong_driver);
}
static void __exit fini(void)
{
unregister_rpmsg_driver(&rpmsg_pingpong_driver);
}
module_init(init);
module_exit(fini);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("iMX virtio remote processor messaging pingpong driver");
MODULE_LICENSE("GPL v2");