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