/* * (Fig.40 E-Fuse Program Flow) * Stage 10-9 * Data=0xFF is set in Address=0xEC. * Data=0x03 is set in Address=0xEF. * Read out the data in Address=0x18 and Address=0x19. */ static void e_fuse_stage10_9(Serial *pc) { pc->printf("stage 10-9\r\n"); _i2c_write(0xEC, 0xFF); _i2c_write(0xEF, 0x03); const uint8_t bit_replacemnt_18 = _i2c_read(0x18); const uint8_t bit_replacemnt_19 = _i2c_read(0x19); pc->printf("Check 0x18 => %d\r\n", bit_replacemnt_18); pc->printf("Check 0x19 => %d\r\n", bit_replacemnt_19); if (bit_replacemnt_18 == 0x82 && bit_replacemnt_19 == 0x00) { pc->printf("Bit Replacement (stage 10) is SUCCESSFUL\r\n"); } else { pc->printf("Bit Replacement (stage 10) is FAILURE\r\n"); } }
/* * (Fig.40 E-Fuse Program Flow) * Stage 9 * Data=0xFF is set in Address=0xEC. * Data=0x03 is set in Address=0xEF. * Read out the data in Address=0x27. * Data=0x00 is set in Address=0xEF. * Data=0x7F is set in Address=0xEC. * * @return 0 for success, 1 for failure : 0x27[4:0] & 0b10000(0x10) */ static uint8_t e_fuse_stage9(Serial *pc) { pc->printf("stage 9\r\n"); // Table.20 List of E-Fuse program flow and setting value _i2c_write(0xEF, 0x00); // add this though it's missing in 12-6 Example of E-Fuse Programming _i2c_write(0xEC, 0xFF); _i2c_write(0xEF, 0x03); const uint8_t check_value = _i2c_read(0x27); const uint8_t check = check_value & 0x1f; pc->printf("Check 0x27[4:0] => %d\r\n", check); const uint8_t success = check & 0x10; // When lower 5bits data[4:0] is 00001, E-Fuse program is finished. // When lower 5bits data[4:0] is not 00001, go to stage10(bit replacement). _i2c_write(0xEF, 0x00); _i2c_write(0xEC, 0x7F); // Check Result return success; }
static int32_t _i2c_smbus_ioctl(int dev, uint8_t rw, uint8_t command, size_t size, union i2c_smbus_data *data) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = rw, .command = command, .size = 0, .data = data }; switch (size) { case 1: ioctldata.size = I2C_SMBUS_BYTE_DATA; break; case 2: ioctldata.size = I2C_SMBUS_WORD_DATA; break; default: ioctldata.size = I2C_SMBUS_BLOCK_DATA; } if (ioctl(dev, I2C_SMBUS, &ioctldata) == -1) { return -errno; } return 0; } static void _i2c_write_quick(struct sol_i2c *i2c, bool rw) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = rw, .command = 0, .size = I2C_SMBUS_QUICK, .data = NULL }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus write quick (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return; } i2c->async.status = 1; } static void _i2c_write_quick_dispatch(struct sol_i2c *i2c) { if (!i2c->async.write_quick_cb.cb) return; i2c->async.write_quick_cb.cb((void *)i2c->async.cb_data, i2c, i2c->async.status); } #ifdef WORKER_THREAD static bool i2c_write_quick_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_write_quick(i2c, (bool)(intptr_t)i2c->async.data); return false; } static void i2c_worker_thread_finished(void *data) { struct sol_i2c *i2c = data; i2c->async.worker = NULL; i2c->async.dispatch(i2c); } #else static bool i2c_write_quick_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_write_quick(i2c, (bool)(intptr_t)i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_write_quick(struct sol_i2c *i2c, bool rw, void (*write_quick_cb)(void *cb_data, struct sol_i2c *i2c, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_write_quick_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = (uint8_t *)(long)rw; i2c->async.status = -1; i2c->async.write_quick_cb.cb = write_quick_cb; i2c->async.dispatch = _i2c_write_quick_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_write_quick_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static bool write_byte(const struct sol_i2c *i2c, uint8_t byte) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = I2C_SMBUS_WRITE, .command = byte, .size = I2C_SMBUS_BYTE, .data = NULL }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus write byte (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return false; } return true; } static bool read_byte(const struct sol_i2c *i2c, uint8_t *byte) { union i2c_smbus_data data; struct i2c_smbus_ioctl_data ioctldata = { .read_write = I2C_SMBUS_READ, .command = 0, .size = I2C_SMBUS_BYTE, .data = &data, }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus read byte (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return false; } *byte = data.byte; return true; } static void _i2c_read(struct sol_i2c *i2c, uint8_t *values) { size_t i; for (i = 0; i < i2c->async.count; i++) { uint8_t byte; if (!read_byte(i2c, &byte)) return; *values = byte; values++; } i2c->async.status = i2c->async.count; } static void _i2c_read_write_dispatch(struct sol_i2c *i2c) { if (!i2c->async.read_write_cb.cb) return; i2c->async.read_write_cb.cb((void *)i2c->async.cb_data, i2c, i2c->async.data, i2c->async.status); } #ifdef WORKER_THREAD static bool i2c_read_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_read(i2c, i2c->async.data); return false; } #else static bool i2c_read_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_read(i2c, i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_read(struct sol_i2c *i2c, uint8_t *values, size_t count, void (*read_cb)(void *cb_data, struct sol_i2c *i2c, uint8_t *data, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_read_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_NULL_CHECK(values, NULL); SOL_INT_CHECK(count, == 0, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = values; i2c->async.count = count; i2c->async.status = -1; i2c->async.read_write_cb.cb = read_cb; i2c->async.dispatch = _i2c_read_write_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_read_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static void _i2c_write(struct sol_i2c *i2c, uint8_t *values) { size_t i; for (i = 0; i < i2c->async.count; i++) { if (!write_byte(i2c, *values)) return; values++; } i2c->async.status = i2c->async.count; } #ifdef WORKER_THREAD static bool i2c_write_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_write(i2c, i2c->async.data); return false; } #else static bool i2c_write_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_write(i2c, i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_write(struct sol_i2c *i2c, uint8_t *values, size_t count, void (*write_cb)(void *cb_data, struct sol_i2c *i2c, uint8_t *data, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_write_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_NULL_CHECK(values, NULL); SOL_INT_CHECK(count, == 0, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = values; i2c->async.count = count; i2c->async.status = -1; i2c->async.read_write_cb.cb = write_cb; i2c->async.dispatch = _i2c_read_write_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_write_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static int sol_i2c_plain_read_register(const struct sol_i2c *i2c, uint8_t command, uint8_t *values, size_t count) { struct i2c_msg msgs[] = { { .addr = i2c->addr, .flags = 0, .len = 1, .buf = &command }, { .addr = i2c->addr, .flags = I2C_M_RD, .len = count, .buf = values, } };