Hi coreboot community.

Although I am working on coreboot for now more than one year mostly behind the 
scenes I am fairly new on the contributor side.  Yesterday, I have started 
contribution and one of my first value that I would like to give back to the 
community is a driver for I2C controllers that starts to get integrated into 
x86-chips from intel (Baytrail has one as well as X1000 Quark). Please be aware 
that this is not a driver for the well-known SMBus controller.

I have written the driver a few weeks ago and at this time there was a pretty 
simple and therefore really generic interface for I2C buses in coreboot. The 
interface is described in src/include/device/i2c.h and was consist of two 
simple functions: i2c_read() and i2c_write().

With this interface the user of the driver (which in most of the cases will be 
another driver for let’s say an EEPROM) can simply call for instance the 
i2c_read()-function and provide as arguments the i2c-bus, the chip-address of 
the slave (EEPROM here), the address inside the slave, a length and a buffer 
where to store the driver. With these parameters, the I2C driver is able to 
read the desired data in one call and store them into the buffer provided. 
Similar procedure is for the write function. You can see that one logical 
transfer can be directly mapped to one function call of the driver (i2c_read or 
i2c_write).

In mid-December 2014, the interface was changed massive by this two commits: 
7947 and 7751. I have had a look at the new interface and what should I say: It 
is not only completely different (what in general would be OK for me) but it is 
in my point of view a step back. 

Let’s see what is happened here. The functions i2c_read() and i2c_write() where 
replaced by i2c_readb(), i2c_writeb(), i2c_read_raw() and i2c_write_raw(). The 
first two functions can read a single byte from a slave on a given register 
address (EEPROM address in my example here). The second two are meant to read a 
chunk of data from the slave. Both of the functions actually are a wrapper to 
call the real i2c driver interface called i2c_transfer().

But wait a moment…with the last two functions there is no way to tell the 
driver _where_ to start reading inside the slave. Let us have a closer look to 
how this interface can be used to transfer a chunk of data from a given address 
inside the slave. To do this, let us consider we want to read 10 bytes starting 
at offset 20.

1.      Store the offset we need (in this case 20) into a buffer
2.      Call i2c_write_raw(bus, chip_adr, &buffer, 1);
3.      Call i2c_read_raw(bus, chip_adr, &buffer,10);

Here are my personal problems with this kind of interface:
1.      Where we earlier had one simple call to i2c_read(), we now have to fill 
one variable with the length we need and call two different functions 
(i2c_write_raw and i2c_read_raw).
2.      Though the read transfer is one logical access to the slave, we have 
split it into two (without any benefit I can see now)
3.      We have added two wrapper layers where we earlier had none!

Unfortunately, the first two mentioned functions of the interface cannot be 
used for transferring more than byte because the length field is missing. In 
contrast, the two functions that have a length field do not have a slave 
address field. This is frustrating!

If one have a hardware implemented I2C-controller in mind, this interface is 
really not that intuitive and simple. This is because we have to perform a 
function switch in the middle of a logical bus action. And: why should one 
perform i2c_write operation in order to read the data? This is not logical to 
me. I know that I2C bus works this way, but it is the responsibility of the 
driver to hide this from the user. And with this interface, this “hiding” is 
simply impossible because now the user have to do it!

I do not see any benefits of this interface and I really cannot see the need 
for the introduced change in the interface. Of course it is technical possible 
to read and write data over I2C with this interface…but to be honest: I would 
not be proud of this solution!

Of course we can add an address field to the i2c_read_raw and i2c_write_raw 
functions. But at the end we will end up with a complex interface for a very 
simple bus. And we will have several wrapper layers compared to the interface 
we had before. There is even no need of _one_ wrapper layer for this bus!

I hope I was able to point out what my concern is about and want to discuss 
this with the community. I want to hear more opinions on this interface and at 
the end want to know whether it is worse to change my I2C driver to be used 
with this interface. The last point I will do if one can show me the _real_ 
benefit of the new interface.

Thank you
Werner

-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to