i2c_eeprom_emul.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Simulate an I2C eeprom
  3. *
  4. * Copyright (c) 2014 Google, Inc
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <errno.h>
  11. #include <i2c.h>
  12. #include <malloc.h>
  13. #include <asm/test.h>
  14. #ifdef DEBUG
  15. #define debug_buffer print_buffer
  16. #else
  17. #define debug_buffer(x, ...)
  18. #endif
  19. DECLARE_GLOBAL_DATA_PTR;
  20. struct sandbox_i2c_flash_plat_data {
  21. enum sandbox_i2c_eeprom_test_mode test_mode;
  22. const char *filename;
  23. int offset_len; /* Length of an offset in bytes */
  24. int size; /* Size of data buffer */
  25. };
  26. struct sandbox_i2c_flash {
  27. uint8_t *data;
  28. };
  29. void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
  30. enum sandbox_i2c_eeprom_test_mode mode)
  31. {
  32. struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
  33. plat->test_mode = mode;
  34. }
  35. void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len)
  36. {
  37. struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
  38. plat->offset_len = offset_len;
  39. }
  40. static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
  41. int nmsgs)
  42. {
  43. struct sandbox_i2c_flash *priv = dev_get_priv(emul);
  44. uint offset = 0;
  45. debug("\n%s\n", __func__);
  46. debug_buffer(0, priv->data, 1, 16, 0);
  47. for (; nmsgs > 0; nmsgs--, msg++) {
  48. struct sandbox_i2c_flash_plat_data *plat =
  49. dev_get_platdata(emul);
  50. int len;
  51. u8 *ptr;
  52. if (!plat->size)
  53. return -ENODEV;
  54. if (msg->addr + msg->len > plat->size) {
  55. debug("%s: Address %x, len %x is outside range 0..%x\n",
  56. __func__, msg->addr, msg->len, plat->size);
  57. return -EINVAL;
  58. }
  59. len = msg->len;
  60. debug(" %s: msg->len=%d",
  61. msg->flags & I2C_M_RD ? "read" : "write",
  62. msg->len);
  63. if (msg->flags & I2C_M_RD) {
  64. if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
  65. len = 1;
  66. debug(", offset %x, len %x: ", offset, len);
  67. memcpy(msg->buf, priv->data + offset, len);
  68. memset(msg->buf + len, '\xff', msg->len - len);
  69. debug_buffer(0, msg->buf, 1, msg->len, 0);
  70. } else if (len >= plat->offset_len) {
  71. int i;
  72. ptr = msg->buf;
  73. for (i = 0; i < plat->offset_len; i++, len--)
  74. offset = (offset << 8) | *ptr++;
  75. debug(", set offset %x: ", offset);
  76. debug_buffer(0, msg->buf, 1, msg->len, 0);
  77. if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
  78. len = min(len, 1);
  79. /* For testing, map offsets into our limited buffer */
  80. for (i = 24; i > 0; i -= 8) {
  81. if (offset > (1 << i)) {
  82. offset = (offset >> i) |
  83. (offset & ((1 << i) - 1));
  84. offset += i;
  85. }
  86. }
  87. memcpy(priv->data + offset, ptr, len);
  88. }
  89. }
  90. debug_buffer(0, priv->data, 1, 16, 0);
  91. return 0;
  92. }
  93. struct dm_i2c_ops sandbox_i2c_emul_ops = {
  94. .xfer = sandbox_i2c_eeprom_xfer,
  95. };
  96. static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
  97. {
  98. struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
  99. plat->size = dev_read_u32_default(dev, "sandbox,size", 32);
  100. plat->filename = dev_read_string(dev, "sandbox,filename");
  101. if (!plat->filename) {
  102. debug("%s: No filename for device '%s'\n", __func__,
  103. dev->name);
  104. return -EINVAL;
  105. }
  106. plat->test_mode = SIE_TEST_MODE_NONE;
  107. plat->offset_len = 1;
  108. return 0;
  109. }
  110. static int sandbox_i2c_eeprom_probe(struct udevice *dev)
  111. {
  112. struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
  113. struct sandbox_i2c_flash *priv = dev_get_priv(dev);
  114. priv->data = calloc(1, plat->size);
  115. if (!priv->data)
  116. return -ENOMEM;
  117. return 0;
  118. }
  119. static int sandbox_i2c_eeprom_remove(struct udevice *dev)
  120. {
  121. struct sandbox_i2c_flash *priv = dev_get_priv(dev);
  122. free(priv->data);
  123. return 0;
  124. }
  125. static const struct udevice_id sandbox_i2c_ids[] = {
  126. { .compatible = "sandbox,i2c-eeprom" },
  127. { }
  128. };
  129. U_BOOT_DRIVER(sandbox_i2c_emul) = {
  130. .name = "sandbox_i2c_eeprom_emul",
  131. .id = UCLASS_I2C_EMUL,
  132. .of_match = sandbox_i2c_ids,
  133. .ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
  134. .probe = sandbox_i2c_eeprom_probe,
  135. .remove = sandbox_i2c_eeprom_remove,
  136. .priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
  137. .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
  138. .ops = &sandbox_i2c_emul_ops,
  139. };