123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /*
- * Simulate an I2C eeprom
- *
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.h>
- #include <dm.h>
- #include <errno.h>
- #include <fdtdec.h>
- #include <i2c.h>
- #include <malloc.h>
- #include <asm/test.h>
- #ifdef DEBUG
- #define debug_buffer print_buffer
- #else
- #define debug_buffer(x, ...)
- #endif
- DECLARE_GLOBAL_DATA_PTR;
- struct sandbox_i2c_flash_plat_data {
- enum sandbox_i2c_eeprom_test_mode test_mode;
- const char *filename;
- int offset_len; /* Length of an offset in bytes */
- int size; /* Size of data buffer */
- };
- struct sandbox_i2c_flash {
- uint8_t *data;
- };
- void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
- enum sandbox_i2c_eeprom_test_mode mode)
- {
- struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
- plat->test_mode = mode;
- }
- void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len)
- {
- struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
- plat->offset_len = offset_len;
- }
- static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
- int nmsgs)
- {
- struct sandbox_i2c_flash *priv = dev_get_priv(emul);
- uint offset = 0;
- debug("\n%s\n", __func__);
- debug_buffer(0, priv->data, 1, 16, 0);
- for (; nmsgs > 0; nmsgs--, msg++) {
- struct sandbox_i2c_flash_plat_data *plat =
- dev_get_platdata(emul);
- int len;
- u8 *ptr;
- 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",
- msg->len);
- if (msg->flags & I2C_M_RD) {
- 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);
- memset(msg->buf + len, '\xff', msg->len - len);
- debug_buffer(0, msg->buf, 1, msg->len, 0);
- } else if (len >= plat->offset_len) {
- int i;
- ptr = msg->buf;
- for (i = 0; i < plat->offset_len; i++, len--)
- offset = (offset << 8) | *ptr++;
- debug(", set offset %x: ", offset);
- debug_buffer(0, msg->buf, 1, msg->len, 0);
- 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;
- }
- }
- memcpy(priv->data + offset, ptr, len);
- }
- }
- debug_buffer(0, priv->data, 1, 16, 0);
- return 0;
- }
- struct dm_i2c_ops sandbox_i2c_emul_ops = {
- .xfer = sandbox_i2c_eeprom_xfer,
- };
- static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
- {
- struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
- plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
- "sandbox,size", 32);
- plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset,
- "sandbox,filename", NULL);
- if (!plat->filename) {
- debug("%s: No filename for device '%s'\n", __func__,
- dev->name);
- return -EINVAL;
- }
- plat->test_mode = SIE_TEST_MODE_NONE;
- plat->offset_len = 1;
- return 0;
- }
- static int sandbox_i2c_eeprom_probe(struct udevice *dev)
- {
- struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
- struct sandbox_i2c_flash *priv = dev_get_priv(dev);
- priv->data = calloc(1, plat->size);
- if (!priv->data)
- return -ENOMEM;
- return 0;
- }
- static int sandbox_i2c_eeprom_remove(struct udevice *dev)
- {
- struct sandbox_i2c_flash *priv = dev_get_priv(dev);
- free(priv->data);
- return 0;
- }
- static const struct udevice_id sandbox_i2c_ids[] = {
- { .compatible = "sandbox,i2c-eeprom" },
- { }
- };
- U_BOOT_DRIVER(sandbox_i2c_emul) = {
- .name = "sandbox_i2c_eeprom_emul",
- .id = UCLASS_I2C_EMUL,
- .of_match = sandbox_i2c_ids,
- .ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
- .probe = sandbox_i2c_eeprom_probe,
- .remove = sandbox_i2c_eeprom_remove,
- .priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
- .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
- .ops = &sandbox_i2c_emul_ops,
- };
|