diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index b885e1a14f..f3a8b455d5 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -72,6 +72,10 @@ void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); +uint sanbox_i2c_eeprom_get_prev_addr(struct udevice *dev); + +uint sanbox_i2c_eeprom_get_prev_offset(struct udevice *dev); + /** * sandbox_i2c_rtc_set_offset() - set the time offset from system/base time * diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c index 29ed45923f..284267f2ea 100644 --- a/drivers/misc/i2c_eeprom_emul.c +++ b/drivers/misc/i2c_eeprom_emul.c @@ -27,6 +27,8 @@ struct sandbox_i2c_flash_plat_data { struct sandbox_i2c_flash { uint8_t *data; + uint prev_addr; /* slave address of previous access */ + uint prev_offset; /* offset of previous access */ }; void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, @@ -44,6 +46,20 @@ void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len) plat->offset_len = offset_len; } +uint sanbox_i2c_eeprom_get_prev_addr(struct udevice *dev) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + return priv->prev_addr; +} + +uint sanbox_i2c_eeprom_get_prev_offset(struct udevice *dev) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + return priv->prev_offset; +} + static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, int nmsgs) { @@ -52,6 +68,10 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, debug("\n%s\n", __func__); debug_buffer(0, priv->data, 1, 16, 0); + + /* store addr for testing visibity */ + priv->prev_addr = msg->addr; + for (; nmsgs > 0; nmsgs--, msg++) { struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(emul); @@ -60,11 +80,6 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, if (!plat->size) return -ENODEV; - if (msg->addr + msg->len > plat->size) { - debug("%s: Address %x, len %x is outside range 0..%x\n", - __func__, msg->addr, msg->len, plat->size); - return -EINVAL; - } len = msg->len; debug(" %s: msg->len=%d", msg->flags & I2C_M_RD ? "read" : "write", @@ -73,7 +88,16 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) len = 1; debug(", offset %x, len %x: ", offset, len); - memcpy(msg->buf, priv->data + offset, len); + if (offset + len > plat->size) { + int overflow = offset + len - plat->size; + int initial = len - overflow; + + memcpy(msg->buf, priv->data + offset, initial); + memcpy(msg->buf + initial, priv->data, + overflow); + } else { + memcpy(msg->buf, priv->data + offset, len); + } memset(msg->buf + len, '\xff', msg->len - len); debug_buffer(0, msg->buf, 1, msg->len, 0); } else if (len >= plat->offset_len) { @@ -87,15 +111,24 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) len = min(len, 1); - /* For testing, map offsets into our limited buffer */ - for (i = 24; i > 0; i -= 8) { - if (offset > (1 << i)) { - offset = (offset >> i) | - (offset & ((1 << i) - 1)); - offset += i; - } + /* store offset for testing visibility */ + priv->prev_offset = offset; + + /* For testing, map offsets into our limited buffer. + * offset wraps every 256 bytes + */ + offset &= 0xff; + debug("mapped offset to %x\n", offset); + + if (offset + len > plat->size) { + int overflow = offset + len - plat->size; + int initial = len - overflow; + + memcpy(priv->data + offset, ptr, initial); + memcpy(priv->data, ptr + initial, overflow); + } else { + memcpy(priv->data + offset, ptr, len); } - memcpy(priv->data + offset, ptr, len); } } debug_buffer(0, priv->data, 1, 16, 0); diff --git a/test/dm/i2c.c b/test/dm/i2c.c index cbbd4aa29a..bf5597b7a6 100644 --- a/test/dm/i2c.c +++ b/test/dm/i2c.c @@ -15,6 +15,7 @@ #include #include #include +#include #include static const int busnum; @@ -185,35 +186,54 @@ static int dm_test_i2c_offset(struct unit_test_state *uts) ut_assertok(i2c_set_chip_offset_len(dev, 0)); ut_assertok(dm_i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2)); ut_assertok(dm_i2c_read(dev, 0, buf, 5)); - ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf))); + ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); + ut_asserteq(0, sanbox_i2c_eeprom_get_prev_offset(eeprom)); /* Offset length 1 */ sandbox_i2c_eeprom_set_offset_len(eeprom, 1); ut_assertok(i2c_set_chip_offset_len(dev, 1)); ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_asserteq(2, sanbox_i2c_eeprom_get_prev_offset(eeprom)); ut_assertok(dm_i2c_read(dev, 0, buf, 5)); - ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf))); + ut_asserteq_mem("ABAB\0", buf, sizeof(buf)); + ut_asserteq(0, sanbox_i2c_eeprom_get_prev_offset(eeprom)); + + /* Offset length 2 boundary - check model wrapping */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(dm_i2c_write(dev, 0xFF, (uint8_t *)"A", 1)); + ut_asserteq(0xFF, sanbox_i2c_eeprom_get_prev_offset(eeprom)); + ut_assertok(dm_i2c_write(dev, 0x100, (uint8_t *)"B", 1)); + ut_asserteq(0x100, sanbox_i2c_eeprom_get_prev_offset(eeprom)); + ut_assertok(dm_i2c_write(dev, 0x101, (uint8_t *)"C", 1)); + ut_asserteq(0x101, sanbox_i2c_eeprom_get_prev_offset(eeprom)); + ut_assertok(dm_i2c_read(dev, 0xFF, buf, 5)); + ut_asserteq_mem("ABCAB", buf, sizeof(buf)); + ut_asserteq(0xFF, sanbox_i2c_eeprom_get_prev_offset(eeprom)); /* Offset length 2 */ sandbox_i2c_eeprom_set_offset_len(eeprom, 2); ut_assertok(i2c_set_chip_offset_len(dev, 2)); - ut_assertok(dm_i2c_write(dev, 0x210, (uint8_t *)"AB", 2)); - ut_assertok(dm_i2c_read(dev, 0x210, buf, 5)); - ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + ut_assertok(dm_i2c_write(dev, 0x2020, (uint8_t *)"AB", 2)); + ut_assertok(dm_i2c_read(dev, 0x2020, buf, 5)); + ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); + ut_asserteq(0x2020, sanbox_i2c_eeprom_get_prev_offset(eeprom)); /* Offset length 3 */ - sandbox_i2c_eeprom_set_offset_len(eeprom, 2); - ut_assertok(i2c_set_chip_offset_len(dev, 2)); - ut_assertok(dm_i2c_write(dev, 0x410, (uint8_t *)"AB", 2)); - ut_assertok(dm_i2c_read(dev, 0x410, buf, 5)); - ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + sandbox_i2c_eeprom_set_offset_len(eeprom, 3); + ut_assertok(i2c_set_chip_offset_len(dev, 3)); + ut_assertok(dm_i2c_write(dev, 0x303030, (uint8_t *)"AB", 2)); + ut_assertok(dm_i2c_read(dev, 0x303030, buf, 5)); + ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); + ut_asserteq(0x303030, sanbox_i2c_eeprom_get_prev_offset(eeprom)); /* Offset length 4 */ - sandbox_i2c_eeprom_set_offset_len(eeprom, 2); - ut_assertok(i2c_set_chip_offset_len(dev, 2)); - ut_assertok(dm_i2c_write(dev, 0x420, (uint8_t *)"AB", 2)); - ut_assertok(dm_i2c_read(dev, 0x420, buf, 5)); - ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + sandbox_i2c_eeprom_set_offset_len(eeprom, 4); + ut_assertok(i2c_set_chip_offset_len(dev, 4)); + ut_assertok(dm_i2c_write(dev, 0x40404040, (uint8_t *)"AB", 2)); + ut_assertok(dm_i2c_read(dev, 0x40404040, buf, 5)); + ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); + ut_asserteq(0x40404040, sanbox_i2c_eeprom_get_prev_offset(eeprom)); /* Restore defaults */ sandbox_i2c_eeprom_set_offset_len(eeprom, 1);