* [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform
@ 2026-03-04 21:18 Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
` (4 more replies)
0 siblings, 5 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
Support the remote devices on the remote processor via the RPMSG bus on
i.MX platform.
Changes in v9:
- Reuse the gpio-virtio design for command and IRQ type definitions.
- Remove msg_id, version, and vendor fields from the generic protocol.
- Add fixed-up handlers to support legacy firmware.
Changes in v8:
- Add "depends on REMOTEPROC" in Kconfig to fix the build error reported
by the kernel test robot.
- Move the .rst patch before the .yaml patch.
- Handle the "ngpios" DT property based on Andrew's feedback.
Changes in v7:
- Reworked the driver to use the rpmsg_driver framework instead of
platform_driver, based on feedback from Bjorn and Arnaud.
- Updated gpio-rpmsg.yaml and imx_rproc.yaml according to comments from
Rob and Arnaud.
- Further refinements to gpio-rpmsg.yaml per Arnaud's feedback.
Changes in v6:
- make the driver more generic with the actions below:
rename the driver file to gpio-rpmsg.c
remove the imx related info in the function and variable names
rename the imx_rpmsg.h to rpdev_info.h
create a gpio-rpmsg.yaml and refer it in imx_rproc.yaml
- update the gpio-rpmsg.rst according to the feedback from Andrew and
move the source file to driver-api/gpio
- fix the bug reported by Zhongqiu Han
- remove the I2C related info
Changes in v5:
- move the gpio-rpmsg.rst from admin-guide to staging directory after
discussion with Randy Dunlap.
- add include files with some code improvements per Bartosz's comments.
Changes in v4:
- add a documentation to describe the transport protocol per Andrew's
comments.
- add a new handler to get the gpio direction.
Changes in v3:
- fix various format issue and return value check per Peng 's review
comments.
- add the logic to also populate the subnodes which are not in the
device map per Arnaud's request. (in imx_rproc.c)
- update the yaml per Frank's review comments.
Changes in v2:
- re-implemented the gpio driver per Linus Walleij's feedback by using
GPIOLIB_IRQCHIP helper library.
- fix various format issue per Mathieu/Peng 's review comments.
- update the yaml doc per Rob's feedback
Shenwei Wang (5):
docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus
dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
gpio: rpmsg: add generic rpmsg GPIO driver
gpio: rpmsg: add support for NXP legacy firmware protocol
arm64: dts: imx8ulp: Add rpmsg node under imx_rproc
.../devicetree/bindings/gpio/gpio-rpmsg.yaml | 55 ++
.../bindings/remoteproc/fsl,imx-rproc.yaml | 53 ++
Documentation/driver-api/gpio/gpio-rpmsg.rst | 258 ++++++
Documentation/driver-api/gpio/index.rst | 1 +
arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 25 +
drivers/gpio/Kconfig | 17 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-rpmsg.c | 735 ++++++++++++++++++
8 files changed, 1145 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
create mode 100644 Documentation/driver-api/gpio/gpio-rpmsg.rst
create mode 100644 drivers/gpio/gpio-rpmsg.c
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
@ 2026-03-04 21:18 ` Shenwei Wang
2026-03-05 7:11 ` kernel test robot
2026-03-05 15:39 ` Daniel Baluta
2026-03-04 21:18 ` [PATCH v9 2/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support Shenwei Wang
` (3 subsequent siblings)
4 siblings, 2 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
Describes the gpio rpmsg transport protocol over the rpmsg bus between
the remote system and Linux.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
Documentation/driver-api/gpio/gpio-rpmsg.rst | 258 +++++++++++++++++++
Documentation/driver-api/gpio/index.rst | 1 +
2 files changed, 259 insertions(+)
create mode 100644 Documentation/driver-api/gpio/gpio-rpmsg.rst
diff --git a/Documentation/driver-api/gpio/gpio-rpmsg.rst b/Documentation/driver-api/gpio/gpio-rpmsg.rst
new file mode 100644
index 000000000000..43ea5c5279f0
--- /dev/null
+++ b/Documentation/driver-api/gpio/gpio-rpmsg.rst
@@ -0,0 +1,258 @@
+.. 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 6-byte packet with the following layout:
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ |type |cmd |port |line | data |
+ +-----+-----+-----+-----+-----+----+
+
+- **Type (Message Type)**: The message type can be one of:
+
+ - 0: GPIO_RPMSG_SEND
+ - 1: GPIO_RPMSG_REPLY
+ - 2: GPIO_RPMSG_NOTIFY
+
+- **Cmd**: Command code, used for GPIO_RPMSG_SEND messages.
+
+- **line**: The GPIO line(pin) index of the port.
+
+- **port**: The GPIO port(bank) index.
+
+- **data**: See details in the command description below.
+
+- **reply err**: Error code from the remote core.
+
+ - 0: Success
+ - 1: General error (Early remote software only returns this unclassified error)
+ - 2: Not supported (A command is not supported by the remote firmware)
+ - 3: Resource not available (The resource is not allocated to Linux)
+ - 4: Resource busy (The resource is already in use)
+ - 5: Parameter error
+
+
+GPIO Commands
+-------------
+
+Commands are specified in the **Cmd** field for **GPIO_RPMSG_SEND** (Type=0) messages.
+
+The SEND message is always sent from Linux to the remote firmware. Each
+SEND corresponds to a single REPLY message. The GPIO driver should
+serialize messages and determine whether a REPLY message is required. If a
+REPLY message is expected but not received within the specified timeout
+period (currently 1 second in the Linux driver), the driver should return
+-ETIMEOUT.
+
+GET_DIRECTION (Cmd=2)
+~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 2 |port |line | 0 | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 1 | 2 |port |line | err | dir|
+ +-----+-----+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+- **dir**: Direction.
+
+ - 0: Output
+ - 1: Input
+
+SET_DIRECTION (Cmd=3)
+~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 3 |port |line | dir | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **dir**: Direction.
+
+ - 0: None
+ - 1: Output
+ - 2: Input
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 1 | 3 |port |line | err | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+
+GET_VALUE (Cmd=4)
+~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 4 |port |line | 0 | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 1 | 4 |port |line | err | val|
+ +-----+-----+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+- **val**: Direction.
+
+ - 0: High
+ - 1: Low
+
+SET_VALUE (Cmd=5)
+~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 5 |port |line | val | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **val**: Output Level.
+
+ - 0: High
+ - 1: Low
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 1 | 5 |port |line | err | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+SET_IRQ_TYPE (Cmd=6)
+~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 6 |port |line | val | wk |
+ +-----+-----+-----+-----+-----+----+
+
+- **val**: IRQ Types.
+
+ - 0: Interrupt disabled
+ - 1: Rising edge trigger
+ - 2: Falling edge trigger
+ - 3: Both edge trigger
+ - 4: High level trigger
+ - 8: Low level trigger
+
+- **wk**: Wakeup enable.
+
+ The remote system should always aim to stay in a power-efficient state by
+ shutting down or clock-gating the GPIO blocks that aren't in use. Since
+ the remoteproc driver is responsible for managing the power states of the
+ remote firmware, the GPIO driver does not require to know the firmware's
+ running states.
+
+ When the wakeup bit is set, the remote firmware should configure the line
+ as a wakeup source. The firmware should send the notification message to
+ Linux after it is woken from the GPIO line.
+
+ - 0: Disable wakeup from GPIO
+ - 1: Enable wakeup from GPIO
+
+**Reply:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 1 | 6 |port |line | err | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+NOTIFY_REPLY (Cmd=10)
+~~~~~~~~~~~~~~~~~~~~
+The reply message for the notification is optional. The remote firmware can
+implement it to simulate the interrupt acknowledgment behavior.
+
+**Request:**
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 0 | 10 |port |line |level| 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **line**: The GPIO line(pin) index of the port.
+- **port**: The GPIO port(bank) index.
+- **level**: GPIO line status.
+
+Notification Message
+--------------------
+
+Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
+
+When a GPIO line asserts an interrupt on the remote processor, the firmware
+should immediately mask the corresponding interrupt source and send a
+notification message to the Linux. Upon completion of the interrupt
+handling on the Linux side, the driver should issue a
+command **SET_IRQ_TYPE** to the firmware to unmask the interrupt.
+
+A Notification message can arrive between a SEND and its REPLY message,
+and the driver is expected to handle this scenario.
+
+.. code-block:: none
+
+ +-----+-----+-----+-----+-----+----+
+ |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
+ | 2 | 0 |port |line |type | 0 |
+ +-----+-----+-----+-----+-----+----+
+
+- **line**: The GPIO line(pin) index of the port.
+- **port**: The GPIO port(bank) index.
+- **type**: Optional parameter to indicate the trigger event type.
+
diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst
index bee58f709b9a..e5eb1f82f01f 100644
--- a/Documentation/driver-api/gpio/index.rst
+++ b/Documentation/driver-api/gpio/index.rst
@@ -16,6 +16,7 @@ Contents:
drivers-on-gpio
bt8xxgpio
pca953x
+ gpio-rpmsg
Core
====
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v9 2/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
@ 2026-03-04 21:18 ` Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 3/5] gpio: rpmsg: add generic rpmsg GPIO driver Shenwei Wang
` (2 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
Remote processors may announce multiple GPIO controllers over an RPMSG
channel. These GPIO controllers 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>
---
.../devicetree/bindings/gpio/gpio-rpmsg.yaml | 55 +++++++++++++++++++
.../bindings/remoteproc/fsl,imx-rproc.yaml | 53 ++++++++++++++++++
2 files changed, 108 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
diff --git a/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
new file mode 100644
index 000000000000..6c78b6850321
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/gpio-rpmsg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic RPMSG GPIO Controller
+
+maintainers:
+ - Shenwei Wang <shenwei.wang@nxp.com>
+
+description:
+ On an AMP platform, some GPIO controllers are exposed by the remote processor
+ through the RPMSG bus. The RPMSG GPIO transport protocol defines the packet
+ structure and communication flow between Linux and the remote firmware. Those
+ controllers are managed via this transport protocol. For more details of the
+ protocol, check the document below.
+ Documentation/driver-api/gpio/gpio-rpmsg.rst
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,rpmsg-gpio
+ - const: rpmsg-gpio
+ - const: rpmsg-gpio
+
+ reg:
+ description:
+ The reg property represents the index of the GPIO controllers. Since
+ the driver manages controllers on a remote system, this index tells
+ the remote system which controller to operate.
+ 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#
+
+unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index ce8ec0119469..88281ffc18ca 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -85,6 +85,34 @@ properties:
This property is to specify the resource id of the remote processor in SoC
which supports SCFW
+ rpmsg:
+ type: object
+ additionalProperties: false
+ description:
+ Represents the RPMSG bus between Linux and the remote system. Contains
+ a group of RPMSG channel devices running on the bus.
+
+ properties:
+ rpmsg-io-channel:
+ type: object
+ additionalProperties: false
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "gpio@[0-9a-f]+$":
+ type: object
+ $ref: /schemas/gpio/gpio-rpmsg.yaml#
+ unevaluatedProperties: false
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
required:
- compatible
@@ -147,5 +175,30 @@ 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 = "rpmsg-gpio";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
+
+ gpio@1 {
+ compatible = "rpmsg-gpio";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
+ };
+ };
};
...
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v9 3/5] gpio: rpmsg: add generic rpmsg GPIO driver
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 2/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support Shenwei Wang
@ 2026-03-04 21:18 ` Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc Shenwei Wang
4 siblings, 0 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx,
Bartosz Golaszewski, Andrew Lunn
On an AMP platform, 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.
Cc: Bartosz Golaszewski <brgl@bgdev.pl>
Cc: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
drivers/gpio/Kconfig | 17 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-rpmsg.c | 592 ++++++++++++++++++++++++++++++++++++++
3 files changed, 610 insertions(+)
create mode 100644 drivers/gpio/gpio-rpmsg.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b45fb799e36c..cff0fda8a283 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1892,6 +1892,23 @@ config GPIO_SODAVILLE
endmenu
+menu "RPMSG GPIO drivers"
+ depends on RPMSG
+
+config GPIO_RPMSG
+ tristate "Generic RPMSG GPIO support"
+ depends on OF && REMOTEPROC
+ select GPIOLIB_IRQCHIP
+ default REMOTEPROC
+ help
+ Say yes here to support the generic GPIO functions over the RPMSG
+ bus. 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 c05f7d795c43..501aba56ad68 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -158,6 +158,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_REALTEK_OTTO) += gpio-realtek-otto.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o
+obj-$(CONFIG_GPIO_RPMSG) += gpio-rpmsg.o
obj-$(CONFIG_GPIO_RTD) += gpio-rtd.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
diff --git a/drivers/gpio/gpio-rpmsg.c b/drivers/gpio/gpio-rpmsg.c
new file mode 100644
index 000000000000..1accf56a0f79
--- /dev/null
+++ b/drivers/gpio/gpio-rpmsg.c
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2026 NXP
+ *
+ * The driver exports a standard gpiochip interface to control
+ * the GPIO controllers via RPMSG on a remote processor.
+ */
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irqdomain.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/rpmsg.h>
+#include <linux/virtio_gpio.h>
+
+#define MAX_PORT_PER_CHANNEL 10
+#define GPIOS_PER_PORT_DEFAULT 32
+#define RPMSG_TIMEOUT 1000
+
+/* GPIO RPMSG Type */
+#define GPIO_RPMSG_SEND 0
+#define GPIO_RPMSG_REPLY 1
+#define GPIO_RPMSG_NOTIFY 2
+
+struct rpmsg_gpio_packet {
+ u8 type; /* Message type */
+ u8 cmd; /* Command code */
+ u8 port_idx;
+ u8 line;
+ u8 val1;
+ u8 val2;
+};
+
+struct rpmsg_gpio_line {
+ u8 irq_shutdown;
+ u8 irq_unmask;
+ u8 irq_mask;
+ u32 irq_wake_enable;
+ u32 irq_type;
+ struct rpmsg_gpio_packet msg;
+};
+
+struct rpmsg_gpio_info {
+ struct rpmsg_device *rpdev;
+ struct rpmsg_gpio_packet *reply_msg;
+ struct completion cmd_complete;
+ struct mutex lock;
+ void **port_store;
+};
+
+struct rpmsg_gpio_port {
+ struct gpio_chip gc;
+ struct rpmsg_gpio_line lines[GPIOS_PER_PORT_DEFAULT];
+ struct rpmsg_gpio_info info;
+ u32 ngpios;
+ u32 idx;
+};
+
+struct rpmsg_gpio_fixed_up {
+ int (*send_fixed_up)(struct rpmsg_gpio_info *info, struct rpmsg_gpio_packet *msg);
+ struct rpmsg_gpio_packet *(*recv_fixed_up)(struct rpmsg_device *rpdev, void *data);
+};
+
+/*
+ * @rproc_name: the name of the remote proc.
+ * @recv_pkt: a pointer to the received packet for protocol fix up.
+ * @protocol_fixed_up: optional callbacks to handle protocol mismatches.
+ * @channel_devices: an array of the devices related to the rpdev.
+ */
+struct rpdev_drvdata {
+ const char *rproc_name;
+ void *recv_pkt;
+ struct rpmsg_gpio_fixed_up *protocol_fixed_up;
+ void *channel_devices[MAX_PORT_PER_CHANNEL];
+};
+
+static int rpmsg_gpio_send_message(struct rpmsg_gpio_port *port,
+ struct rpmsg_gpio_packet *msg,
+ bool sync)
+{
+ struct rpmsg_gpio_info *info = &port->info;
+ struct rpdev_drvdata *drvdata;
+ int ret;
+
+ drvdata = dev_get_drvdata(&info->rpdev->dev);
+ reinit_completion(&info->cmd_complete);
+
+ if (drvdata->protocol_fixed_up)
+ ret = drvdata->protocol_fixed_up->send_fixed_up(info, msg);
+ else
+ ret = rpmsg_send(info->rpdev->ept, msg, sizeof(*msg));
+
+ if (ret) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ return ret;
+ }
+
+ if (sync) {
+ ret = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (ret == 0) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->reply_msg->val1 != 0) {
+ dev_err(&info->rpdev->dev, "remote core replies an error: %d!\n",
+ info->reply_msg->val1);
+ return -EINVAL;
+ }
+
+ /* copy the reply message */
+ memcpy(&port->lines[info->reply_msg->line].msg,
+ info->reply_msg, sizeof(*info->reply_msg));
+ }
+
+ return 0;
+}
+
+static struct rpmsg_gpio_packet *
+rpmsg_gpio_msg_init_common(struct rpmsg_gpio_port *port, unsigned int line, u8 cmd)
+{
+ struct rpmsg_gpio_packet *msg = &port->lines[line].msg;
+
+ memset(msg, 0, sizeof(struct rpmsg_gpio_packet));
+ msg->type = GPIO_RPMSG_SEND;
+ msg->cmd = cmd;
+ msg->port_idx = port->idx;
+ msg->line = line;
+
+ return msg;
+}
+
+static int rpmsg_gpio_get(struct gpio_chip *gc, unsigned int line)
+{
+ struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct rpmsg_gpio_packet *msg;
+ int ret;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_GET_VALUE);
+
+ ret = rpmsg_gpio_send_message(port, msg, true);
+ if (!ret)
+ ret = !!port->lines[line].msg.val2;
+
+ return ret;
+}
+
+static int rpmsg_gpio_get_direction(struct gpio_chip *gc, unsigned int line)
+{
+ struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct rpmsg_gpio_packet *msg;
+ int ret;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_GET_DIRECTION);
+
+ ret = rpmsg_gpio_send_message(port, msg, true);
+ if (ret)
+ return ret;
+
+ switch (port->lines[line].msg.val2) {
+ case VIRTIO_GPIO_DIRECTION_IN:
+ return GPIO_LINE_DIRECTION_IN;
+ case VIRTIO_GPIO_DIRECTION_OUT:
+ return GPIO_LINE_DIRECTION_OUT;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int rpmsg_gpio_direction_input(struct gpio_chip *gc, unsigned int line)
+{
+ struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct rpmsg_gpio_packet *msg;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_SET_DIRECTION);
+ msg->val1 = VIRTIO_GPIO_DIRECTION_IN;
+
+ return rpmsg_gpio_send_message(port, msg, true);
+}
+
+static int rpmsg_gpio_set(struct gpio_chip *gc, unsigned int line, int val)
+{
+ struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct rpmsg_gpio_packet *msg;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_SET_VALUE);
+ msg->val1 = val;
+
+ return rpmsg_gpio_send_message(port, msg, true);
+}
+
+static int rpmsg_gpio_direction_output(struct gpio_chip *gc, unsigned int line, int val)
+{
+ struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct rpmsg_gpio_packet *msg;
+ int ret;
+
+ guard(mutex)(&port->info.lock);
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_SET_DIRECTION);
+ msg->val1 = VIRTIO_GPIO_DIRECTION_OUT;
+
+ ret = rpmsg_gpio_send_message(port, msg, true);
+ if (ret)
+ return ret;
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_SET_VALUE);
+ msg->val1 = val;
+
+ return rpmsg_gpio_send_message(port, msg, true);
+}
+
+static int gpio_rpmsg_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 line = d->hwirq;
+ int ret = 0;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ type = VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING;
+ irq_set_handler_locked(d, handle_simple_irq);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ type = VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING;
+ irq_set_handler_locked(d, handle_simple_irq);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ type = VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH;
+ irq_set_handler_locked(d, handle_simple_irq);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW;
+ irq_set_handler_locked(d, handle_level_irq);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH;
+ irq_set_handler_locked(d, handle_level_irq);
+ break;
+ default:
+ ret = -EINVAL;
+ irq_set_handler_locked(d, handle_bad_irq);
+ break;
+ }
+
+ port->lines[line].irq_type = type;
+
+ return ret;
+}
+
+static int gpio_rpmsg_irq_set_wake(struct irq_data *d, u32 enable)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 line = d->hwirq;
+
+ port->lines[line].irq_wake_enable = enable;
+
+ return 0;
+}
+
+/*
+ * This unmask/mask function is invoked in two situations:
+ * - when an interrupt is being set up, and
+ * - after an interrupt has occurred.
+ *
+ * The GPIO driver does not access hardware registers directly.
+ * Instead, it caches all relevant information locally, and then sends
+ * the accumulated state to the remote system at this stage.
+ */
+static void gpio_rpmsg_unmask_irq(struct irq_data *d)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 line = d->hwirq;
+
+ port->lines[line].irq_unmask = 1;
+}
+
+static void gpio_rpmsg_mask_irq(struct irq_data *d)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 line = d->hwirq;
+
+ /*
+ * When an interrupt occurs, the remote system masks the interrupt
+ * and then sends a notification to Linux. After Linux processes
+ * that notification, it sends an RPMsg command back to the remote
+ * system to unmask the interrupt again.
+ */
+ port->lines[line].irq_mask = 1;
+}
+
+static void gpio_rpmsg_irq_shutdown(struct irq_data *d)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 line = d->hwirq;
+
+ port->lines[line].irq_shutdown = 1;
+}
+
+static void gpio_rpmsg_irq_bus_lock(struct irq_data *d)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+
+ mutex_lock(&port->info.lock);
+}
+
+static void gpio_rpmsg_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ struct rpmsg_gpio_packet *msg = NULL;
+ u32 line = d->hwirq;
+
+ /*
+ * For mask irq, do nothing here.
+ * The remote system will mask interrupt after an interrupt occurs,
+ * and then send a notify to Linux system.
+ * After Linux system dealt with the notify, it will send an rpmsg to
+ * the remote system to unmask this interrupt again.
+ */
+ if (port->lines[line].irq_mask && !port->lines[line].irq_unmask) {
+ port->lines[line].irq_mask = 0;
+ mutex_unlock(&port->info.lock);
+ return;
+ }
+
+ msg = rpmsg_gpio_msg_init_common(port, line, VIRTIO_GPIO_MSG_IRQ_TYPE);
+
+ if (port->lines[line].irq_shutdown) {
+ port->lines[line].irq_shutdown = 0;
+ msg->val1 = VIRTIO_GPIO_IRQ_TYPE_NONE;
+ msg->val2 = 0;
+ } else {
+ /* if not set irq type, then use low level as trigger type */
+ msg->val1 = port->lines[line].irq_type;
+ if (!msg->val1)
+ msg->val1 = VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW;
+ if (port->lines[line].irq_unmask) {
+ msg->val2 = 0;
+ port->lines[line].irq_unmask = 0;
+ } else /* irq set wake */
+ msg->val2 = port->lines[line].irq_wake_enable;
+ }
+
+ rpmsg_gpio_send_message(port, msg, false);
+ mutex_unlock(&port->info.lock);
+}
+
+static const struct irq_chip gpio_rpmsg_irq_chip = {
+ .irq_mask = gpio_rpmsg_mask_irq,
+ .irq_unmask = gpio_rpmsg_unmask_irq,
+ .irq_set_wake = gpio_rpmsg_irq_set_wake,
+ .irq_set_type = gpio_rpmsg_irq_set_type,
+ .irq_shutdown = gpio_rpmsg_irq_shutdown,
+ .irq_bus_lock = gpio_rpmsg_irq_bus_lock,
+ .irq_bus_sync_unlock = gpio_rpmsg_irq_bus_sync_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+};
+
+static void rpmsg_gpio_remove_action(void *data)
+{
+ struct rpmsg_gpio_port *port = data;
+
+ port->info.port_store[port->idx] = NULL;
+}
+
+static int rpmsg_gpiochip_register(struct rpmsg_device *rpdev, struct device_node *np)
+{
+ struct rpdev_drvdata *drvdata = dev_get_drvdata(&rpdev->dev);
+ struct rpmsg_gpio_port *port;
+ struct gpio_irq_chip *girq;
+ struct gpio_chip *gc;
+ int ret;
+
+ port = devm_kzalloc(&rpdev->dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "reg", &port->idx);
+ if (ret)
+ return ret;
+
+ if (port->idx >= MAX_PORT_PER_CHANNEL)
+ return -EINVAL;
+
+ ret = devm_mutex_init(&rpdev->dev, &port->info.lock);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "ngpios", &port->ngpios);
+ if (ret || port->ngpios > GPIOS_PER_PORT_DEFAULT)
+ port->ngpios = GPIOS_PER_PORT_DEFAULT;
+
+ init_completion(&port->info.cmd_complete);
+ port->info.reply_msg = devm_kzalloc(&rpdev->dev,
+ sizeof(struct rpmsg_gpio_packet),
+ GFP_KERNEL);
+ port->info.port_store = drvdata->channel_devices;
+ port->info.port_store[port->idx] = port;
+ port->info.rpdev = rpdev;
+
+ gc = &port->gc;
+ gc->owner = THIS_MODULE;
+ gc->parent = &rpdev->dev;
+ gc->fwnode = of_fwnode_handle(np);
+ gc->ngpio = port->ngpios;
+ gc->base = -1;
+ gc->label = devm_kasprintf(&rpdev->dev, GFP_KERNEL, "%s-gpio%d",
+ drvdata->rproc_name, port->idx);
+
+ gc->direction_input = rpmsg_gpio_direction_input;
+ gc->direction_output = rpmsg_gpio_direction_output;
+ gc->get_direction = rpmsg_gpio_get_direction;
+ gc->get = rpmsg_gpio_get;
+ gc->set = rpmsg_gpio_set;
+
+ girq = &gc->irq;
+ gpio_irq_chip_set_chip(girq, &gpio_rpmsg_irq_chip);
+ girq->parent_handler = NULL;
+ girq->num_parents = 0;
+ girq->parents = NULL;
+ girq->chip->name = devm_kasprintf(&rpdev->dev, GFP_KERNEL, "%s-gpio%d",
+ drvdata->rproc_name, port->idx);
+
+ ret = devm_add_action_or_reset(&rpdev->dev, rpmsg_gpio_remove_action, port);
+ if (ret)
+ return ret;
+
+ return devm_gpiochip_add_data(&rpdev->dev, gc, port);
+}
+
+static const char *rpmsg_get_rproc_node_name(struct rpmsg_device *rpdev)
+{
+ const char *name = NULL;
+ struct device_node *np;
+ struct rproc *rproc;
+
+ rproc = rproc_get_by_child(&rpdev->dev);
+
+ if (!rproc)
+ return NULL;
+
+ np = of_node_get(rproc->dev.of_node);
+ if (!np && rproc->dev.parent)
+ np = of_node_get(rproc->dev.parent->of_node);
+
+ if (np) {
+ name = devm_kstrdup(&rpdev->dev, np->name, GFP_KERNEL);
+ of_node_put(np);
+ }
+
+ return name;
+}
+
+static struct device_node *
+rpmsg_get_channel_ofnode(struct rpmsg_device *rpdev, char *chan_name)
+{
+ struct device_node *np_chan = NULL, *np;
+ struct rproc *rproc;
+
+ rproc = rproc_get_by_child(&rpdev->dev);
+ if (!rproc)
+ return NULL;
+
+ np = of_node_get(rproc->dev.of_node);
+ if (!np && rproc->dev.parent)
+ np = of_node_get(rproc->dev.parent->of_node);
+
+ /* The of_node_put() is performed by of_find_node_by_name(). */
+ if (np)
+ np_chan = of_find_node_by_name(np, chan_name);
+
+ return np_chan;
+}
+
+static int
+rpmsg_gpio_channel_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 src)
+{
+ struct rpmsg_gpio_packet *msg = data;
+ struct rpmsg_gpio_port *port = NULL;
+ struct rpdev_drvdata *drvdata;
+
+ drvdata = dev_get_drvdata(&rpdev->dev);
+ if (!drvdata)
+ return -EINVAL;
+
+ if (drvdata->protocol_fixed_up)
+ msg = drvdata->protocol_fixed_up->recv_fixed_up(rpdev, data);
+
+ if (msg && msg->port_idx < MAX_PORT_PER_CHANNEL)
+ port = drvdata->channel_devices[msg->port_idx];
+
+ if (!port)
+ return -ENODEV;
+
+ if (msg->type == GPIO_RPMSG_REPLY) {
+ *port->info.reply_msg = *msg;
+ complete(&port->info.cmd_complete);
+ } else if (msg->type == GPIO_RPMSG_NOTIFY) {
+ generic_handle_domain_irq_safe(port->gc.irq.domain, msg->line);
+ } else
+ dev_err(&rpdev->dev, "wrong command type (0x%x)\n", msg->type);
+
+ return 0;
+}
+
+static int rpmsg_gpio_channel_probe(struct rpmsg_device *rpdev)
+{
+ struct device *dev = &rpdev->dev;
+ struct rpdev_drvdata *drvdata;
+ struct device_node *np;
+ int ret;
+
+ if (!dev->of_node) {
+ np = rpmsg_get_channel_ofnode(rpdev, rpdev->id.name);
+ if (np) {
+ dev->of_node = np;
+ set_primary_fwnode(dev, of_fwnode_handle(np));
+ }
+ return -EPROBE_DEFER;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->rproc_name = rpmsg_get_rproc_node_name(rpdev);
+ drvdata->protocol_fixed_up =
+ (struct rpmsg_gpio_fixed_up *)(uintptr_t)rpdev->id.driver_data;
+ dev_set_drvdata(dev, drvdata);
+
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+
+ if (!of_match_node(dev->driver->of_match_table, child))
+ continue;
+
+ ret = rpmsg_gpiochip_register(rpdev, child);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id rpmsg_gpio_dt_ids[] = {
+ { .compatible = "rpmsg-gpio" },
+ { /* sentinel */ }
+};
+
+static struct rpmsg_device_id rpmsg_gpio_channel_id_table[] = {
+ { .name = "rpmsg-io" },
+ { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_gpio_channel_id_table);
+
+static struct rpmsg_driver rpmsg_gpio_channel_client = {
+ .drv = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = rpmsg_gpio_dt_ids,
+ },
+ .id_table = rpmsg_gpio_channel_id_table,
+ .probe = rpmsg_gpio_channel_probe,
+ .callback = rpmsg_gpio_channel_callback,
+};
+module_rpmsg_driver(rpmsg_gpio_channel_client);
+
+MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
+MODULE_DESCRIPTION("generic rpmsg gpio driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
` (2 preceding siblings ...)
2026-03-04 21:18 ` [PATCH v9 3/5] gpio: rpmsg: add generic rpmsg GPIO driver Shenwei Wang
@ 2026-03-04 21:18 ` Shenwei Wang
2026-03-05 15:16 ` Frank Li
` (2 more replies)
2026-03-04 21:18 ` [PATCH v9 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc Shenwei Wang
4 siblings, 3 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
Implement fixed-up message handlers to maintain compatibility with
existing i.MX devices that rely on the NXP legacy RPMSG firmware and
its transport protocol. This ensures backward compatibility and preserves
functionality for deployed NXP systems.
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
drivers/gpio/gpio-rpmsg.c | 143 ++++++++++++++++++++++++++++++++++++++
1 file changed, 143 insertions(+)
diff --git a/drivers/gpio/gpio-rpmsg.c b/drivers/gpio/gpio-rpmsg.c
index 1accf56a0f79..fcfca658cb8d 100644
--- a/drivers/gpio/gpio-rpmsg.c
+++ b/drivers/gpio/gpio-rpmsg.c
@@ -84,6 +84,145 @@ struct rpdev_drvdata {
void *channel_devices[MAX_PORT_PER_CHANNEL];
};
+/* NXP I.MX Legacy GPIO RPMSG protocol */
+#define IMX_RPMSG_CONFIG_INPUT 0
+#define IMX_RPMSG_CONFIG_OUTPUT 1
+#define IMX_RPMSG_GET_LEVEL 2
+#define IMX_RPMSG_GET_DIRECTION 3
+#define IMX_RPMSG_CMD_UNKNOWN 0x7F
+
+#define IMX_RPMSG_TRI_LOW_LEVEL 4
+#define IMX_RPMSG_TRI_HIGH_LEVEL 5
+
+#define IMX_RPMSG_ID 5
+#define IMX_RPMSG_VENDOR 1
+#define IMX_RPMSG_VERSION 0
+
+struct rpmsg_gpio_nxp_packet {
+ u8 id; /* Message ID Code */
+ u8 vendor; /* Vendor ID number */
+ u8 version; /* Protocol version number */
+ u8 type; /* Message type */
+ u8 cmd; /* Command code */
+ u8 reserved[5];
+ u8 line;
+ u8 port_idx;
+ u8 val1;
+ u8 val2;
+};
+
+static struct rpmsg_gpio_packet *
+rpmsg_gpio_imx_recv_fixed_up(struct rpmsg_device *rpdev, void *data)
+{
+ struct rpmsg_gpio_nxp_packet *imx_msg = data;
+ struct rpmsg_gpio_packet *msg;
+ struct rpdev_drvdata *drvdata;
+
+ if (!imx_msg)
+ return NULL;
+
+ drvdata = dev_get_drvdata(&rpdev->dev);
+ if (!drvdata->recv_pkt)
+ drvdata->recv_pkt = devm_kzalloc(&rpdev->dev, sizeof(*msg), GFP_KERNEL);
+
+ if (!drvdata->recv_pkt)
+ return NULL;
+
+ msg = drvdata->recv_pkt;
+
+ msg->type = imx_msg->type;
+ msg->cmd = imx_msg->cmd;
+ msg->port_idx = imx_msg->port_idx;
+ msg->line = imx_msg->line;
+ msg->val1 = imx_msg->val1;
+ msg->val2 = imx_msg->val2;
+
+ switch (imx_msg->cmd) {
+ case IMX_RPMSG_GET_LEVEL:
+ msg->cmd = VIRTIO_GPIO_MSG_GET_VALUE;
+ break;
+
+ case IMX_RPMSG_GET_DIRECTION:
+ msg->cmd = VIRTIO_GPIO_MSG_GET_DIRECTION;
+ break;
+
+ case IMX_RPMSG_CONFIG_OUTPUT:
+ msg->cmd = VIRTIO_GPIO_MSG_SET_DIRECTION;
+ msg->val2 = VIRTIO_GPIO_DIRECTION_OUT;
+ break;
+
+ case IMX_RPMSG_CONFIG_INPUT:
+ msg->cmd = VIRTIO_GPIO_MSG_SET_DIRECTION;
+ msg->val2 = VIRTIO_GPIO_DIRECTION_IN;
+ break;
+
+ default:
+ break;
+ }
+
+ return msg;
+}
+
+static int imx_std_cmd_map[] = {
+ IMX_RPMSG_CMD_UNKNOWN,
+ IMX_RPMSG_CMD_UNKNOWN, /* VIRTIO_GPIO_MSG_GET_NAMES */
+ IMX_RPMSG_GET_DIRECTION, /* VIRTIO_GPIO_MSG_GET_DIRECTION */
+ IMX_RPMSG_CONFIG_INPUT, /* VIRTIO_GPIO_MSG_SET_DIRECTION */
+ IMX_RPMSG_GET_LEVEL, /* VIRTIO_GPIO_MSG_GET_VALUE */
+ IMX_RPMSG_CONFIG_OUTPUT, /* VIRTIO_GPIO_MSG_SET_VALUE */
+ IMX_RPMSG_CONFIG_INPUT /* VIRTIO_GPIO_MSG_IRQ_TYPE */
+};
+
+static int rpmsg_gpio_imx_send_fixed_up(struct rpmsg_gpio_info *info,
+ struct rpmsg_gpio_packet *msg)
+{
+ struct rpmsg_gpio_nxp_packet imx_msg;
+
+ if (msg->cmd >= sizeof(imx_std_cmd_map))
+ return -EINVAL;
+
+ imx_msg.id = IMX_RPMSG_ID;
+ imx_msg.vendor = IMX_RPMSG_VENDOR;
+ imx_msg.version = IMX_RPMSG_VERSION;
+ imx_msg.type = msg->type;
+ imx_msg.cmd = imx_std_cmd_map[msg->cmd];
+ imx_msg.port_idx = msg->port_idx;
+ imx_msg.line = msg->line;
+ imx_msg.val1 = msg->val1;
+ imx_msg.val2 = msg->val2;
+
+ switch (msg->cmd) {
+ case VIRTIO_GPIO_MSG_IRQ_TYPE:
+ switch (msg->val1) {
+ case VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH:
+ imx_msg.val1 = IMX_RPMSG_TRI_HIGH_LEVEL;
+ break;
+ case VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW:
+ imx_msg.val1 = IMX_RPMSG_TRI_LOW_LEVEL;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case VIRTIO_GPIO_MSG_SET_DIRECTION:
+ imx_msg.val1 = 0;
+ if (msg->val1 == VIRTIO_GPIO_DIRECTION_OUT)
+ imx_msg.cmd = IMX_RPMSG_CONFIG_OUTPUT;
+ break;
+
+ default:
+ break;
+ }
+
+ return rpmsg_send(info->rpdev->ept, &imx_msg, sizeof(imx_msg));
+}
+
+static struct rpmsg_gpio_fixed_up imx_fixed_up_data = {
+ .recv_fixed_up = rpmsg_gpio_imx_recv_fixed_up,
+ .send_fixed_up = rpmsg_gpio_imx_send_fixed_up,
+};
+
static int rpmsg_gpio_send_message(struct rpmsg_gpio_port *port,
struct rpmsg_gpio_packet *msg,
bool sync)
@@ -572,6 +711,10 @@ static const struct of_device_id rpmsg_gpio_dt_ids[] = {
static struct rpmsg_device_id rpmsg_gpio_channel_id_table[] = {
{ .name = "rpmsg-io" },
+ {
+ .name = "rpmsg-io-channel",
+ .driver_data = (kernel_ulong_t)(uintptr_t)&imx_fixed_up_data
+ },
{ },
};
MODULE_DEVICE_TABLE(rpmsg, rpmsg_gpio_channel_id_table);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v9 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
` (3 preceding siblings ...)
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
@ 2026-03-04 21:18 ` Shenwei Wang
4 siblings, 0 replies; 13+ messages in thread
From: Shenwei Wang @ 2026-03-04 21:18 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
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 | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 9b5d98766512..ad1ef00a1e3d 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -191,6 +191,31 @@ 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 = "rpmsg-gpio";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
+
+ rpmsg_gpiob: gpio@1 {
+ compatible = "rpmsg-gpio";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
+ };
+ };
};
soc: soc@0 {
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
@ 2026-03-05 7:11 ` kernel test robot
2026-03-05 15:39 ` Daniel Baluta
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2026-03-05 7:11 UTC (permalink / raw)
To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: oe-kbuild-all, Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
Hi Shenwei,
kernel test robot noticed the following build warnings:
[auto build test WARNING on brgl/gpio/for-next]
[also build test WARNING on remoteproc/rproc-next robh/for-next next-20260304]
[cannot apply to linus/master v6.16-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Shenwei-Wang/docs-driver-api-gpio-rpmsg-gpio-driver-over-rpmsg-bus/20260305-052440
base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link: https://lore.kernel.org/r/20260304211808.1437846-2-shenwei.wang%40nxp.com
patch subject: [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260305/202603050819.478UbJ2l-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603050819.478UbJ2l-lkp@intel.com/
All warnings (new ones prefixed by >>):
.. code-block:: none
+-----+-----+-----+-----+-----+----+
|0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
| 1 | 2 |port |line | err | dir|
+-----+-----+-----+-----+-----+----+ [docutils]
>> Documentation/driver-api/gpio/gpio-rpmsg.rst:115: WARNING: Title underline too short.
vim +115 Documentation/driver-api/gpio/gpio-rpmsg.rst
112
113
114 GET_VALUE (Cmd=4)
> 115 ~~~~~~~~~~~~~~~~
116
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
@ 2026-03-05 15:16 ` Frank Li
2026-03-06 7:35 ` Dan Carpenter
2026-03-06 14:24 ` Andrew Lunn
2 siblings, 0 replies; 13+ messages in thread
From: Frank Li @ 2026-03-05 15:16 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Frank Li, Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx
From: Frank Li (AI-BOT) <frank.li@nxp.com>
> +static int imx_std_cmd_map[] = {
AI: Should be 'static const int' since this is a read-only lookup table.
> + if (msg->cmd >= sizeof(imx_std_cmd_map))
AI: Use ARRAY_SIZE(imx_std_cmd_map) instead of sizeof() for clarity.
because imx_std_cmd_map is array, AI most likely is correct.
Frank
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
2026-03-05 7:11 ` kernel test robot
@ 2026-03-05 15:39 ` Daniel Baluta
1 sibling, 0 replies; 13+ messages in thread
From: Daniel Baluta @ 2026-03-05 15:39 UTC (permalink / raw)
To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen
Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Peng Fan, devicetree,
linux-remoteproc, imx, linux-arm-kernel, linux-imx
On 3/4/26 23:18, Shenwei Wang wrote:
[...]
> +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 6-byte packet with the following layout:
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + |type |cmd |port |line | data |
> + +-----+-----+-----+-----+-----+----+
> +
> +- **Type (Message Type)**: The message type can be one of:
> +
> + - 0: GPIO_RPMSG_SEND
> + - 1: GPIO_RPMSG_REPLY
> + - 2: GPIO_RPMSG_NOTIFY
I think would make sense to display the type in hexa. e.g : 0x00, 0x01, etc.
Also, would it make sense to display the byte index as follows outside of the boxes?
> +
> +- **Cmd**: Command code, used for GPIO_RPMSG_SEND messages.
Are there any specific commands? Also please either use upper-case first
letter (e.g Type, Cmd) or lower-case letter (port, line) but do not mix them.
> +
> +- **line**: The GPIO line(pin) index of the port.
In message format line comes after port so switch the order here.
> +
> +- **port**: The GPIO port(bank) index.
> +
> +- **data**: See details in the command description below.
> +
> +- **reply err**: Error code from the remote core.
> +
> + - 0: Success
> + - 1: General error (Early remote software only returns this unclassified error)
> + - 2: Not supported (A command is not supported by the remote firmware)
> + - 3: Resource not available (The resource is not allocated to Linux)
> + - 4: Resource busy (The resource is already in use)
> + - 5: Parameter error
Is this part of the 6-byte packet? Are these standard errors or you defined them as is?
> +
> +
> +GPIO Commands
> +-------------
> +
> +Commands are specified in the **Cmd** field for **GPIO_RPMSG_SEND** (Type=0) messages.
> +
> +The SEND message is always sent from Linux to the remote firmware. Each
> +SEND corresponds to a single REPLY message. The GPIO driver should
Wouldn't be the other way around? Each REPLY corresponds to a single SEND msg?
> +serialize messages and determine whether a REPLY message is required. If a
> +REPLY message is expected but not received within the specified timeout
> +period (currently 1 second in the Linux driver), the driver should return
> +-ETIMEOUT.
> +
> +GET_DIRECTION (Cmd=2)
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 0 | 2 |port |line | 0 | 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +**Reply:**
> +
> +.. code-block:: none
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 1 | 2 |port |line | err | dir|
> + +-----+-----+-----+-----+-----+----+
> +
> +- **err**: See above for definitions.
> +
> +- **dir**: Direction.
> +
> + - 0: Output
> + - 1: Input
> +
> +SET_DIRECTION (Cmd=3)
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 0 | 3 |port |line | dir | 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +- **dir**: Direction.
> +
> + - 0: None
> + - 1: Output
> + - 2: Input
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 1 | 3 |port |line | err | 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +- **err**: See above for definitions.
> +
> +
> +GET_VALUE (Cmd=4)
> +~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 0 | 4 |port |line | 0 | 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +**Reply:**
> +
> +.. code-block:: none
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 1 | 4 |port |line | err | val|
> + +-----+-----+-----+-----+-----+----+
> +
> +- **err**: See above for definitions.
> +
> +- **val**: Direction.
Why is direction High or Low? Or I'm missing something.
> +
> + - 0: High
> + - 1: Low
> +
> +SET_VALUE (Cmd=5)
> +~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 0 | 5 |port |line | val | 0 |
> + +-----+-----+-----+-----+-----+----+
So when getting replies val is at index 5, but when sending requests val is at index 4. Wonder
if we make this consistent? Or at least explain why did you choose this layout.
> +
> +- **val**: Output Level.
> +
> + - 0: High
> + - 1: Low
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 1 | 5 |port |line | err | 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +- **err**: See above for definitions.
> +
> +SET_IRQ_TYPE (Cmd=6)
Is there a cmd for gpio polarity?
[...]
> +
> +NOTIFY_REPLY (Cmd=10)
> +~~~~~~~~~~~~~~~~~~~~
> +The reply message for the notification is optional. The remote firmware can
> +implement it to simulate the interrupt acknowledgment behavior.
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> + +-----+-----+-----+-----+-----+----+
> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
> + | 0 | 10 |port |line |level| 0 |
> + +-----+-----+-----+-----+-----+----+
> +
> +- **line**: The GPIO line(pin) index of the port.
> +- **port**: The GPIO port(bank) index.
> +- **level**: GPIO line status.
> +
> +Notification Message
> +--------------------
> +
> +Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
Here you should clarify who sends the notification messages.
... Notifications are messages sent by the remote core and they have Type=0x02...
[..]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
2026-03-05 15:16 ` Frank Li
@ 2026-03-06 7:35 ` Dan Carpenter
2026-03-06 14:24 ` Andrew Lunn
2 siblings, 0 replies; 13+ messages in thread
From: Dan Carpenter @ 2026-03-06 7:35 UTC (permalink / raw)
To: oe-kbuild, Shenwei Wang, Linus Walleij, Bartosz Golaszewski,
Jonathan Corbet, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Mathieu Poirier, Frank Li, Sascha Hauer,
arnaud.pouliquen
Cc: lkp, oe-kbuild-all, Shuah Khan, linux-gpio, linux-doc,
linux-kernel, Pengutronix Kernel Team, Fabio Estevam,
Shenwei Wang, Peng Fan, devicetree, linux-remoteproc, imx,
linux-arm-kernel, linux-imx
Hi Shenwei,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Shenwei-Wang/docs-driver-api-gpio-rpmsg-gpio-driver-over-rpmsg-bus/20260305-052440
base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link: https://lore.kernel.org/r/20260304211808.1437846-5-shenwei.wang%40nxp.com
patch subject: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
config: x86_64-randconfig-161-20260306 (https://download.01.org/0day-ci/archive/20260306/202603060910.Q5zBquzF-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
smatch: v0.5.0-9004-gb810ac53
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202603060910.Q5zBquzF-lkp@intel.com/
smatch warnings:
drivers/gpio/gpio-rpmsg.c:188 rpmsg_gpio_imx_send_fixed_up() error: buffer overflow 'imx_std_cmd_map' 7 <= 27
vim +/imx_std_cmd_map +188 drivers/gpio/gpio-rpmsg.c
49a0cb20cd49a59 Shenwei Wang 2026-03-04 176 static int rpmsg_gpio_imx_send_fixed_up(struct rpmsg_gpio_info *info,
49a0cb20cd49a59 Shenwei Wang 2026-03-04 177 struct rpmsg_gpio_packet *msg)
49a0cb20cd49a59 Shenwei Wang 2026-03-04 178 {
49a0cb20cd49a59 Shenwei Wang 2026-03-04 179 struct rpmsg_gpio_nxp_packet imx_msg;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 180
49a0cb20cd49a59 Shenwei Wang 2026-03-04 181 if (msg->cmd >= sizeof(imx_std_cmd_map))
This looks like a sizeof() vs ARRAY_SIZE() bug.
49a0cb20cd49a59 Shenwei Wang 2026-03-04 182 return -EINVAL;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 183
49a0cb20cd49a59 Shenwei Wang 2026-03-04 184 imx_msg.id = IMX_RPMSG_ID;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 185 imx_msg.vendor = IMX_RPMSG_VENDOR;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 186 imx_msg.version = IMX_RPMSG_VERSION;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 187 imx_msg.type = msg->type;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 @188 imx_msg.cmd = imx_std_cmd_map[msg->cmd];
^^^^^^^^
Out of bounds.
49a0cb20cd49a59 Shenwei Wang 2026-03-04 189 imx_msg.port_idx = msg->port_idx;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 190 imx_msg.line = msg->line;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 191 imx_msg.val1 = msg->val1;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 192 imx_msg.val2 = msg->val2;
49a0cb20cd49a59 Shenwei Wang 2026-03-04 193
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
2026-03-05 15:16 ` Frank Li
2026-03-06 7:35 ` Dan Carpenter
@ 2026-03-06 14:24 ` Andrew Lunn
2026-03-06 16:34 ` Shenwei Wang
2 siblings, 1 reply; 13+ messages in thread
From: Andrew Lunn @ 2026-03-06 14:24 UTC (permalink / raw)
To: Shenwei Wang
Cc: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer, arnaud.pouliquen,
Shuah Khan, linux-gpio, linux-doc, linux-kernel,
Pengutronix Kernel Team, Fabio Estevam, Peng Fan, devicetree,
linux-remoteproc, imx, linux-arm-kernel, linux-imx
> +static struct rpmsg_gpio_fixed_up imx_fixed_up_data = {
> + .recv_fixed_up = rpmsg_gpio_imx_recv_fixed_up,
> + .send_fixed_up = rpmsg_gpio_imx_send_fixed_up,
> +};
> +
> static int rpmsg_gpio_send_message(struct rpmsg_gpio_port *port,
> struct rpmsg_gpio_packet *msg,
> bool sync)
> @@ -572,6 +711,10 @@ static const struct of_device_id rpmsg_gpio_dt_ids[] = {
>
> static struct rpmsg_device_id rpmsg_gpio_channel_id_table[] = {
> { .name = "rpmsg-io" },
> + {
> + .name = "rpmsg-io-channel",
> + .driver_data = (kernel_ulong_t)(uintptr_t)&imx_fixed_up_data
> + },
Its not clear to me how this gets applied. Don't you need a different
compatible? fsl,rpmsg-gpio-legacy or something?
I would also put it behind a CONFIG_ option, and in a different
module. Nobody needs this code other than your legacy products. You
don't need the bloat for your new devices and other vendors don't need
it.
Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-06 14:24 ` Andrew Lunn
@ 2026-03-06 16:34 ` Shenwei Wang
2026-03-06 16:56 ` Andrew Lunn
0 siblings, 1 reply; 13+ messages in thread
From: Shenwei Wang @ 2026-03-06 16:34 UTC (permalink / raw)
To: Andrew Lunn
Cc: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer,
arnaud.pouliquen@foss.st.com, Shuah Khan,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, Pengutronix Kernel Team,
Fabio Estevam, Peng Fan, devicetree@vger.kernel.org,
linux-remoteproc@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, dl-linux-imx
> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Friday, March 6, 2026 8:24 AM
> To: Shenwei Wang <shenwei.wang@nxp.com>
> Cc: Linus Walleij <linusw@kernel.org>; Bartosz Golaszewski <brgl@kernel.org>;
> Jonathan Corbet <corbet@lwn.net>; Rob Herring <robh@kernel.org>; Krzysztof
> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Bjorn
> Andersson <andersson@kernel.org>; Mathieu Poirier
> <mathieu.poirier@linaro.org>; Frank Li <frank.li@nxp.com>; Sascha Hauer
> <s.hauer@pengutronix.de>; arnaud.pouliquen@foss.st.com; Shuah Khan
> <skhan@linuxfoundation.org>; linux-gpio@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Pengutronix Kernel Team
> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; Peng Fan
> <peng.fan@nxp.com>; devicetree@vger.kernel.org; linux-
> remoteproc@vger.kernel.org; imx@lists.linux.dev; linux-arm-
> kernel@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [EXT] Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy
> firmware protocol
> > +static struct rpmsg_gpio_fixed_up imx_fixed_up_data = {
> > + .recv_fixed_up = rpmsg_gpio_imx_recv_fixed_up,
> > + .send_fixed_up = rpmsg_gpio_imx_send_fixed_up, };
> > +
> > static int rpmsg_gpio_send_message(struct rpmsg_gpio_port *port,
> > struct rpmsg_gpio_packet *msg,
> > bool sync) @@ -572,6 +711,10 @@
> > static const struct of_device_id rpmsg_gpio_dt_ids[] = {
> >
> > static struct rpmsg_device_id rpmsg_gpio_channel_id_table[] = {
> > { .name = "rpmsg-io" },
> > + {
> > + .name = "rpmsg-io-channel",
> > + .driver_data = (kernel_ulong_t)(uintptr_t)&imx_fixed_up_data
> > + },
>
> Its not clear to me how this gets applied. Don't you need a different compatible?
> fsl,rpmsg-gpio-legacy or something?
>
This is not a compatible. It is the RPMSG channel name advertised by the remote processor.
The generic implementation uses "rpmsg-io" as the channel name, and "rpmsg-io-channel" is
used by NXP's existing firmware.
> I would also put it behind a CONFIG_ option, and in a different module. Nobody
> needs this code other than your legacy products. You don't need the bloat for
> your new devices and other vendors don't need it.
>
Other vendors may add fixed up handlers in the same way to support their existing products.
Thanks,
Shenwei
> Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol
2026-03-06 16:34 ` Shenwei Wang
@ 2026-03-06 16:56 ` Andrew Lunn
0 siblings, 0 replies; 13+ messages in thread
From: Andrew Lunn @ 2026-03-06 16:56 UTC (permalink / raw)
To: Shenwei Wang
Cc: Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer,
arnaud.pouliquen@foss.st.com, Shuah Khan,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, Pengutronix Kernel Team,
Fabio Estevam, Peng Fan, devicetree@vger.kernel.org,
linux-remoteproc@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, dl-linux-imx
> Other vendors may add fixed up handlers in the same way to support
> their existing products.
But that is exactly what we don't want. Why bother adding a generic
protocol, if vendors then hack it around to make it compatible with
whatever their legacy systems have? We want to discourage such bad
behaviour.
How do we discourage this? We add the label 'legacy' everywhere we
can, so it looks bad. We put the legacy code into a module, behind a
symbol with LEGACY in its name, which is disabled by default.
The messaging i've seen from ST is that they will use the generic
protocol. We reward them for doing this by not bloating the code they
need with legacy support for other vendors...
Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-03-06 16:56 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-04 21:18 [PATCH v9 0/5] Enable Remote GPIO over RPMSG on i.MX Platform Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 1/5] docs: driver-api: gpio: rpmsg gpio driver over rpmsg bus Shenwei Wang
2026-03-05 7:11 ` kernel test robot
2026-03-05 15:39 ` Daniel Baluta
2026-03-04 21:18 ` [PATCH v9 2/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 3/5] gpio: rpmsg: add generic rpmsg GPIO driver Shenwei Wang
2026-03-04 21:18 ` [PATCH v9 4/5] gpio: rpmsg: add support for NXP legacy firmware protocol Shenwei Wang
2026-03-05 15:16 ` Frank Li
2026-03-06 7:35 ` Dan Carpenter
2026-03-06 14:24 ` Andrew Lunn
2026-03-06 16:34 ` Shenwei Wang
2026-03-06 16:56 ` Andrew Lunn
2026-03-04 21:18 ` [PATCH v9 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc Shenwei Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox