* [PATCH v4 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
2025-10-29 19:56 [PATCH v4 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
@ 2025-10-29 19:56 ` Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 2/5] remoteproc: imx_rproc: Populate devices under "rpmsg" subnode Shenwei Wang
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 19:56 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx, Shenwei Wang
Remote processors may announce multiple devices (e.g., I2C, GPIO) over
an RPMSG channel. These devices may require corresponding device tree
nodes, especially when acting as providers, to supply phandles for their
consumers.
Define an RPMSG node to work as a container for a group of RPMSG channels
under the imx_rproc node.
Each subnode within "rpmsg" represents an individual RPMSG channel. The
name of each subnode corresponds to the channel name as defined by the
remote processor.
All remote devices associated with a given channel are defined as child
nodes under the corresponding channel node.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
.../bindings/remoteproc/fsl,imx-rproc.yaml | 123 ++++++++++++++++++
1 file changed, 123 insertions(+)
diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index 57d75acb0b5e..897a16c4f7db 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -84,6 +84,92 @@ properties:
This property is to specify the resource id of the remote processor in SoC
which supports SCFW
+ rpmsg:
+ type: object
+ additionalProperties: false
+ description:
+ Present a group of RPMSG channel devices.
+
+ properties:
+ rpmsg-io-channel:
+ type: object
+ additionalProperties: false
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "gpio@[0-9a-f]+$":
+ type: object
+ unevaluatedProperties: false
+ properties:
+ compatible:
+ enum:
+ - fsl,imx-rpmsg-gpio
+
+ reg:
+ maxItems: 1
+
+ "#gpio-cells":
+ const: 2
+
+ gpio-controller: true
+
+ interrupt-controller: true
+
+ "#interrupt-cells":
+ const: 2
+
+ required:
+ - compatible
+ - reg
+ - "#gpio-cells"
+ - "#interrupt-cells"
+
+ allOf:
+ - $ref: /schemas/gpio/gpio.yaml#
+ - $ref: /schemas/interrupt-controller.yaml#
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
+ rpmsg-i2c-channel:
+ type: object
+ unevaluatedProperties: false
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "i2c@[0-9a-f]+$":
+ type: object
+ unevaluatedProperties: false
+ properties:
+ compatible:
+ enum:
+ - fsl,imx-rpmsg-i2c
+
+ reg:
+ maxItems: 1
+
+ required:
+ - compatible
+ - reg
+
+ allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
required:
- compatible
@@ -146,5 +232,42 @@ examples:
&mu 3 1>;
memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
syscon = <&src>;
+
+ rpmsg {
+ rpmsg-io-channel {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio@0 {
+ compatible = "fsl,imx-rpmsg-gpio";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&rpmsg_gpioa>;
+ };
+
+ gpio@1 {
+ compatible = "fsl,imx-rpmsg-gpio";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&rpmsg_gpiob>;
+ };
+ };
+
+ rpmsg-i2c-channel {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ compatible = "fsl,imx-rpmsg-i2c";
+ reg = <0>;
+ };
+ };
+ };
};
...
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v4 2/5] remoteproc: imx_rproc: Populate devices under "rpmsg" subnode
2025-10-29 19:56 [PATCH v4 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support Shenwei Wang
@ 2025-10-29 19:56 ` Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus Shenwei Wang
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 19:56 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx, Shenwei Wang
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@nxp.com>
---
drivers/remoteproc/imx_rproc.c | 146 ++++++++++++++++++++++++++++++++
include/linux/rpmsg/imx_rpmsg.h | 48 +++++++++++
2 files changed, 194 insertions(+)
create mode 100644 include/linux/rpmsg/imx_rpmsg.h
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index a6eef0080ca9..e21a7980c490 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/rpmsg/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,144 @@ 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_is_in_map(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(channel_device_map); i++) {
+ if (strcmp(name, channel_device_map[i][0]) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static int imx_of_rpmsg_register_rpdriver(struct device_node *channel,
+ struct device *dev, int idx)
+{
+ struct imx_rpmsg_driver_data *driver_data;
+ struct imx_rpmsg_driver *rp_driver;
+ struct rpmsg_device_id *rpdev_id;
+
+ rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id) * 2, GFP_KERNEL);
+ if (!rpdev_id)
+ return -ENOMEM;
+
+ strscpy(rpdev_id[0].name, channel_device_map[idx][0], RPMSG_NAME_SIZE);
+
+ rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
+ if (!rp_driver)
+ return -ENOMEM;
+
+ driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
+ if (!driver_data)
+ return -ENOMEM;
+
+ driver_data->rproc_name = dev->of_node->name;
+ driver_data->channel_node = channel;
+ driver_data->map_idx = idx;
+
+ rp_driver->rpdrv.drv.name = channel_device_map[idx][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);
+
+ return 0;
+}
+
+static int imx_of_rpmsg_node_init(struct platform_device *pdev)
+{
+ struct device_node *np __free(device_node);
+ struct device *dev = &pdev->dev;
+ int idx, ret;
+
+ np = of_get_child_by_name(dev->of_node, "rpmsg");
+ if (!np)
+ return 0;
+
+ for_each_child_of_node_scoped(np, child) {
+ idx = imx_of_rpmsg_is_in_map(child->name);
+ if (idx < 0)
+ ret = of_platform_default_populate(child, NULL, dev);
+ else
+ ret = imx_of_rpmsg_register_rpdriver(child, dev, idx);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1177,6 +1319,10 @@ static int imx_rproc_probe(struct platform_device *pdev)
goto err_put_clk;
}
+ ret = imx_of_rpmsg_node_init(pdev);
+ if (ret < 0)
+ dev_info(dev, "populating 'rpmsg' node failed\n");
+
return 0;
err_put_clk:
diff --git a/include/linux/rpmsg/imx_rpmsg.h b/include/linux/rpmsg/imx_rpmsg.h
new file mode 100644
index 000000000000..04a5ad2d4a1d
--- /dev/null
+++ b/include/linux/rpmsg/imx_rpmsg.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2025 NXP */
+
+/*
+ * @file linux/imx_rpmsg.h
+ *
+ * @brief Global header file for iMX RPMSG
+ *
+ * @ingroup RPMSG
+ */
+#ifndef __LINUX_IMX_RPMSG_H__
+#define __LINUX_IMX_RPMSG_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; /* Category */
+ u8 major; /* Major version */
+ u8 minor; /* Minor version */
+ u8 type; /* Message type */
+ u8 cmd; /* Command code */
+ 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 *rpdev, void *data,
+ int len, void *priv, u32 src);
+ void *channel_devices[MAX_DEV_PER_CHANNEL];
+};
+
+#endif /* __LINUX_IMX_RPMSG_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus
2025-10-29 19:56 [PATCH v4 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 2/5] remoteproc: imx_rproc: Populate devices under "rpmsg" subnode Shenwei Wang
@ 2025-10-29 19:56 ` Shenwei Wang
2025-10-29 20:46 ` Randy Dunlap
2025-10-29 19:56 ` [PATCH v4 4/5] gpio: imx-rpmsg: add imx-rpmsg GPIO driver Shenwei Wang
2025-10-29 19:56 ` [PATCH v4 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc Shenwei Wang
4 siblings, 1 reply; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 19:56 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx, Shenwei Wang
Describes the gpio rpmsg transport protocol over the rpmsg bus between
the cores.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
Documentation/admin-guide/gpio/gpio-rpmsg.rst | 202 ++++++++++++++++++
Documentation/admin-guide/gpio/index.rst | 1 +
2 files changed, 203 insertions(+)
create mode 100644 Documentation/admin-guide/gpio/gpio-rpmsg.rst
diff --git a/Documentation/admin-guide/gpio/gpio-rpmsg.rst b/Documentation/admin-guide/gpio/gpio-rpmsg.rst
new file mode 100644
index 000000000000..ad6207a3093f
--- /dev/null
+++ b/Documentation/admin-guide/gpio/gpio-rpmsg.rst
@@ -0,0 +1,202 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+GPIO RPMSG Protocol
+===================
+
+The GPIO RPMSG transport protocol is used for communication and interaction
+with GPIO controllers located on remote cores on the RPMSG bus.
+
+Message Format
+--------------
+
+The RPMSG message consists of a 14-byte packet with the following layout:
+
+.. code-block:: none
+
+ +-----+------+------+-----+-----+------------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ |cate |major |minor |type |cmd |reserved[5] |line |port | data |
+ +-----+------+------+-----+-----+------------+-----+-----+-----+----+
+
+- **Cate (Category field)**: Indicates the category of the message, such as GPIO, I2C, PMIC, AUDIO, etc.
+
+ Defined categories:
+
+ - 1: RPMSG_LIFECYCLE
+ - 2: RPMSG_PMIC
+ - 3: RPMSG_AUDIO
+ - 4: RPMSG_KEY
+ - 5: RPMSG_GPIO
+ - 6: RPMSG_RTC
+ - 7: RPMSG_SENSOR
+ - 8: RPMSG_AUTO
+ - 9: RPMSG_CATEGORY
+ - A: RPMSG_PWM
+ - B: RPMSG_UART
+
+- **Major**: Major version number.
+
+- **Minor**: Minor version number.
+
+- **Type (Message Type)**: For the GPIO category, can be one of:
+
+ - 0: GPIO_RPMSG_SETUP
+ - 1: GPIO_RPMSG_REPLY
+ - 2: GPIO_RPMSG_NOTIFY
+
+- **Cmd**: Command code, used for GPIO_RPMSG_SETUP messages.
+
+- **reserved[5]**: Reserved bytes.
+
+- **line**: The GPIO line index.
+
+- **port**: The GPIO controller index.
+
+GPIO Commands
+-------------
+
+Commands are specified in the **Cmd** field for **GPIO_RPMSG_SETUP** (Type=0) messages.
+
+GPIO_RPMSG_INPUT_INIT (Cmd=0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 0 | 0 | 0 |line |port | val | wk |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **val**: Interrupt trigger type.
+
+ - 0: Interrupt disabled
+ - 1: Rising edge trigger
+ - 2: Falling edge trigger
+ - 3: Both edge trigger
+ - 4: Low level trigger
+ - 5: High level trigger
+
+- **wk**: Wakeup enable.
+
+ - 0: Disable wakeup from GPIO
+ - 1: Enable wakeup from GPIO
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 1 | 1 | 0 |line |port | err | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **err**: Error code from the remote core.
+
+ - 0: Success
+ - 1: General error (early remote software only returns this unclassified error)
+ - 2: Not supported
+ - 3: Resource not available
+ - 4: Resource busy
+ - 5: Parameter error
+
+GPIO_RPMSG_OUTPUT_INIT (Cmd=1)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 0 | 1 | 0 |line |port | val | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **val**: Output level.
+
+ - 0: Low
+ - 1: High
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 1 | 1 | 0 |line |port | err | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+GPIO_RPMSG_INPUT_GET (Cmd=2)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 0 | 2 | 0 |line |port | 0 | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
+ | 5 | 1 | 0 | 1 | 2 | 0 |line |port | err |level|
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+
+- **err**: See above for definitions.
+
+- **level**: Input level.
+
+ - 0: Low
+ - 1: High
+
+GPIO_RPMSG_GET_DIRECTION (Cmd=3)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 0 | 3 | 0 |line |port | 0 | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
+ | 5 | 1 | 0 | 1 | 3 | 0 |line |port | err | dir |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+
+- **err**: See above for definitions.
+
+- **dir**: Direction.
+
+ - 0: Output
+ - 1: Input
+
+Notification Message
+--------------------
+
+Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+ | 5 | 1 | 0 | 2 | 0 | 0 |line |port | 0 | 0 |
+ +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **line**: The GPIO line index.
+- **port**: The GPIO controller index.
+
diff --git a/Documentation/admin-guide/gpio/index.rst b/Documentation/admin-guide/gpio/index.rst
index 712f379731cb..9c8f4441038a 100644
--- a/Documentation/admin-guide/gpio/index.rst
+++ b/Documentation/admin-guide/gpio/index.rst
@@ -9,6 +9,7 @@ GPIO
Character Device Userspace API <../../userspace-api/gpio/chardev>
gpio-aggregator
+ gpio-rpmsg
gpio-sim
gpio-virtuser
Obsolete APIs <obsolete>
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus
2025-10-29 19:56 ` [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus Shenwei Wang
@ 2025-10-29 20:46 ` Randy Dunlap
2025-10-29 20:52 ` Shenwei Wang
0 siblings, 1 reply; 10+ messages in thread
From: Randy Dunlap @ 2025-10-29 20:46 UTC (permalink / raw)
To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx
Hi--
On 10/29/25 12:56 PM, Shenwei Wang wrote:
> Describes the gpio rpmsg transport protocol over the rpmsg bus between
> the cores.
>
> Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
> ---
> Documentation/admin-guide/gpio/gpio-rpmsg.rst | 202 ++++++++++++++++++
> Documentation/admin-guide/gpio/index.rst | 1 +
> 2 files changed, 203 insertions(+)
> create mode 100644 Documentation/admin-guide/gpio/gpio-rpmsg.rst
>
I don't think this should be in admin-guide/gpio/.
How about in driver-api/gpio/?
That may not be perfect either, but transport protocols are not
typically admin material AFAIK.
> diff --git a/Documentation/admin-guide/gpio/index.rst b/Documentation/admin-guide/gpio/index.rst
> index 712f379731cb..9c8f4441038a 100644
> --- a/Documentation/admin-guide/gpio/index.rst
> +++ b/Documentation/admin-guide/gpio/index.rst
> @@ -9,6 +9,7 @@ GPIO
>
> Character Device Userspace API <../../userspace-api/gpio/chardev>
> gpio-aggregator
> + gpio-rpmsg
> gpio-sim
> gpio-virtuser
> Obsolete APIs <obsolete>
If someone thinks that it should be in admin-guide/,please explain why.
Thanks.
--
~Randy
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus
2025-10-29 20:46 ` Randy Dunlap
@ 2025-10-29 20:52 ` Shenwei Wang
2025-10-29 21:02 ` Randy Dunlap
0 siblings, 1 reply; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 20:52 UTC (permalink / raw)
To: Randy Dunlap, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-remoteproc@vger.kernel.org,
devicetree@vger.kernel.org, imx@lists.linux.dev, dl-linux-imx
> -----Original Message-----
> From: Randy Dunlap <rdunlap@infradead.org>
> Sent: Wednesday, October 29, 2025 3:47 PM
> To: Shenwei Wang <shenwei.wang@nxp.com>; Linus Walleij
> <linus.walleij@linaro.org>; Bartosz Golaszewski <brgl@bgdev.pl>; Jonathan
> Corbet <corbet@lwn.net>; Bjorn Andersson <andersson@kernel.org>; Mathieu
> Poirier <mathieu.poirier@linaro.org>; Rob Herring <robh@kernel.org>; Krzysztof
> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Shawn
> Guo <shawnguo@kernel.org>; Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Pengutronix Kernel Team <kernel@pengutronix.de>; Fabio Estevam
> <festevam@gmail.com>; Peng Fan <peng.fan@nxp.com>; linux-
> gpio@vger.kernel.org; linux-doc@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-remoteproc@vger.kernel.org; devicetree@vger.kernel.org;
> imx@lists.linux.dev; dl-linux-imx <linux-imx@nxp.com>
> Subject: [EXT] Re: [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over
> rpmsg bus
>
> Hi--
>
> On 10/29/25 12:56 PM, Shenwei Wang wrote:
> > Describes the gpio rpmsg transport protocol over the rpmsg bus between
> > the cores.
> >
> > Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
> > ---
> > Documentation/admin-guide/gpio/gpio-rpmsg.rst | 202 ++++++++++++++++++
> > Documentation/admin-guide/gpio/index.rst | 1 +
> > 2 files changed, 203 insertions(+)
> > create mode 100644 Documentation/admin-guide/gpio/gpio-rpmsg.rst
> >
>
> I don't think this should be in admin-guide/gpio/.
> How about in driver-api/gpio/?
> That may not be perfect either, but transport protocols are not typically admin
> material AFAIK.
>
How about putting it in Documentation/staging directory?
I saw both remoteproc.rst and rpmsg.rst are in the directory.
Thanks,
Shenwei
> > diff --git a/Documentation/admin-guide/gpio/index.rst
> > b/Documentation/admin-guide/gpio/index.rst
> > index 712f379731cb..9c8f4441038a 100644
> > --- a/Documentation/admin-guide/gpio/index.rst
> > +++ b/Documentation/admin-guide/gpio/index.rst
> > @@ -9,6 +9,7 @@ GPIO
> >
> > Character Device Userspace API <../../userspace-api/gpio/chardev>
> > gpio-aggregator
> > + gpio-rpmsg
> > gpio-sim
> > gpio-virtuser
> > Obsolete APIs <obsolete>
> If someone thinks that it should be in admin-guide/,please explain why.
>
> Thanks.
> --
> ~Randy
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus
2025-10-29 20:52 ` Shenwei Wang
@ 2025-10-29 21:02 ` Randy Dunlap
0 siblings, 0 replies; 10+ messages in thread
From: Randy Dunlap @ 2025-10-29 21:02 UTC (permalink / raw)
To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-remoteproc@vger.kernel.org,
devicetree@vger.kernel.org, imx@lists.linux.dev, dl-linux-imx
On 10/29/25 1:52 PM, Shenwei Wang wrote:
>
>
>> -----Original Message-----
>> From: Randy Dunlap <rdunlap@infradead.org>
>> Sent: Wednesday, October 29, 2025 3:47 PM
>> To: Shenwei Wang <shenwei.wang@nxp.com>; Linus Walleij
>> <linus.walleij@linaro.org>; Bartosz Golaszewski <brgl@bgdev.pl>; Jonathan
>> Corbet <corbet@lwn.net>; Bjorn Andersson <andersson@kernel.org>; Mathieu
>> Poirier <mathieu.poirier@linaro.org>; Rob Herring <robh@kernel.org>; Krzysztof
>> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Shawn
>> Guo <shawnguo@kernel.org>; Sascha Hauer <s.hauer@pengutronix.de>
>> Cc: Pengutronix Kernel Team <kernel@pengutronix.de>; Fabio Estevam
>> <festevam@gmail.com>; Peng Fan <peng.fan@nxp.com>; linux-
>> gpio@vger.kernel.org; linux-doc@vger.kernel.org; linux-kernel@vger.kernel.org;
>> linux-remoteproc@vger.kernel.org; devicetree@vger.kernel.org;
>> imx@lists.linux.dev; dl-linux-imx <linux-imx@nxp.com>
>> Subject: [EXT] Re: [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over
>> rpmsg bus
>>
>> Hi--
>>
>> On 10/29/25 12:56 PM, Shenwei Wang wrote:
>>> Describes the gpio rpmsg transport protocol over the rpmsg bus between
>>> the cores.
>>>
>>> Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
>>> ---
>>> Documentation/admin-guide/gpio/gpio-rpmsg.rst | 202 ++++++++++++++++++
>>> Documentation/admin-guide/gpio/index.rst | 1 +
>>> 2 files changed, 203 insertions(+)
>>> create mode 100644 Documentation/admin-guide/gpio/gpio-rpmsg.rst
>>>
>>
>> I don't think this should be in admin-guide/gpio/.
>> How about in driver-api/gpio/?
>> That may not be perfect either, but transport protocols are not typically admin
>> material AFAIK.
>>
>
> How about putting it in Documentation/staging directory?
> I saw both remoteproc.rst and rpmsg.rst are in the directory.
>
Yeah, maybe. That's sort of a last resort location for things
that don't have a better place.
>
>>> diff --git a/Documentation/admin-guide/gpio/index.rst
>>> b/Documentation/admin-guide/gpio/index.rst
>>> index 712f379731cb..9c8f4441038a 100644
>>> --- a/Documentation/admin-guide/gpio/index.rst
>>> +++ b/Documentation/admin-guide/gpio/index.rst
>>> @@ -9,6 +9,7 @@ GPIO
>>>
>>> Character Device Userspace API <../../userspace-api/gpio/chardev>
>>> gpio-aggregator
>>> + gpio-rpmsg
>>> gpio-sim
>>> gpio-virtuser
>>> Obsolete APIs <obsolete>
>> If someone thinks that it should be in admin-guide/,please explain why.
>>
>> Thanks.
>> --
>> ~Randy
--
~Randy
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 4/5] gpio: imx-rpmsg: add imx-rpmsg GPIO driver
2025-10-29 19:56 [PATCH v4 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
` (2 preceding siblings ...)
2025-10-29 19:56 ` [PATCH v4 3/5] docs: admin-guide: gpio: rpmsg: gpio over rpmsg bus Shenwei Wang
@ 2025-10-29 19:56 ` Shenwei Wang
2025-10-30 15:44 ` Bartosz Golaszewski
2025-10-29 19:56 ` [PATCH v4 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc Shenwei Wang
4 siblings, 1 reply; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 19:56 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx, Shenwei Wang
On i.MX SoCs, the system may include two processors:
- An MCU running an RTOS
- An MPU running Linux
These processors communicate via the RPMSG protocol.
The driver implements the standard GPIO interface, allowing
the Linux side to control GPIO controllers which reside in
the remote processor via RPMSG protocol.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
drivers/gpio/Kconfig | 17 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-imx-rpmsg.c | 467 ++++++++++++++++++++++++++++++++++
3 files changed, 485 insertions(+)
create mode 100644 drivers/gpio/gpio-imx-rpmsg.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a437fe652dbc..97eda94b0ba1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1847,6 +1847,23 @@ config GPIO_SODAVILLE
endmenu
+menu "RPMSG GPIO drivers"
+ depends on RPMSG
+
+config GPIO_IMX_RPMSG
+ tristate "NXP i.MX SoC RPMSG GPIO support"
+ depends on IMX_REMOTEPROC
+ select GPIOLIB_IRQCHIP
+ default IMX_REMOTEPROC
+ help
+ Say yes here to support the RPMSG GPIO functions on i.MX SoC based
+ platform. Currently supported devices: i.MX7ULP, i.MX8ULP, i.MX8x,
+ and i.MX9x.
+
+ If unsure, say N.
+
+endmenu
+
menu "SPI GPIO expanders"
depends on SPI_MASTER
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 379f55e9ed1e..e01465c03431 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IDIO_16) += gpio-idio-16.o
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
+obj-$(CONFIG_GPIO_IMX_RPMSG) += gpio-imx-rpmsg.o
obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
diff --git a/drivers/gpio/gpio-imx-rpmsg.c b/drivers/gpio/gpio-imx-rpmsg.c
new file mode 100644
index 000000000000..5787ec3a1249
--- /dev/null
+++ b/drivers/gpio/gpio-imx-rpmsg.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 NXP
+ *
+ * The driver exports a standard gpiochip interface to control
+ * the GPIO controllers via RPMSG on a remote processor.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/rpmsg/imx_rpmsg.h>
+
+#define IMX_RPMSG_GPIO_PER_PORT 32
+#define RPMSG_TIMEOUT 1000
+
+enum gpio_input_trigger_type {
+ GPIO_RPMSG_TRI_IGNORE,
+ GPIO_RPMSG_TRI_RISING,
+ GPIO_RPMSG_TRI_FALLING,
+ GPIO_RPMSG_TRI_BOTH_EDGE,
+ GPIO_RPMSG_TRI_LOW_LEVEL,
+ GPIO_RPMSG_TRI_HIGH_LEVEL,
+};
+
+enum gpio_rpmsg_header_type {
+ GPIO_RPMSG_SETUP,
+ GPIO_RPMSG_REPLY,
+ GPIO_RPMSG_NOTIFY,
+};
+
+enum gpio_rpmsg_header_cmd {
+ GPIO_RPMSG_INPUT_INIT,
+ GPIO_RPMSG_OUTPUT_INIT,
+ GPIO_RPMSG_INPUT_GET,
+ GPIO_RPMSG_DIRECTION_GET,
+};
+
+struct gpio_rpmsg_data {
+ struct imx_rpmsg_head header;
+ u8 pin_idx;
+ u8 port_idx;
+ union {
+ u8 event;
+ u8 retcode;
+ u8 value;
+ } out;
+ union {
+ u8 wakeup;
+ u8 value;
+ } in;
+} __packed __aligned(8);
+
+struct imx_rpmsg_gpio_pin {
+ u8 irq_shutdown;
+ u8 irq_unmask;
+ u8 irq_mask;
+ u32 irq_wake_enable;
+ u32 irq_type;
+ struct gpio_rpmsg_data msg;
+};
+
+struct imx_gpio_rpmsg_info {
+ struct rpmsg_device *rpdev;
+ struct gpio_rpmsg_data *notify_msg;
+ struct gpio_rpmsg_data *reply_msg;
+ struct completion cmd_complete;
+ struct mutex lock;
+ void **port_store;
+};
+
+struct imx_rpmsg_gpio_port {
+ struct gpio_chip gc;
+ struct imx_rpmsg_gpio_pin gpio_pins[IMX_RPMSG_GPIO_PER_PORT];
+ struct imx_gpio_rpmsg_info info;
+ int idx;
+};
+
+static int gpio_send_message(struct imx_rpmsg_gpio_port *port,
+ struct gpio_rpmsg_data *msg,
+ bool sync)
+{
+ struct imx_gpio_rpmsg_info *info = &port->info;
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(&info->rpdev->dev,
+ "rpmsg channel doesn't exist, is remote core ready?\n");
+ return -EINVAL;
+ }
+
+ reinit_completion(&info->cmd_complete);
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct gpio_rpmsg_data));
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ return err;
+ }
+
+ if (sync) {
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->reply_msg->out.retcode != 0) {
+ dev_err(&info->rpdev->dev, "remote core replies an error: %d!\n",
+ info->reply_msg->out.retcode);
+ return -EINVAL;
+ }
+
+ /* copy the reply message */
+ memcpy(&port->gpio_pins[info->reply_msg->pin_idx].msg,
+ info->reply_msg, sizeof(*info->reply_msg));
+ }
+
+ return 0;
+}
+
+static struct gpio_rpmsg_data *gpio_setup_msg_header(struct imx_rpmsg_gpio_port *port,
+ unsigned int offset,
+ u8 cmd)
+{
+ struct gpio_rpmsg_data *msg = &port->gpio_pins[offset].msg;
+
+ memset(msg, 0, sizeof(struct gpio_rpmsg_data));
+ msg->header.cate = IMX_RPMSG_GPIO;
+ msg->header.major = IMX_RMPSG_MAJOR;
+ msg->header.minor = IMX_RMPSG_MINOR;
+ msg->header.type = GPIO_RPMSG_SETUP;
+ msg->header.cmd = cmd;
+ msg->pin_idx = offset;
+ msg->port_idx = port->idx;
+
+ return msg;
+};
+
+static int imx_rpmsg_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data *msg = NULL;
+ int ret;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_GET);
+
+ ret = gpio_send_message(port, msg, true);
+ if (!ret)
+ ret = !!port->gpio_pins[gpio].msg.in.value;
+
+ return ret;
+}
+
+static int imx_rpmsg_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data *msg = NULL;
+ int ret;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_DIRECTION_GET);
+
+ ret = gpio_send_message(port, msg, true);
+ if (!ret)
+ ret = !!port->gpio_pins[gpio].msg.in.value;
+
+ return ret;
+}
+
+static int imx_rpmsg_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data *msg = NULL;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_INIT);
+
+ return gpio_send_message(port, msg, true);
+}
+
+static int imx_rpmsg_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data *msg = NULL;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_OUTPUT_INIT);
+ msg->out.value = val;
+
+ return gpio_send_message(port, msg, true);
+}
+
+static int imx_rpmsg_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int gpio, int val)
+{
+
+ return imx_rpmsg_gpio_set(gc, gpio, val);
+}
+
+static int imx_rpmsg_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+ int edge = 0;
+ int ret = 0;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ edge = GPIO_RPMSG_TRI_RISING;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ edge = GPIO_RPMSG_TRI_FALLING;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ edge = GPIO_RPMSG_TRI_BOTH_EDGE;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ edge = GPIO_RPMSG_TRI_LOW_LEVEL;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ edge = GPIO_RPMSG_TRI_HIGH_LEVEL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ port->gpio_pins[gpio_idx].irq_type = edge;
+
+ return ret;
+}
+
+static int imx_rpmsg_irq_set_wake(struct irq_data *d, u32 enable)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+
+ port->gpio_pins[gpio_idx].irq_wake_enable = enable;
+
+ return 0;
+}
+
+/*
+ * This function will be called at:
+ * - one interrupt setup.
+ * - the end of one interrupt happened
+ * The gpio over rpmsg driver will not write the real register, so save
+ * all infos before this function and then send all infos to M core in this
+ * step.
+ */
+static void imx_rpmsg_unmask_irq(struct irq_data *d)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+
+ port->gpio_pins[gpio_idx].irq_unmask = 1;
+}
+
+static void imx_rpmsg_mask_irq(struct irq_data *d)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+ /*
+ * No need to implement the callback at A core side.
+ * M core will mask interrupt after a interrupt occurred, and then
+ * sends a notify to A core.
+ * After A core dealt with the notify, A core will send a rpmsg to
+ * M core to unmask this interrupt again.
+ */
+ port->gpio_pins[gpio_idx].irq_mask = 1;
+}
+
+static void imx_rpmsg_irq_shutdown(struct irq_data *d)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+
+ port->gpio_pins[gpio_idx].irq_shutdown = 1;
+}
+
+static void imx_rpmsg_irq_bus_lock(struct irq_data *d)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+
+ mutex_lock(&port->info.lock);
+}
+
+static void imx_rpmsg_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ struct gpio_rpmsg_data *msg = NULL;
+ u32 gpio_idx = d->hwirq;
+
+ if (port == NULL) {
+ mutex_unlock(&port->info.lock);
+ return;
+ }
+
+ /*
+ * For mask irq, do nothing here.
+ * M core will mask interrupt after a interrupt occurred, and then
+ * sends a notify to A core.
+ * After A core dealt with the notify, A core will send a rpmsg to
+ * M core to unmask this interrupt again.
+ */
+
+ if (port->gpio_pins[gpio_idx].irq_mask && !port->gpio_pins[gpio_idx].irq_unmask) {
+ port->gpio_pins[gpio_idx].irq_mask = 0;
+ mutex_unlock(&port->info.lock);
+ return;
+ }
+
+ msg = gpio_setup_msg_header(port, gpio_idx, GPIO_RPMSG_INPUT_INIT);
+
+ if (port->gpio_pins[gpio_idx].irq_shutdown) {
+ msg->out.event = GPIO_RPMSG_TRI_IGNORE;
+ msg->in.wakeup = 0;
+ port->gpio_pins[gpio_idx].irq_shutdown = 0;
+ } else {
+ /* if not set irq type, then use low level as trigger type */
+ msg->out.event = port->gpio_pins[gpio_idx].irq_type;
+ if (!msg->out.event)
+ msg->out.event = GPIO_RPMSG_TRI_LOW_LEVEL;
+ if (port->gpio_pins[gpio_idx].irq_unmask) {
+ msg->in.wakeup = 0;
+ port->gpio_pins[gpio_idx].irq_unmask = 0;
+ } else /* irq set wake */
+ msg->in.wakeup = port->gpio_pins[gpio_idx].irq_wake_enable;
+ }
+
+ gpio_send_message(port, msg, false);
+ mutex_unlock(&port->info.lock);
+}
+
+static const struct irq_chip imx_rpmsg_irq_chip = {
+ .irq_mask = imx_rpmsg_mask_irq,
+ .irq_unmask = imx_rpmsg_unmask_irq,
+ .irq_set_wake = imx_rpmsg_irq_set_wake,
+ .irq_set_type = imx_rpmsg_irq_set_type,
+ .irq_shutdown = imx_rpmsg_irq_shutdown,
+ .irq_bus_lock = imx_rpmsg_irq_bus_lock,
+ .irq_bus_sync_unlock = imx_rpmsg_irq_bus_sync_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+};
+
+static int imx_rpmsg_gpio_callback(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct gpio_rpmsg_data *msg = (struct gpio_rpmsg_data *)data;
+ struct imx_rpmsg_gpio_port *port = NULL;
+ struct imx_rpmsg_driver_data *drvdata;
+
+ drvdata = dev_get_drvdata(&rpdev->dev);
+ if (msg)
+ port = drvdata->channel_devices[msg->port_idx];
+
+ if (!port)
+ return -ENODEV;
+
+ if (msg->header.type == GPIO_RPMSG_REPLY) {
+ port->info.reply_msg = msg;
+ complete(&port->info.cmd_complete);
+ } else if (msg->header.type == GPIO_RPMSG_NOTIFY) {
+ port->info.notify_msg = msg;
+ generic_handle_domain_irq_safe(port->gc.irq.domain, msg->pin_idx);
+ } else
+ dev_err(&rpdev->dev, "wrong command type!\n");
+
+ return 0;
+}
+
+static void imx_rpmsg_gpio_remove_action(void *data)
+{
+ struct imx_rpmsg_gpio_port *port = data;
+
+ port->info.port_store[port->idx] = NULL;
+}
+
+static int imx_rpmsg_gpio_probe(struct platform_device *pdev)
+{
+ struct imx_rpmsg_driver_data *pltdata = pdev->dev.platform_data;
+ struct imx_rpmsg_gpio_port *port;
+ struct gpio_irq_chip *girq;
+ struct gpio_chip *gc;
+ int ret;
+
+ if (!pltdata)
+ return -EPROBE_DEFER;
+
+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ ret = device_property_read_u32(&pdev->dev, "reg", &port->idx);
+ if (ret)
+ return ret;
+
+ if (port->idx > MAX_DEV_PER_CHANNEL)
+ return -EINVAL;
+
+ mutex_init(&port->info.lock);
+ init_completion(&port->info.cmd_complete);
+ port->info.rpdev = pltdata->rpdev;
+ port->info.port_store = pltdata->channel_devices;
+ port->info.port_store[port->idx] = port;
+ if (!pltdata->rx_callback)
+ pltdata->rx_callback = imx_rpmsg_gpio_callback;
+
+ gc = &port->gc;
+ gc->owner = THIS_MODULE;
+ gc->parent = &pdev->dev;
+ gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
+ pltdata->rproc_name, port->idx);
+ gc->ngpio = IMX_RPMSG_GPIO_PER_PORT;
+ gc->base = -1;
+
+ gc->direction_input = imx_rpmsg_gpio_direction_input;
+ gc->direction_output = imx_rpmsg_gpio_direction_output;
+ gc->get_direction = imx_rpmsg_gpio_get_direction;
+ gc->get = imx_rpmsg_gpio_get;
+ gc->set = imx_rpmsg_gpio_set;
+
+ platform_set_drvdata(pdev, port);
+ girq = &gc->irq;
+ gpio_irq_chip_set_chip(girq, &imx_rpmsg_irq_chip);
+ girq->parent_handler = NULL;
+ girq->num_parents = 0;
+ girq->parents = NULL;
+ girq->chip->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
+ pltdata->rproc_name, port->idx);
+
+ ret = devm_add_action_or_reset(&pdev->dev, imx_rpmsg_gpio_remove_action, port);
+ if (ret)
+ return ret;
+
+ return devm_gpiochip_add_data(&pdev->dev, gc, port);
+}
+
+static const struct of_device_id imx_rpmsg_gpio_dt_ids[] = {
+ { .compatible = "fsl,imx-rpmsg-gpio" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver imx_rpmsg_gpio_driver = {
+ .driver = {
+ .name = "gpio-imx-rpmsg",
+ .of_match_table = imx_rpmsg_gpio_dt_ids,
+ },
+ .probe = imx_rpmsg_gpio_probe,
+};
+
+module_platform_driver(imx_rpmsg_gpio_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NXP i.MX SoC rpmsg gpio driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 4/5] gpio: imx-rpmsg: add imx-rpmsg GPIO driver
2025-10-29 19:56 ` [PATCH v4 4/5] gpio: imx-rpmsg: add imx-rpmsg GPIO driver Shenwei Wang
@ 2025-10-30 15:44 ` Bartosz Golaszewski
0 siblings, 0 replies; 10+ messages in thread
From: Bartosz Golaszewski @ 2025-10-30 15:44 UTC (permalink / raw)
To: Shenwei Wang
Cc: Linus Walleij, Jonathan Corbet, Bjorn Andersson, Mathieu Poirier,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
linux-gpio, linux-doc, linux-kernel, linux-remoteproc, devicetree,
imx, linux-imx
On Wed, Oct 29, 2025 at 8:57 PM Shenwei Wang <shenwei.wang@nxp.com> wrote:
>
> On i.MX SoCs, the system may include two processors:
> - An MCU running an RTOS
> - An MPU running Linux
>
> These processors communicate via the RPMSG protocol.
> The driver implements the standard GPIO interface, allowing
> the Linux side to control GPIO controllers which reside in
> the remote processor via RPMSG protocol.
>
Looks good, just a couple nits.
> +
> +#include <linux/err.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/init.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/rpmsg.h>
> +#include <linux/rpmsg/imx_rpmsg.h>
Also at least: mutex.h, completion.h, device.h (for devm_kzalloc() and
co.), module.h, mod_devicetable.h.
> +
> +static int imx_rpmsg_gpio_probe(struct platform_device *pdev)
> +{
> + struct imx_rpmsg_driver_data *pltdata = pdev->dev.platform_data;
> + struct imx_rpmsg_gpio_port *port;
> + struct gpio_irq_chip *girq;
> + struct gpio_chip *gc;
> + int ret;
> +
> + if (!pltdata)
> + return -EPROBE_DEFER;
> +
> + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
> + if (!port)
> + return -ENOMEM;
> +
> + ret = device_property_read_u32(&pdev->dev, "reg", &port->idx);
> + if (ret)
> + return ret;
> +
> + if (port->idx > MAX_DEV_PER_CHANNEL)
> + return -EINVAL;
> +
> + mutex_init(&port->info.lock);
devm_mutex_init() to allow mutex debugging
> +
> +static struct platform_driver imx_rpmsg_gpio_driver = {
> + .driver = {
> + .name = "gpio-imx-rpmsg",
> + .of_match_table = imx_rpmsg_gpio_dt_ids,
> + },
> + .probe = imx_rpmsg_gpio_probe,
> +};
> +
> +module_platform_driver(imx_rpmsg_gpio_driver);
> +
> +MODULE_AUTHOR("NXP Semiconductor");
You can state copyright for a company in the header comment, please
put your name and email address in here.
> +MODULE_DESCRIPTION("NXP i.MX SoC rpmsg gpio driver");
> +MODULE_LICENSE("GPL");
> --
> 2.43.0
>
With the above fixed:
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc
2025-10-29 19:56 [PATCH v4 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
` (3 preceding siblings ...)
2025-10-29 19:56 ` [PATCH v4 4/5] gpio: imx-rpmsg: add imx-rpmsg GPIO driver Shenwei Wang
@ 2025-10-29 19:56 ` Shenwei Wang
4 siblings, 0 replies; 10+ messages in thread
From: Shenwei Wang @ 2025-10-29 19:56 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer
Cc: Pengutronix Kernel Team, Fabio Estevam, Peng Fan, linux-gpio,
linux-doc, linux-kernel, linux-remoteproc, devicetree, imx,
linux-imx, Shenwei Wang
Add the RPMSG bus node along with its GPIO subnodes to the device
tree.
Enable remote device communication and GPIO control via RPMSG on
the i.MX platform.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 27 ++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..6ab1c12a3bc1 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -191,6 +191,33 @@ scmi_sensor: protocol@15 {
cm33: remoteproc-cm33 {
compatible = "fsl,imx8ulp-cm33";
status = "disabled";
+
+ rpmsg {
+ rpmsg-io-channel {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rpmsg_gpioa: gpio@0 {
+ compatible = "fsl,imx-rpmsg-gpio";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&rpmsg_gpioa>;
+ };
+
+ rpmsg_gpiob: gpio@1 {
+ compatible = "fsl,imx-rpmsg-gpio";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&rpmsg_gpiob>;
+ };
+ };
+ };
};
soc: soc@0 {
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread