Hello,
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.
- 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>
- 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.
Regards Stefan
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@lists.genode.org https://lists.genode.org/listinfo/users