[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250818204420.794554-3-shenwei.wang@nxp.com>
Date: Mon, 18 Aug 2025 15:44:18 -0500
From: Shenwei Wang <shenwei.wang@....com>
To: Bjorn Andersson <andersson@...nel.org>,
Mathieu Poirier <mathieu.poirier@...aro.org>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Shawn Guo <shawnguo@...nel.org>,
Sascha Hauer <s.hauer@...gutronix.de>,
Linus Walleij <linus.walleij@...aro.org>,
Bartosz Golaszewski <brgl@...ev.pl>
Cc: Pengutronix Kernel Team <kernel@...gutronix.de>,
Fabio Estevam <festevam@...il.com>,
Shenwei Wang <shenwei.wang@....com>,
Peng Fan <peng.fan@....com>,
linux-remoteproc@...r.kernel.org,
devicetree@...r.kernel.org,
imx@...ts.linux.dev,
linux-arm-kernel@...ts.infradead.org,
linux-kernel@...r.kernel.org,
linux-imx@....com
Subject: [PATCH 2/4] remoteproc: imx_rproc: Populate devices under "rpmsg" subnode
Register the RPMsg channel driver and populate remote devices defined
under the "rpmsg" subnode upon receiving their notification messages.
The following illustrates the expected DTS layout structure:
cm33: remoteproc-cm33 {
compatible = "fsl,imx8ulp-cm33";
rpmsg {
rpmsg-io-channel {
gpio@0 {
compatible = "fsl,imx-rpmsg-gpio";
reg = <0>;
};
gpio@1 {
compatible = "fsl,imx-rpmsg-gpio";
reg = <1>;
};
...
};
rpmsg-i2c-channel {
i2c@0 {
compatible = "fsl,imx-rpmsg-i2c";
reg = <0>;
};
};
...
};
};
Signed-off-by: Shenwei Wang <shenwei.wang@....com>
---
drivers/remoteproc/imx_rproc.c | 125 +++++++++++++++++++++++++++++++++
include/linux/imx_rpmsg.h | 55 +++++++++++++++
2 files changed, 180 insertions(+)
create mode 100644 include/linux/imx_rpmsg.h
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index a6eef0080ca9..9b3396f3f1ec 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/firmware/imx/sci.h>
+#include <linux/imx_rpmsg.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
@@ -15,6 +16,8 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
@@ -22,6 +25,7 @@
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
+#include <linux/rpmsg.h>
#include <linux/workqueue.h>
#include "imx_rproc.h"
@@ -1084,6 +1088,126 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
return NOTIFY_DONE;
}
+struct imx_rpmsg_driver {
+ struct rpmsg_driver rpdrv;
+ void *driver_data;
+};
+
+static char *channel_device_map[][2] = {
+ {"rpmsg-io-channel", "fsl,imx-rpmsg-gpio"},
+ {"rpmsg-i2c-channel", "fsl,imx-rpmsg-i2c"},
+};
+
+static int imx_rpmsg_endpoint_cb(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct imx_rpmsg_driver_data *drvdata;
+
+ drvdata = dev_get_drvdata(&rpdev->dev);
+ if (drvdata && drvdata->rx_callback)
+ return drvdata->rx_callback(rpdev, data, len, priv, src);
+
+ return 0;
+}
+
+static void imx_rpmsg_endpoint_remove(struct rpmsg_device *rpdev)
+{
+ of_platform_depopulate(&rpdev->dev);
+}
+
+static int imx_rpmsg_endpoint_probe(struct rpmsg_device *rpdev)
+{
+ struct imx_rpmsg_driver_data *drvdata;
+ struct imx_rpmsg_driver *imx_rpdrv;
+ struct device *dev = &rpdev->dev;
+ struct of_dev_auxdata *auxdata;
+ struct rpmsg_driver *rpdrv;
+ int i;
+
+ rpdrv = container_of(dev->driver, struct rpmsg_driver, drv);
+ imx_rpdrv = container_of(rpdrv, struct imx_rpmsg_driver, rpdrv);
+
+ if (!imx_rpdrv->driver_data)
+ return -EINVAL;
+
+ drvdata = devm_kmemdup(dev, imx_rpdrv->driver_data, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ i = drvdata->map_idx;
+ if (i >= ARRAY_SIZE(channel_device_map))
+ return -ENODEV;
+
+ auxdata = devm_kzalloc(dev, sizeof(*auxdata)*2, GFP_KERNEL);
+ if (!auxdata)
+ return -ENOMEM;
+
+ drvdata->rpdev = rpdev;
+ auxdata[0].compatible = channel_device_map[i][1];
+ auxdata[0].platform_data = drvdata;
+ dev_set_drvdata(dev, drvdata);
+
+ of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);
+ of_node_put(drvdata->channel_node);
+
+ return 0;
+}
+
+static int imx_of_rpmsg_node_init(struct platform_device *pdev)
+{
+ struct device_node *np __free(device_node), *channel;
+ struct imx_rpmsg_driver_data *driver_data;
+ struct imx_rpmsg_driver *rp_driver;
+ struct rpmsg_device_id *rpdev_id;
+ int i, ret;
+
+ int count = ARRAY_SIZE(channel_device_map);
+ struct device *dev = &pdev->dev;
+
+ np = of_get_child_by_name(dev->of_node, "rpmsg");
+ if (!np)
+ return 0;
+
+ for (i = 0; i < count; i++) {
+ ret = -ENOMEM;
+ channel = of_get_child_by_name(np, channel_device_map[i][0]);
+ if (!channel)
+ continue;
+
+ rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id)*2, GFP_KERNEL);
+ if (!rpdev_id)
+ break;
+ strscpy(rpdev_id[0].name, channel_device_map[i][0], RPMSG_NAME_SIZE);
+
+ rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
+ if (!rp_driver)
+ break;
+
+ driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
+ if (!driver_data)
+ break;
+
+ ret = 0;
+ driver_data->rproc_name = dev->of_node->name;
+ driver_data->channel_node = channel;
+ driver_data->map_idx = i;
+
+ rp_driver->rpdrv.drv.name = channel_device_map[i][0];
+ rp_driver->rpdrv.id_table = rpdev_id;
+ rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
+ rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
+ rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
+ rp_driver->driver_data = driver_data;
+
+ register_rpmsg_driver(&rp_driver->rpdrv);
+ }
+
+ if ((ret < 0) && channel)
+ of_node_put(channel);
+
+ return ret;
+}
+
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1177,6 +1301,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
goto err_put_clk;
}
+ imx_of_rpmsg_node_init(pdev);
return 0;
err_put_clk:
diff --git a/include/linux/imx_rpmsg.h b/include/linux/imx_rpmsg.h
new file mode 100644
index 000000000000..300ada6237be
--- /dev/null
+++ b/include/linux/imx_rpmsg.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * @file linux/imx_rpmsg.h
+ *
+ * @brief Global header file for iMX RPMSG
+ *
+ * @ingroup RPMSG
+ */
+#ifndef __LINUX_IMX_RPMSG_H__
+#define __LINUX_IMX_RPMSG_H__
+
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* Category define */
+#define IMX_RMPSG_LIFECYCLE 1
+#define IMX_RPMSG_PMIC 2
+#define IMX_RPMSG_AUDIO 3
+#define IMX_RPMSG_KEY 4
+#define IMX_RPMSG_GPIO 5
+#define IMX_RPMSG_RTC 6
+#define IMX_RPMSG_SENSOR 7
+/* rpmsg version */
+#define IMX_RMPSG_MAJOR 1
+#define IMX_RMPSG_MINOR 0
+
+#define MAX_DEV_PER_CHANNEL 10
+
+struct imx_rpmsg_head {
+ u8 cate;
+ u8 major;
+ u8 minor;
+ u8 type;
+ u8 cmd;
+ u8 reserved[5];
+} __packed;
+
+struct imx_rpmsg_driver_data {
+ int map_idx;
+ const char *rproc_name;
+ struct rpmsg_device *rpdev;
+ struct device_node *channel_node;
+ int (*rx_callback)(struct rpmsg_device *, void *, int, void *, u32);
+ void *channel_devices[MAX_DEV_PER_CHANNEL];
+};
+
+#endif /* __LINUX_IMX_RPMSG_H__ */
--
2.43.0
Powered by blists - more mailing lists