[PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO driver

Beleswar Prasad Padhi b-padhi at ti.com
Mon May 4 01:17:17 PDT 2026


Hi Arnaud,

On 30/04/26 22:10, Arnaud POULIQUEN wrote:
>
>
> On 4/30/26 14:56, Beleswar Prasad Padhi wrote:
>> Hello Arnaud,
>>
>> On 30/04/26 13:05, Arnaud POULIQUEN wrote:
>>> Hello,
>>>
>>> On 4/29/26 21:20, Mathieu Poirier wrote:
>>>> On Wed, 29 Apr 2026 at 12:07, Padhi, Beleswar <b-padhi at ti.com> wrote:
>>>>>
>>>>> Hi Mathieu,
>>>>>
>>>>> On 4/29/2026 11:03 PM, Mathieu Poirier wrote:
>>>>>> On Wed, 29 Apr 2026 at 10:53, Shenwei Wang <shenwei.wang at nxp.com> wrote:
>>>>

[...]

>>>>> My mental model looks like this for the complete picture:
>>>>>
>>>>> 1. namespace/channel#1 = rpmsg-io
>>>>>       a. ept1 -> gpio-controller at 1
>>>>>       b. ept2 -> gpio-controller at 2
>>>>>
>>>>
>>>> I've asked for one endpoint per GPIO controller since the very
>>>> beginning.  I don't yet have a strong opinion on whether to use one
>>>> namespace request per GPIO controller or a single request that spins
>>>> off multiple endpoints.  I'll have to look at your link and reflect on
>>>> that.  Regardless of how we proceed on that front, multiplexing needs
>>>> to happen at the endpoint level rather than the packet level.  This is
>>>> the only way this work can move forward.
>>>>
>>>
>>> I would be more in favor of Mathieu’s proposal: “An endpoint is created with every namespace request.”
>>>
>>> If the endpoint is created only on the Linux side, how do we match the Linux endpoint address with the local port field on the remote side?
>>
>>
>> Simply by sending a message to the remote containing the newly created
>> endpoint and the port idx. Note that is this done just one time, after this
>> Linux need not have the port field in the message everytime its sending
>> a message.
>>
>>>
>>> With a multi-namespace approach, the namespace could be rpmsg-io-[addr], where [addr] corresponds to the GPIO controller address in the DT. This would:
>>
>>
>> You will face the same problem in this case also that you asked above:
>> "how do we match the Linux endpoint address with the local port field
>> on the remote side?"
>
> Sorry I probably introduced confusion here
> my sentence should be;
>  With a multi-namespace approach, the namespace could be rpmsg-io-[port],
>  where [port] corresponds to the GPIO controller port in the DT.
>
>
> For instance:
>
>       rpmsg {
>         rpmsg-io {
>           #address-cells = <1>;
>           #size-cells = <0>;
>
>           gpio at 25 {
>             compatible = "rpmsg-gpio";
>             reg = <25>;
>             gpio-controller;
>             #gpio-cells = <2>;
>             #interrupt-cells = <2>;
>             interrupt-controller;
>           };
>
>           gpio at 32 {
>             compatible = "rpmsg-gpio";
>             reg = <32>;
>             gpio-controller;
>             #gpio-cells = <2>;
>             #interrupt-cells = <2>;
>             interrupt-controller;
>           };
>         };
>       };
>
>  rpmsg-io-25  would match with gpio at 25
>  rpmsg-io-32  would match with gpio at 32
>
>
>>
>> Because the endpoint that is created on a namespace request is also
>> dynamic in nature. How will the remote know which endpoint addr
>> Linux allocated for a namespace that it announced?
>>
>> As an example/PoC, I created a firmware example which announces
>> 2 name services to Linux, one is the standard "rpmsg_chrdev" and
>> the other is a TI specific name service "ti.ipc4.ping-pong". You can
>> see it created 2 different addresses (0x400 and 0x401) for each of
>> the name service request from the same firmware:
>>
>> root at j784s4-evm:~# dmesg | grep virtio0 | grep -i channel
>> [    9.290275] virtio_rpmsg_bus virtio0: creating channel ti.ipc4.ping-pong addr 0xd
>> [    9.311230] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev addr 0xe
>> [    9.496645] rpmsg_chrdev virtio0.rpmsg_chrdev.-1.14: DEBUG: Channel formed from src = 0x400 to dst = 0xe
>> [    9.707255] rpmsg_client_sample virtio0.ti.ipc4.ping-pong.-1.13: new channel: 0x401 -> 0xd!
>>
>> So in this case, rpmsg-io-1 can have different ept addr than rpmsg-io-2
>> Back to same problem. Simple solution is to reply to remote with the
>> created ept addr and the index.
>
> That why I would like to suggest to use the name service field to identify the port/controller, instead of the endpoint address.
>>  
>>>
>>> - match the RPMsg probe with the DT,
>>
>>
>> We can probe from all controllers with a single name service
>> announcement too.
>>
>>> - provide a simple mapping between the port and the endpoint on both sides,
>>
>>
>> We are trying to get rid of this mapping from Linux side to adapt
>> the gpio-virtio design.
>>
>>> - allow multiple endpoints on the remote side,
>>
>>
>> We can support this as well with single nameservice model.
>> There is no limitation. Remote has to send a message with
>> its newly created ept that's all.
>>
>>> - provide a simple discovery mechanism for remote capabilities.
>>
>>
>> A single announcement: "rpmsg-io" is also discovery mechanism.
>>
>> Feel free to let me know if you have concerns with any of the
>> suggestions!
>
> My only concern, whatever the solution, is that we find a smart
> solution to associate the correct endpoint with the correct GPIO
> port/controller defined in the DT. 


In my solution, there is no need to have this map of endpoint to
GPIO port at Linux side. This aligns more with virtio-gpio design
as well.

>
> I may have misunderstood your solution. Could you please help me
> understand your proposal by explaining how you would handle three
> GPIO ports defined in the DT, considering that the endpoint
> addresses on the Linux side can be random?
> If I assume there is a unique endpoint on the remote side,
> I do not understand how you can match, on the firmware side,
> the Linux endpoint address to the GPIO port. 


Sure, let me take an example:
Assumptions: 3 GPIO ports in DT, 3 endpoints in Linux (one per port),
1 endpoint in remote (0xd) and 1 rpmsg channel (rpmsg-io)

       rpmsg {
         rpmsg-io {
           #address-cells = <1>;
           #size-cells = <0>;

           gpio at 25 {
             compatible = "rpmsg-gpio";
             reg = <25>;
             gpio-controller;
             #gpio-cells = <2>;
             #interrupt-cells = <2>;
             interrupt-controller;
           };

           gpio at 32 {
             compatible = "rpmsg-gpio";
             reg = <32>;
             gpio-controller;
             #gpio-cells = <2>;
             #interrupt-cells = <2>;
             interrupt-controller;
           };

           gpio at 35 {
             compatible = "rpmsg-gpio";
             reg = <35>;
             gpio-controller;
             #gpio-cells = <2>;
             #interrupt-cells = <2>;
             interrupt-controller;
           };
         };
       };

Code Flow:
1. "rpmsg-io" channel is announced from remote firmware with unique dst
    ept = 0xd.

2. rpmsg_core.c creates the default dynamic local ept for the channel
    ept = 0x405.

3. rpmsg_core.c assigns the allocated addr to rpdev device:
    rpdev->src = 0x405 and rpdev->dst = 0xd.

4. rpmsg_gpio_channel_probe() is triggered. For *each* of the GPIO ports
    in DT, it will trigger rpmsg_gpiochip_register() which will now:
       a. Call port->ept = rpmsg_create_ept(rpdev,
                                                                   rpmsg_gpio_channel_callback,
                                                                   port,
                                                                  {rpdev.id.name,
                                                                   RPMSG_ADDR_ANY,
                                                                   RPMSG_ADDR_ANY}); 
           Ex- port->ept->addr = 0x408

       b. Prepare a 8-byte message having 2 fields:
           port->ept->addr (0x408) and port->idx (25)

       c. Send this message to remote firmware on default channel ept
           (0x405 -> 0xd) by:
           rpmsg_send(rpdev->ept, &message, sizeof(message));

       d. Remote side receives this message and creates a map of the
           linux_ept_addr to gpio_port. (0x408 <-> 25)

5. After this point, any gpio messages sent from Linux from gpio port
    endpoints (Ex- 0x408) can be decoded at remote side by looking up
    its map (Ex- map[0x408] = 25).

6. Any messages sent from remote to Linux for a particular gpio port can
    also be decoded at Linux by simply fetching the priv pointer to get
    the per-port device:
    struct rpmsg_gpio_port *port = priv;

So Linux does not need to send the port idx everytime while sending a
gpio message anymore.

Thanks,
Beleswar

[...]




More information about the linux-arm-kernel mailing list