[U-Boot] [PATCH v3 4/4] cmd_eeprom: bug fix for i2c read/write
Kuo-Jung Su
dantesu at gmail.com
Tue Dec 3 01:55:41 CET 2013
2013/12/2 Alexey Brodkin <Alexey.Brodkin at synopsys.com>:
> On Mon, 2013-12-02 at 16:02 +0800, Kuo-Jung Su wrote:
>> From: Kuo-Jung Su <dantesu at faraday-tech.com>
>
>> diff --git a/common/cmd_eeprom.c b/common/cmd_eeprom.c
>> index 02539c4..3924805 100644
>> --- a/common/cmd_eeprom.c
>> +++ b/common/cmd_eeprom.c
>> @@ -161,7 +161,7 @@ int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt
>> #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
>> spi_read (addr, alen, buffer, len);
>> #else
>> - if (i2c_read (addr[0], addr[1], alen-1, buffer, len) != 0)
>> + if (i2c_read(addr[0], offset, alen - 1, buffer, len))
>> rcode = 1;
>> #endif
>> buffer += len;
>
> I think this change is whether incomplete or improper.
> Let's look at source code above line 161:
> =============================
> 125 #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
> 126 uchar addr[2];
> 127
> 128 blk_off = offset & 0xFF; /* block offset */
> 129
> 130 addr[0] = offset >> 8; /* block number */
> 131 addr[1] = blk_off; /* block offset */
> 132 alen = 2;
> 133 #else
> 134 uchar addr[3];
> 135
> 136 blk_off = offset & 0xFF; /* block offset */
> 137
> 138 addr[0] = offset >> 16; /* block number */
> 139 addr[1] = offset >> 8; /* upper address
> octet */
> 140 addr[2] = blk_off; /* lower address
> octet */
> 141 alen = 3;
> 142 #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
> 143
> 144 addr[0] |= dev_addr; /* insert device
> address */
> =============================
>
> From these line you see that "addr[0]" is set like this:
> ===========
> If "CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1":
> addr[0] = offset >> 8;
>
> If "CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 1":
> addr[0] = offset >> 16;
>
> And in both cases then OR with "dev_addr":
> addr[0] |= dev_addr;
> ===========
>
This is the reason why I said:
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW is always enabled inside cmd_eeprom.c
so everything is O.K.
> In other words it gets both real I2S slave address + MSB bits of offset.
> But note that "offset" value stays unchanged.
>
The comment bellow clearly explain the issue here.
soft_i2c.c: line 351 ~ 367:
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
chip, addr);
#endif
> So if you pass both "addr[0]" (which already has MSB bits of "offset")
> and "offset" itself then you'll get completely incorrect I2C command.
>
>> @@ -339,7 +339,7 @@ int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cn
>> /* Write is enabled ... now write eeprom value.
>> */
>> #endif
>> - if (i2c_write (addr[0], addr[1], alen-1, buffer, len) != 0)
>> + if (i2c_write(addr[0], offset, alen - 1, buffer, len))
>> rcode = 1;
>>
>> #endif
>
> Same goes to "eeprom_write".
>
> Moreover I'd say that this address/offset tricks are very
> EEPROM-specific and because of this we'd better keep it here and don't
> modify generic I2C code.
>
Yes,the address/offset tricks are device specific (not only EEPROM, it
also applies to Audio Codecs..etc.)
But this code was there over a decade. And if everything works just
fine, why bother ?
> Regards,
> Alexey
>
--
Best wishes,
Kuo-Jung Su
More information about the U-Boot
mailing list