Hi Werner,

I agree we could probably do a little better than we do today (feel free to
submit a patch ;)),
but speaking for what I have seen on bringing up Chrome OS devices, the
ODMs ultimately
end up having to tweak these values depending on the board design (bus
load, etc.); e.g.

```
$
 git grep 'scl_lcnt' -- src/mainboard/google/*.cb | wc -l
72
```

One idea we've had is to implement a sysfs interface in the Linux kernel to
expose
a way to change these registers at runtime, so they can be tuned, or add a
custom
module to our payload (depthcharge) to allow tuning these values in the CLI.

-Tim

On Tue, Apr 27, 2021 at 3:01 AM Zeh, Werner <werner....@siemens.com> wrote:

> Hi everybody.
>
> We do have a driver for a widely used I2C-controller from Designware in
> src/drivers/i2c/designware.
> It is used across multiple platforms and has a quite good configurability
> from mainboard side. One can tweak everything needed and make it work with
> the needed timing easily.
> Though I stumbled lately across a thing I wouldn't expect the way it is.
>
> It is possible to define the speed one needs to operate the I2C bus on in
> devicetree by setting the .speed-value to one of the supported defines
> (I2C_SPEED_STANDARD, I2C_SPEED_FAST, I2C_SPEED_FAST_PLUS, I2C_SPEED_HIGH or
> I2C_SPEED_FAST_ULTRA), e.g.:
>
> register "common_soc_config" = "{
>         .i2c[0] = {
>                 .speed = I2C_SPEED_STANDARD
>                  }
>         }"
>
> If one just sets the .speed value, the driver will take care about the
> needed SCL clock rate and set it up to a default value. Yes, these values
> might be not the best for the current bus load but should at least provide
> a clock that matches the requested speed.
> This default values are defined in src/drivers/i2c/designware/dw_i2c.c as
> follows:
> /* High and low times in different speed modes (in ns) */
> enum {
>         /* SDA Hold Time */
>         DEFAULT_SDA_HOLD_TIME   = 300,
>         /* Standard Speed */
>         MIN_SS_SCL_HIGHTIME     = 4000,
>         MIN_SS_SCL_LOWTIME              = 4700,
>         /* Fast Speed */
>         MIN_FS_SCL_HIGHTIME     = 600,
>         MIN_FS_SCL_LOWTIME              = 1300,
>         /* Fast Plus Speed */
>         MIN_FP_SCL_HIGHTIME     = 260,
>         MIN_FP_SCL_LOWTIME      = 500,
>         /* High Speed */
>         MIN_HS_SCL_HIGHTIME     = 60,
>         MIN_HS_SCL_LOWTIME      = 160,
> };
>
> While these values do match the needed _minimum_ durations for the high
> and low period of the SCL signal according to the I2C-specification [1],
> they are not enough for the overall clock cycle to match the requested
> speed. Let's take standard speed for example:
>
> MIN_SS_SCL_HIGHTIME = 4,0 us, MIN_SS_SCL_LOWTIME = 4,7 µs
>         ==> MIN_SS_SCL_HIGHTIME + MIN_SS_SCL_LOWTIME = 8,7 µs which equals
> to 114,943 kHz instead of 100 kHz
> The same applies to the other speeds as well.
>
> As the driver is aware of the clock the IP is clocked with inside the
> Chipset/SoC (CONFIG_DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ), it can be done
> right. There is code already which computes the needed counter values for
> high and low period from the provided IP-clock, *LOWTIME and *HIGHTIME in
> dw_i2c_gen_speed_config():
> ...
> if (speed >= I2C_SPEED_HIGH) {
>         /* High speed */
>         hcnt_min = MIN_HS_SCL_HIGHTIME;
>         lcnt_min = MIN_HS_SCL_LOWTIME;
> } else if (speed >= I2C_SPEED_FAST_PLUS) {
>         /* Fast-Plus speed */
>         hcnt_min = MIN_FP_SCL_HIGHTIME;
>         lcnt_min = MIN_FP_SCL_LOWTIME;
> } else if (speed >= I2C_SPEED_FAST) {
>         /* Fast speed */
>         hcnt_min = MIN_FS_SCL_HIGHTIME;
>         lcnt_min = MIN_FS_SCL_LOWTIME;
> } else {
>         /* Standard speed */
>         hcnt_min = MIN_SS_SCL_HIGHTIME;
>         lcnt_min = MIN_SS_SCL_LOWTIME;
> }
> config->speed = speed;
> config->scl_hcnt = ic_clk * hcnt_min / KHz;
> config->scl_lcnt = ic_clk * lcnt_min / KHz;
> config->sda_hold = ic_clk * DEFAULT_SDA_HOLD_TIME / KHz;
> ...
>
> I tend to change the high and low values
> (MIN_{SS,FS,FPHS}_SCL_{HIGH,LOW}TIME) to match the needed minimum
> constraints while still fulfilling the overall clock cycle, e.g. by
> increasing the HIGHTIME.
> But I would like to hear other opinions on that. Surely I am not aware of
> all the use cases out there.
>
> And again: These default values can easily be overridden in the devicetree
> with something like this:
> register "common_soc_config" = "{
>         .i2c[0] = {
>                 .speed = I2C_SPEED_STANDARD,
>                 .speed_config[0] = {
>                         .speed = I2C_SPEED_STANDARD,
>                         .scl_lcnt = 664,
>                         .scl_hcnt = 657, /*This value is smaller due to
> the IP adding a count of 8 internally, see [2]*/
>                         .sda_hold = 39
>                 }
>         },
> }"
>
> But I would expect the driver to do it right in the default configuration.
>
> Any input is highly welcome.
>
> Werner
>
> [1] https://www.nxp.com/docs/en/user-guide/UM10204.pdf
> [2]
> https://dokumen.tips/documents/designware-dw-apb-i2c-databook-pudn-designware-dwapbi2c-databook-preface-preface.html
> _______________________________________________
> coreboot mailing list -- coreboot@coreboot.org
> To unsubscribe send an email to coreboot-le...@coreboot.org
>
_______________________________________________
coreboot mailing list -- coreboot@coreboot.org
To unsubscribe send an email to coreboot-le...@coreboot.org

Reply via email to