RPC Interface for I2C Driver

Stefan Kalkowski stefan.kalkowski at genode-labs.com
Thu Feb 25 15:44:01 CET 2021


I just want to share my thoughts on this topic inline below:

On Thu, Feb 25, 2021 at 02:48:32PM +0100, Christian Helmuth wrote:
> Hello Jean-Adrien,
> first please note that I'm far from an export for I2C but nevertheless
> like to share my thoughts from an architectural perspective on Genode.
> On Thu, Feb 25, 2021 at 10:57:21 CET, Jean-Adrien Domage wrote:
> > We would like to introduce an i2c driver for imx8q_evk to Genode. Thanks to
> > the hints from Sebastian, I now have a prototype component that can
> > send/receive data via the i2c bus of the imx8q_evk. The next task is to
> > design the RPC interface for the driver.
> My first impulse was to respond with: Why don't you reuse an existing
> RPC interface as there are quite many use cases covered with these.
> But thinking about the task more I could not find a fit in the current
> arsenal myself ;-)
> > What would be a good kind of interface? Do you have driver(s)/component(s)
> > to recommend as example? Or any specific guidelines?
> In my opinion there are two design questions to answer.
> 1. What is the nature of I2C and how should it be reflected in Genode?
> According to Wikipedia [1], I2C is a master-slave bus comparable to
> USB on a high level but far less complex. The master may request read
> or write transactions from/to a slave peripheral. I can't derive the
> requirement for an interrupt scheme resp. asynchronous operation from
> this information. Naturally, peripherals are addressed in some way by
> a _bus address_.
> As I've limited to no hands-on experience with I2C hardware, I'd start
> with a design that considers the Genode host's I2C bus driver as the
> bus master, which sends request transactions to a bunch of slave
> peripherals on the bus. Each peripheral is a distinct hardware
> resource possibly used by distinct Genode components. Therefore, the
> permission to address requests to _one_ I2C peripheral should be
> expressed by a session. Multiple peripherals can be accessed via
> multiple sessions each one dedicated to one device on the I2C bus. The
> bus driver can then be configured by policies that match session
> labels to bus addresses and, thereby, the permission to interact with
> one specific peripheral.
> A rough example of a Genode configuration may look like follows.
>   <start name="i2c_bus_drv">
>     <provides> <service name="I2c"/> </provides>
>     <config>
>       <policy label_prefix="sensor"     bus_address="1"/>
>       <policy label_prefix="motor"      bus_address="2"/>
>       <policy label_prefix="peripheral" bus_address="5"/>
>     </config>
>     <route>
>       <!-- allow the bus driver to access required I/O resources -->
>     </route>
>   </start>
>   <start name="combined_drv">
>     <route>
>       <!-- driver requests 2 sessions - "sensor" and "motor" -->
>       <service name="I2c" label="sensor"> <child name="i2c_bus_drv" label="sensor"/> </service>
>       <service name="I2c" label="motor">  <child name="i2c_bus_drv" label="motor"/>  </service>
>     </route>
>   </start>
>   <start name="single_drv">
>     <route>
>       <service name="I2c"> <child name="i2c_bus_drv" label="peripheral"/> </service>
>     </route>
>   </start>
> 2. How should an appropriate functional session interface look like?
> According to what I learned from Wikipedia, the most simple operations
> required are like follows.
>   uint8_t read_byte()
>   void    write_byte(uint8_t)

>From my limited experience with I2C-connected devices, the most
prominent way of using it is to access device registers. Thereby,
above mentioned I2C addresses refer to the devices connected to the bus.

When taking the interface proposed by Christian as given, a driver
would need to do one write/read for reading a device register, and a
write/write to write it. The first write is always the relative device
register address.

Therefore, it is more accurate in my eyes to transfer it one step,
when designing the RPC interface, like:

  uint8_t read(uint8_t addr);
  void    write(uint8_t addr, uint8_t value);

Most device registers are even bigger than one byte. A common register
width is mostly 16-bit or even 32-bit wide. Accordingly, it would be
good to match this in the interface too.

>From my point of view, the I2C-bus, I/O port, and PCI(/x)
configuration space access have much in common with regards to its
API needs. In fact, it is mostly about device configuration resp.
register access. The device driver that needs to access it, shouldn't
care much about the concrete bus-interface.
Moreover, to not fray the RPC interface landscape I would actually
love to use one common interface. For the beginning a set of
read/write pairs for bytes, half-words, and words would be sufficient
in my eyes.


> The functions do not need a bus address parameter as the session
> hard-wires the access to one peripheral. The sketched operations may
> not suffice if I2C supports multi-byte transactions and those are
> required by the peripherals too. These could be added easily later.
> [1] https://en.wikipedia.org/wiki/I%C2%B2C
> I hope this helps you starting your design and are curious which
> solution you are going to propose.
> Regards
> -- 
> Christian Helmuth
> Genode Labs
> https://www.genode-labs.com/ · https://genode.org/
> https://twitter.com/GenodeLabs · /ˈdʒiː.nəʊd/
> Genode Labs GmbH · Amtsgericht Dresden · HRB 28424 · Sitz Dresden
> Geschäftsführer: Dr.-Ing. Norman Feske, Christian Helmuth
> _______________________________________________
> Genode users mailing list
> users at lists.genode.org
> https://lists.genode.org/listinfo/users

Stefan Kalkowski
Genode labs

https://github.com/skalk | https://genode.org

More information about the users mailing list