summaryrefslogtreecommitdiff
path: root/util/iteflash.c
diff options
context:
space:
mode:
authorMatthew Blecker <matthewb@chromium.org>2018-10-24 18:48:06 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-11-02 10:46:26 -0700
commit12bbb6b1d838b10f38afcca2c421856829a431cb (patch)
tree09c4c927e7411d9ce58d152e894a4798659a9aa1 /util/iteflash.c
parent826ba21fb5d5e7285201b04856dfc89ab2c4656a (diff)
downloadchrome-ec-12bbb6b1d838b10f38afcca2c421856829a431cb.tar.gz
iteflash: Refactor I2C interface and configuration handling.
Currently iteflash supports two I2C interfaces, CCD and FTDI. While tracked in an enum, the function calls were handled by many "if" branches. Also, most configuration settings are stored in static global variables. This replaces the "if" branches after initial option parsing with a struct of callbacks, which can be implemented for any I2C interface. This also moves the static global config variables into a config struct, which becomes part of common_hnd which is already passed around ~everywhere. This replaces the -c / --ccd flag with a -c / --i2c-interface flag which takes an argument of an interface name, currently "ccd" or "ftdi", the latter being the default for compatibility with current flash_ec invocation of iteflash. (Refactoring bonus: The new flag can be specified anywhere on the command line.) This adds a -W / --send_waveform boolean flag which can be set explicitly true or false. The default is false, with flash_ec updated to set it to true to maintain the current behavior. This change is in preparation for supporting a third interface type, the Linux i2c-dev interface to Linux kernel I2C adapters. In the long term direct use of FTDI or CCD I2C interfaces may become unused, however at the very least there will need to be a migration period where all three I2C interfaces are supported, and we may want to continue supporting direct use of CCD and possibly FTDI indefinitely. (Both CCD and FTDI / Servo v2 will be supported indirectly via Linux i2c-dev, along with other Servo versions.) BRANCH=none BUG=b:79684405 TEST=With Servo v2 "flash_ec --board=bip" continues to work. Change-Id: I6d96777016d05947acc5b0c073a315dfa2fe72c3 Signed-off-by: Matthew Blecker <matthewb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1300373 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Diffstat (limited to 'util/iteflash.c')
-rw-r--r--util/iteflash.c457
1 files changed, 290 insertions, 167 deletions
diff --git a/util/iteflash.c b/util/iteflash.c
index 95a60c1c97..d608031f83 100644
--- a/util/iteflash.c
+++ b/util/iteflash.c
@@ -49,10 +49,10 @@
#define CHIP_ID 0x8380
/* Embedded flash page size */
-#define PAGE_SIZE 256
+#define PAGE_SIZE (1<<8)
/* Embedded flash block write size for different programming modes. */
-#define FTDI_BLOCK_WRITE_SIZE 65536
+#define FTDI_BLOCK_WRITE_SIZE (1<<16)
/* Embedded flash number of pages in a sector erase */
#define SECTOR_ERASE_PAGES 4
@@ -78,56 +78,63 @@
#define RSTS_HGRST 0x08
#define RSTS_GRST 0x04
-/* store custom parameters */
-const char *input_filename;
-const char *output_filename;
-static int usb_vid = SERVO_USB_VID;
-static int usb_pid = SERVO_USB_PID;
-static int usb_interface = SERVO_INTERFACE;
-static char *usb_serial;
-static int flash_size;
-static int exit_requested;
-static int is8320dx;
-
-/* debug traces : default OFF*/
-static int debug;
-
-/* optional command flags */
-enum {
- FLAG_UNPROTECT = 0x01,
- FLAG_ERASE = 0x02,
- FLAG_CCD_MODE = 0x04
-};
-
-enum interface_type {
- FTDI_IF,
- CCD_IF
+static volatile sig_atomic_t exit_requested;
+
+struct i2c_interface;
+
+/* Config mostly comes from the command line. Defaults are set in main(). */
+struct iteflash_config {
+ const char *input_filename;
+ const char *output_filename;
+ int send_waveform; /* boolean */
+ int unprotect; /* boolean */
+ int erase; /* boolean */
+ int debug; /* boolean */
+ int usb_interface;
+ int usb_vid;
+ int usb_pid;
+ const char *usb_serial;
+ const struct i2c_interface *i2c_if;
};
struct common_hnd {
- enum interface_type iftype;
+ struct iteflash_config conf;
+ int flash_size;
+ int is8320dx; /* boolean */
union {
struct ftdi_context *ftdi_hnd;
struct usb_endpoint uep;
};
};
-/* number of bytes to send consecutively before checking for ACKs */
-#define TX_BUFFER_LIMIT 32
+/* For all callback return values, zero indicates success, non-zero failure. */
+struct i2c_interface {
+ /* Optional, may be NULL. */
+ int (*interface_init)(struct common_hnd *chnd);
+ /* Always called if non-NULL, even if special waveform is skipped! */
+ /* Optional, may be NULL. */
+ int (*interface_post_waveform)(struct common_hnd *chnd);
+ /* Called exactly once if and only if interface_init() succeeded. */
+ /* Optional, may be NULL. */
+ int (*interface_shutdown)(struct common_hnd *chnd);
+ /* Optional, may be NULL (unsupported for this I2C interface type). */
+ int (*send_special_waveform)(struct common_hnd *chnd);
+ /* Required, must not be NULL. */
+ int (*byte_transfer)(struct common_hnd *chnd, uint8_t addr,
+ uint8_t *data, int write, int numbytes);
+ /* Required, must be positive. */
+ int block_write_size;
+};
-/* For backwards compatibility let FTDI value be the default. */
-static int block_write_size_ = FTDI_BLOCK_WRITE_SIZE;
-static int block_write_size(void)
-{
- return block_write_size_;
-}
+/* number of bytes to send consecutively before checking for ACKs */
+#define FTDI_TX_BUFFER_LIMIT 32
static int i2c_add_send_byte(struct ftdi_context *ftdi, uint8_t *buf,
- uint8_t *ptr, uint8_t *tbuf, int tcnt)
+ uint8_t *ptr, uint8_t *tbuf, int tcnt, int debug)
{
int ret, i, j, remaining_data, ack_idx;
int tx_buffered = 0;
- static uint8_t ack[TX_BUFFER_LIMIT];
+ static uint8_t ack[FTDI_TX_BUFFER_LIMIT];
uint8_t *b = ptr;
uint8_t failed_ack = 0;
@@ -151,10 +158,10 @@ static int i2c_add_send_byte(struct ftdi_context *ftdi, uint8_t *buf,
tx_buffered++;
/*
- * On the last byte, or every TX_BUFFER_LIMIT bytes, read the
- * ACK bits.
+ * On the last byte, or every FTDI_TX_BUFFER_LIMIT bytes, read
+ * the ACK bits.
*/
- if (i == tcnt-1 || (tx_buffered == TX_BUFFER_LIMIT)) {
+ if (i == tcnt-1 || (tx_buffered == FTDI_TX_BUFFER_LIMIT)) {
/* write data */
ret = ftdi_write_data(ftdi, buf, b - buf);
if (ret < 0) {
@@ -198,7 +205,7 @@ static int i2c_add_send_byte(struct ftdi_context *ftdi, uint8_t *buf,
}
static int i2c_add_recv_bytes(struct ftdi_context *ftdi, uint8_t *buf,
- uint8_t *ptr, uint8_t *rbuf, int rcnt)
+ uint8_t *ptr, uint8_t *rbuf, int rcnt)
{
int ret, i, rbuf_idx;
uint8_t *b = ptr;
@@ -246,8 +253,15 @@ static int i2c_add_recv_bytes(struct ftdi_context *ftdi, uint8_t *buf,
return ret;
}
+static inline int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
+ uint8_t *data, int write, int numbytes)
+{
+ return chnd->conf.i2c_if->byte_transfer(chnd, addr, data, write,
+ numbytes);
+}
+
#define USB_I2C_HEADER_SIZE 4
-static int ccd_i2c_byte_transfer(struct usb_endpoint *uep, uint8_t addr,
+static int ccd_i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
uint8_t *data, int write, int numbytes)
{
uint8_t usb_buffer[USB_I2C_HEADER_SIZE + numbytes +
@@ -292,7 +306,7 @@ static int ccd_i2c_byte_transfer(struct usb_endpoint *uep, uint8_t addr,
}
response_size = 0;
- usb_trx(uep, usb_buffer,
+ usb_trx(&chnd->uep, usb_buffer,
write ? sizeof(usb_buffer) : USB_I2C_HEADER_SIZE + extra,
usb_buffer, sizeof(usb_buffer), 1, &response_size);
@@ -325,8 +339,8 @@ static int ccd_i2c_byte_transfer(struct usb_endpoint *uep, uint8_t addr,
return 0;
}
-static int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
- uint8_t *data, int write, int numbytes)
+static int ftdi_i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
+ uint8_t *data, int write, int numbytes)
{
int ret, rets;
static uint8_t buf[FTDI_CMD_BUF_SIZE];
@@ -334,10 +348,6 @@ static int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
uint8_t slave_addr;
struct ftdi_context *ftdi;
- if (chnd->iftype == CCD_IF)
- return ccd_i2c_byte_transfer(&chnd->uep, addr,
- data, write, numbytes);
-
ret = 0;
b = buf;
ftdi = chnd->ftdi_hnd;
@@ -355,9 +365,9 @@ static int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
/* send address */
slave_addr = (addr << 1) | (write ? 0 : 1);
- ret = i2c_add_send_byte(ftdi, buf, b, &slave_addr, 1);
+ ret = i2c_add_send_byte(ftdi, buf, b, &slave_addr, 1, chnd->conf.debug);
if (ret < 0) {
- if (debug)
+ if (chnd->conf.debug)
fprintf(stderr, "address %02x failed\n", addr);
ret = -ENXIO;
goto exit_xfer;
@@ -365,7 +375,8 @@ static int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
b = buf;
if (write) /* write data */
- ret = i2c_add_send_byte(ftdi, buf, b, data, numbytes);
+ ret = i2c_add_send_byte(ftdi, buf, b, data, numbytes,
+ chnd->conf.debug);
else /* read data */
ret = i2c_add_recv_bytes(ftdi, buf, b, data, numbytes);
@@ -413,6 +424,7 @@ static int i2c_read_byte(struct common_hnd *chnd, uint8_t cmd, uint8_t *data)
return 0;
}
+/* Fills in chnd->flash_size */
static int check_chipid(struct common_hnd *chnd)
{
int ret;
@@ -458,19 +470,19 @@ static int check_chipid(struct common_hnd *chnd)
}
/* compute embedded flash size from CHIPVER field */
if ((ver & 0x0f) == 0x03) {
- flash_size = DX[(ver & 0xF0)>>5] * 1024;
- is8320dx = 1;
+ chnd->flash_size = DX[(ver & 0xF0)>>5] * 1024;
+ chnd->is8320dx = 1;
} else {
- flash_size = (128 + (ver & 0xF0)) * 1024;
- is8320dx = 0;
+ chnd->flash_size = (128 + (ver & 0xF0)) * 1024;
+ chnd->is8320dx = 0;
}
printf("CHIPID %04x, CHIPVER %02x, Flash size %d kB\n", id, ver,
- flash_size / 1024);
+ chnd->flash_size / 1024);
return 0;
}
-/* DBGR Reset*/
+/* DBGR Reset */
static int dbgr_reset(struct common_hnd *chnd, unsigned char val)
{
int ret = 0;
@@ -489,7 +501,7 @@ static int dbgr_reset(struct common_hnd *chnd, unsigned char val)
return 0;
}
-/* disable watchdog*/
+/* disable watchdog */
static int dbgr_disable_watchdog(struct common_hnd *chnd)
{
int ret = 0;
@@ -646,7 +658,7 @@ failed_read_status:
return ret;
}
-static int config_i2c(struct ftdi_context *ftdi)
+static int ftdi_config_i2c(struct ftdi_context *ftdi)
{
int ret;
uint8_t buf[5];
@@ -699,7 +711,7 @@ static int config_i2c(struct ftdi_context *ftdi)
#define SPECIAL_BUFFER_SIZE \
(((SPECIAL_LEN_USEC * SPECIAL_FREQ * 2 / USEC) + 7) & ~7)
-static int ccd_trigger_special_waveform(struct usb_endpoint *uep)
+static int ccd_trigger_special_waveform(struct common_hnd *chnd)
{
uint8_t response[20];
size_t rsize;
@@ -711,7 +723,8 @@ static int ccd_trigger_special_waveform(struct usb_endpoint *uep)
CROS_CMD_ITE_SYNC
};
- usb_trx(uep, req, sizeof(req), response, sizeof(response), 1, &rsize);
+ usb_trx(&chnd->uep, req, sizeof(req), response, sizeof(response), 1,
+ &rsize);
if (rsize < USB_I2C_HEADER_SIZE)
return -1;
@@ -722,17 +735,26 @@ static int ccd_trigger_special_waveform(struct usb_endpoint *uep)
return 0;
}
-static int ftdi_send_special_waveform(struct ftdi_context *ftdi, uint64_t *wave)
+static int ftdi_send_special_waveform(struct common_hnd *chnd)
{
int ret;
int i;
uint8_t release_lines[] = {SET_BITS_LOW, 0, 0};
+ uint64_t *wave;
+ struct ftdi_context *ftdi = chnd->ftdi_hnd;
+
+ wave = malloc(SPECIAL_BUFFER_SIZE);
+ if (!wave) {
+ fprintf(stderr, "malloc(%zu) failed\n",
+ (size_t)SPECIAL_BUFFER_SIZE);
+ return -1;
+ }
/* Reset the FTDI into a known state */
ret = ftdi_set_bitmode(ftdi, 0xFF, BITMODE_RESET);
if (ret) {
fprintf(stderr, "failed to reset FTDI\n");
- return ret;
+ goto free_and_return;
}
/*
@@ -742,14 +764,14 @@ static int ftdi_send_special_waveform(struct ftdi_context *ftdi, uint64_t *wave)
ret = ftdi_set_baudrate(ftdi, 160000);
if (ret) {
fprintf(stderr, "failed to set bitbang clock\n");
- return ret;
+ goto free_and_return;
}
/* Enable asynchronous bit-bang mode */
ret = ftdi_set_bitmode(ftdi, 0xFF, BITMODE_BITBANG);
if (ret) {
fprintf(stderr, "failed to set bitbang mode\n");
- return ret;
+ goto free_and_return;
}
/* do usb special waveform */
@@ -779,34 +801,33 @@ static int ftdi_send_special_waveform(struct ftdi_context *ftdi, uint64_t *wave)
/* clean everything to go back to regular I2C communication */
ftdi_usb_purge_buffers(ftdi);
ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET);
- config_i2c(ftdi);
+ ftdi_config_i2c(ftdi);
ftdi_write_data(ftdi, release_lines, sizeof(release_lines));
+ free_and_return:
+ free(wave);
return ret;
}
static int send_special_waveform(struct common_hnd *chnd)
{
int ret;
- uint64_t *wave;
int iterations;
- if (chnd->iftype == FTDI_IF)
- wave = malloc(SPECIAL_BUFFER_SIZE);
- else
- wave = NULL;
+ if (!chnd->conf.i2c_if->send_special_waveform) {
+ fprintf(stderr, "This binary does not support sending the ITE "
+ "special waveform with the chosen I2C interface.\n");
+ return -1;
+ }
+ /* Is this printed log line accurate here? Is this FTDI-specific? */
printf("Waiting for the EC power-on sequence ...");
fflush(stdout);
iterations = 0;
do {
- if (chnd->iftype == FTDI_IF)
- ret = ftdi_send_special_waveform(chnd->ftdi_hnd, wave);
- else
- ret = ccd_trigger_special_waveform(&chnd->uep);
-
+ ret = chnd->conf.i2c_if->send_special_waveform(chnd);
if (ret)
break;
@@ -818,7 +839,7 @@ static int send_special_waveform(struct common_hnd *chnd)
spi_flash_follow_mode_exit(chnd, "exit follow mode");
/*
* If we can talk to chip, then we can break the retry
- * loop
+ * loop.
*/
ret = check_chipid(chnd);
@@ -831,7 +852,7 @@ static int send_special_waveform(struct common_hnd *chnd)
ret = -1;
if (!(iterations % 10))
printf("!please reset EC if flashing sequence"
- " is not starting!\n");
+ " is not starting!\n");
}
} while (ret && (iterations++ < 10));
@@ -841,8 +862,6 @@ static int send_special_waveform(struct common_hnd *chnd)
else
printf(" Done.\n");
- if (wave)
- free(wave);
return ret;
}
@@ -912,6 +931,7 @@ static int command_write_pages(struct common_hnd *chnd, uint32_t address,
uint32_t size, uint8_t *buffer)
{
int res = -EIO;
+ int block_write_size = chnd->conf.i2c_if->block_write_size;
uint32_t remaining = size;
int cnt;
uint8_t addr_H, addr_M, addr_L;
@@ -921,8 +941,8 @@ static int command_write_pages(struct common_hnd *chnd, uint32_t address,
goto failed_write;
while (remaining) {
- cnt = (remaining > block_write_size()) ?
- block_write_size() : remaining;
+ cnt = (remaining > block_write_size) ?
+ block_write_size : remaining;
addr_H = (address >> 16) & 0xFF;
addr_M = (address >> 8) & 0xFF;
addr_L = (address) & 0xFF;
@@ -957,7 +977,7 @@ static int command_write_pages(struct common_hnd *chnd, uint32_t address,
if (spi_poll_busy(chnd, "AAI write") < 0)
goto failed_write;
- /* Write up to block_write_size() data */
+ /* Write up to block_write_size data */
res = i2c_write_byte(chnd, 0x10, 0x20);
res = i2c_byte_transfer(chnd, I2C_BLOCK_ADDR, buffer, 1, cnt);
buffer += cnt;
@@ -1007,7 +1027,8 @@ failed_write:
* original ITE 8903 Download board.
*/
static int command_write_pages2(struct common_hnd *chnd, uint32_t address,
- uint32_t size, uint8_t *buffer)
+ uint32_t size, uint8_t *buffer,
+ int block_write_size)
{
int res = 0;
uint8_t BA, A1, A0, data;
@@ -1064,8 +1085,8 @@ static int command_write_pages2(struct common_hnd *chnd, uint32_t address,
goto failed_write;
res = i2c_write_byte(chnd, 0x10, 0x20);
- res = i2c_byte_transfer(chnd, I2C_BLOCK_ADDR,
- buffer, 1, block_write_size()-2);
+ res = i2c_byte_transfer(chnd, I2C_BLOCK_ADDR, buffer, 1,
+ block_write_size-2);
/* No error so far */
res = size;
@@ -1096,7 +1117,7 @@ static int command_erase(struct common_hnd *chnd, uint32_t len, uint32_t off)
printf("Erasing chip...\n");
- if (off != 0 || len != flash_size) {
+ if (off != 0 || len != chnd->flash_size) {
fprintf(stderr, "Only full chip erase is supported\n");
return -EINVAL;
}
@@ -1115,7 +1136,7 @@ static int command_erase(struct common_hnd *chnd, uint32_t len, uint32_t off)
goto failed_erase;
/* do chip erase */
- if (remaining == flash_size) {
+ if (remaining == chnd->flash_size) {
if (spi_flash_command_short(chnd, SPI_CMD_CHIP_ERASE,
"chip erase") < 0)
goto failed_erase;
@@ -1138,7 +1159,7 @@ wait_busy_cleared:
"write disable for erase") < 0)
goto failed_erase;
- if (remaining == flash_size) {
+ if (remaining == chnd->flash_size) {
remaining = 0;
draw_spinner(remaining, len);
} else {
@@ -1184,7 +1205,7 @@ static int command_erase2(struct common_hnd *chnd, uint32_t len,
printf("Erasing flash...erase size=%d\n", len);
- if (off != 0 || len != flash_size) {
+ if (off != 0 || len != chnd->flash_size) {
fprintf(stderr, "Only full chip erase is supported\n");
return -EINVAL;
}
@@ -1265,7 +1286,7 @@ static int read_flash(struct common_hnd *chnd, const char *filename,
}
if (!size)
- size = flash_size;
+ size = chnd->flash_size;
printf("Reading %d bytes at 0x%08x\n", size, offset);
res = command_read_pages(chnd, offset, size, buffer);
if (res > 0) {
@@ -1285,7 +1306,7 @@ static int write_flash(struct common_hnd *chnd, const char *filename,
{
int res, written;
FILE *hnd;
- int size = flash_size;
+ int size = chnd->flash_size;
uint8_t *buffer = malloc(size);
if (!buffer) {
@@ -1331,8 +1352,9 @@ static int write_flash2(struct common_hnd *chnd, const char *filename,
uint32_t offset)
{
int res, written;
+ int block_write_size = chnd->conf.i2c_if->block_write_size;
FILE *hnd;
- int size = flash_size;
+ int size = chnd->flash_size;
int cnt;
uint8_t *buffer = malloc(size);
@@ -1359,10 +1381,9 @@ static int write_flash2(struct common_hnd *chnd, const char *filename,
offset = 0;
printf("Writing %d bytes at 0x%08x.......\n", res, offset);
while (res) {
- cnt = (res > block_write_size()) ?
- block_write_size() : res;
+ cnt = (res > block_write_size) ? block_write_size : res;
written = command_write_pages2(chnd, offset, cnt,
- &buffer[offset]);
+ &buffer[offset], block_write_size);
if (written == -EIO)
goto failed_write;
@@ -1390,11 +1411,11 @@ static int verify_flash(struct common_hnd *chnd, const char *filename,
int res;
int file_size;
FILE *hnd;
- uint8_t *buffer = malloc(flash_size);
- uint8_t *buffer2 = malloc(flash_size);
+ uint8_t *buffer = malloc(chnd->flash_size);
+ uint8_t *buffer2 = malloc(chnd->flash_size);
if (!buffer || !buffer2) {
- fprintf(stderr, "Cannot allocate %d bytes\n", flash_size);
+ fprintf(stderr, "Cannot allocate %d bytes\n", chnd->flash_size);
free(buffer);
free(buffer2);
return -ENOMEM;
@@ -1407,7 +1428,7 @@ static int verify_flash(struct common_hnd *chnd, const char *filename,
goto exit;
}
- file_size = fread(buffer, 1, flash_size, hnd);
+ file_size = fread(buffer, 1, chnd->flash_size, hnd);
fclose(hnd);
if (file_size <= 0) {
fprintf(stderr, "Cannot read %s\n", filename);
@@ -1416,7 +1437,7 @@ static int verify_flash(struct common_hnd *chnd, const char *filename,
}
printf("Verify %d bytes at 0x%08x\n", file_size, offset);
- res = command_read_pages(chnd, offset, flash_size, buffer2);
+ res = command_read_pages(chnd, offset, chnd->flash_size, buffer2);
if (res > 0)
res = memcmp(buffer, buffer2, file_size);
@@ -1429,7 +1450,7 @@ exit:
}
static struct ftdi_context *open_ftdi_device(int vid, int pid,
- int interface, char *serial)
+ int interface, const char *serial)
{
struct ftdi_context *ftdi;
int ret;
@@ -1459,14 +1480,88 @@ open_failed:
return NULL;
}
+static int ccd_i2c_interface_init(struct common_hnd *chnd)
+{
+ int ret;
+ chnd->conf.usb_vid = CR50_USB_VID;
+ chnd->conf.usb_pid = CR50_USB_PID;
+ ret = usb_findit(chnd->conf.usb_vid, chnd->conf.usb_pid,
+ CR50_I2C_SUBCLASS, CR50_I2C_PROTOCOL, &chnd->uep);
+ if (ret < 0) {
+ fprintf(stderr, "%s: usb_findit() returned %d error", __func__,
+ ret);
+ return ret;
+ }
+ printf("Using CCD device%s\n",
+ chnd->conf.usb_serial ? ", ignoring serial number" : "");
+ return 0;
+}
+
+static int ccd_i2c_interface_shutdown(struct common_hnd *chnd)
+{
+ usb_shut_down(&chnd->uep);
+ return 0;
+}
+
+static int ftdi_i2c_interface_init(struct common_hnd *chnd)
+{
+ chnd->ftdi_hnd = open_ftdi_device(chnd->conf.usb_vid,
+ chnd->conf.usb_pid, chnd->conf.usb_interface,
+ chnd->conf.usb_serial);
+ if (chnd->ftdi_hnd == NULL)
+ return -1;
+ return 0;
+}
+
+static int ftdi_i2c_interface_post_waveform(struct common_hnd *chnd)
+{
+ int ret;
+
+ ret = ftdi_config_i2c(chnd->ftdi_hnd);
+ if (ret < 0)
+ return ret;
+
+ ret = check_chipid(chnd);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Close the FTDI USB handle */
+static int ftdi_i2c_interface_shutdown(struct common_hnd *chnd)
+{
+ ftdi_usb_close(chnd->ftdi_hnd);
+ ftdi_free(chnd->ftdi_hnd);
+ return 0;
+}
+
+static const struct i2c_interface ccd_i2c_interface = {
+ .interface_init = ccd_i2c_interface_init,
+ .interface_shutdown = ccd_i2c_interface_shutdown,
+ .send_special_waveform = ccd_trigger_special_waveform,
+ .byte_transfer = ccd_i2c_byte_transfer,
+ .block_write_size = PAGE_SIZE,
+};
+
+static const struct i2c_interface ftdi_i2c_interface = {
+ .interface_init = ftdi_i2c_interface_init,
+ .interface_post_waveform = ftdi_i2c_interface_post_waveform,
+ .interface_shutdown = ftdi_i2c_interface_shutdown,
+ .send_special_waveform = ftdi_send_special_waveform,
+ .byte_transfer = ftdi_i2c_byte_transfer,
+ .block_write_size = FTDI_BLOCK_WRITE_SIZE,
+};
+
static const struct option longopts[] = {
- {"ccd", 0, 0, 'c'},
{"debug", 0, 0, 'd'},
{"erase", 0, 0, 'e'},
{"help", 0, 0, 'h'},
+ {"i2c-interface", 1, 0, 'c'},
{"interface", 1, 0, 'i'},
{"product", 1, 0, 'p'},
{"read", 1, 0, 'r'},
+ {"send-waveform", 1, 0, 'W'},
{"serial", 1, 0, 's'},
{"unprotect", 0, 0, 'u'},
{"vendor", 1, 0, 'v'},
@@ -1476,12 +1571,13 @@ static const struct option longopts[] = {
static void display_usage(char *program)
{
- fprintf(stderr, "Usage: %s [-c] [-d] [-v <VID>] [-p <PID>] [-i <1|2>] "
- "[-s <serial>] [-u] [-e] [-r <file>] [-w <file>]\n", program);
- fprintf(stderr, "--c[cd] : use CCD interface instead of FTDI, make "
- "sure this option is included before -p and or -v\n");
+ fprintf(stderr, "Usage: %s [-d] [-v <VID>] [-p <PID>] "
+ "[-c <ccd|ftdi>] [-i <1|2>] [-s <serial>] [-u] [-e] "
+ "[-r <file>] [-W <0|1|false|true>] [-w <file>]\n", program);
fprintf(stderr, "--d[ebug] : output debug traces\n");
fprintf(stderr, "--e[rase] : erase all the flash content\n");
+ fprintf(stderr, "-c, --i2c_interface <ccd|ftdi> : I2C interface "
+ "to use\n");
fprintf(stderr, "--i[interface] <1> : FTDI interface: A=1, B=2, ...\n");
fprintf(stderr, "--p[roduct] <0x1234> : USB product ID\n");
fprintf(stderr, "--r[ead] <file> : read the flash content and "
@@ -1489,66 +1585,88 @@ static void display_usage(char *program)
fprintf(stderr, "--s[erial] <serialname> : USB serial string\n");
fprintf(stderr, "--u[nprotect] : remove flash write protect\n");
fprintf(stderr, "--v[endor] <0x1234> : USB vendor ID\n");
+ fprintf(stderr, "-W, --send-waveform <0|1|false|true> : Send the "
+ "specal waveform? Default is false, subject to change."
+ " Set to false if ITE direct firmware update mode has "
+ "already been enabled.\n");
fprintf(stderr, "--w[rite] <file> : read <file> and "
"write it to flash\n");
exit(2);
}
-static int parse_parameters(int argc, char **argv)
+static int parse_parameters(int argc, char **argv, struct iteflash_config *conf)
{
int opt, idx;
- int flags = 0;
- while ((opt = getopt_long(argc, argv, "?cdehi:p:r:s:uv:w:",
+ while ((opt = getopt_long(argc, argv, "?dehc:i:p:r:s:uv:W:w:",
longopts, &idx)) != -1) {
switch (opt) {
case 'c':
- flags |= FLAG_CCD_MODE;
- usb_vid = CR50_USB_VID;
- usb_pid = CR50_USB_PID;
- block_write_size_ = PAGE_SIZE;
+ if (!strcasecmp(optarg, "ccd")) {
+ conf->i2c_if = &ccd_i2c_interface;
+ } else if (!strcasecmp(optarg, "ftdi")) {
+ conf->i2c_if = &ftdi_i2c_interface;
+ } else {
+ fprintf(stderr, "Unexpected -c / "
+ "--i2c-interface value: %s\n", optarg);
+ return -1;
+ }
break;
case 'd':
- debug = 1;
+ conf->debug = 1;
break;
case 'e':
- flags |= FLAG_ERASE;
+ conf->erase = 1;
break;
case 'h':
case '?':
display_usage(argv[0]);
break;
case 'i':
- usb_interface = atoi(optarg);
+ conf->usb_interface = atoi(optarg);
break;
case 'p':
- usb_pid = strtol(optarg, NULL, 16);
+ conf->usb_pid = strtol(optarg, NULL, 16);
break;
case 'r':
- input_filename = optarg;
+ conf->input_filename = optarg;
break;
case 's':
- usb_serial = optarg;
+ conf->usb_serial = optarg;
break;
case 'u':
- flags |= FLAG_UNPROTECT;
+ conf->unprotect = 1;
break;
case 'v':
- usb_vid = strtol(optarg, NULL, 16);
+ conf->usb_vid = strtol(optarg, NULL, 16);
+ break;
+ case 'W':
+ if (!strcmp(optarg, "0") ||
+ !strcasecmp(optarg, "false")) {
+ conf->send_waveform = 0;
+ } else if (!strcmp(optarg, "1") ||
+ !strcasecmp(optarg, "true")) {
+ conf->send_waveform = 1;
+ } else {
+ fprintf(stderr, "Unexpected -W / "
+ "--special-waveform value: %s\n",
+ optarg);
+ return -1;
+ }
break;
case 'w':
- output_filename = optarg;
+ conf->output_filename = optarg;
break;
}
}
- return flags;
+ return 0;
}
static void sighandler(int signum)
{
printf("\nCaught signal %d: %s\nExiting...\n",
signum, sys_siglist[signum]);
- ++exit_requested;
+ exit_requested = 1;
}
static void register_sigaction(void)
@@ -1565,70 +1683,75 @@ static void register_sigaction(void)
int main(int argc, char **argv)
{
- struct common_hnd chnd;
- int ret = 1;
- int flags;
+ int ret = 1, other_ret;
+ struct common_hnd chnd = {
+ /* Default flag settings. */
+ .conf = {
+ .usb_interface = SERVO_INTERFACE,
+ .usb_vid = SERVO_USB_VID,
+ .usb_pid = SERVO_USB_PID,
+ .i2c_if = &ftdi_i2c_interface,
+ },
+ };
/* Parse command line options */
- flags = parse_parameters(argc, argv);
+ if (parse_parameters(argc, argv, &chnd.conf) < 0)
+ return ret;
/* Open the communications channel. */
- memset(&chnd, 0, sizeof(chnd));
- if (flags & FLAG_CCD_MODE) {
- usb_findit(usb_vid, usb_pid, CR50_I2C_SUBCLASS,
- CR50_I2C_PROTOCOL, &chnd.uep);
- chnd.iftype = CCD_IF;
- printf("Using CCD device%s\n",
- usb_serial ? ", ignoring serial number" : "");
- } else {
- chnd.ftdi_hnd = open_ftdi_device(usb_vid, usb_pid,
- usb_interface, usb_serial);
- if (chnd.ftdi_hnd == NULL)
- return 1;
- chnd.iftype = FTDI_IF;
- }
+ if (chnd.conf.i2c_if->interface_init &&
+ chnd.conf.i2c_if->interface_init(&chnd))
+ return ret;
- /* Register signal handler after opening USB handle. */
+ /* Register signal handler after opening the communications channel. */
register_sigaction();
/* Trigger embedded monitor detection */
- if (send_special_waveform(&chnd) < 0)
- goto terminate;
-
- if (chnd.iftype == FTDI_IF) {
- if (config_i2c(chnd.ftdi_hnd) < 0)
+ if (chnd.conf.send_waveform) {
+ if (send_special_waveform(&chnd))
goto terminate;
- if (check_chipid(&chnd) < 0)
+ } else {
+ ret = check_chipid(&chnd);
+ if (ret) {
+ fprintf(stderr, "Failed to get ITE chip ID. This "
+ "could be because the ITE direct firmware "
+ "update (DFU) mode is not enabled.\n");
goto terminate;
+ }
}
- if (flags & FLAG_UNPROTECT)
+ if (chnd.conf.i2c_if->interface_post_waveform &&
+ chnd.conf.i2c_if->interface_post_waveform(&chnd))
+ goto terminate;
+
+ if (chnd.conf.unprotect)
command_write_unprotect(&chnd);
- if (input_filename) {
- ret = read_flash(&chnd, input_filename, 0, flash_size);
+ if (chnd.conf.input_filename) {
+ ret = read_flash(&chnd, chnd.conf.input_filename, 0,
+ chnd.flash_size);
if (ret)
goto terminate;
}
- if (flags & FLAG_ERASE) {
- if (is8320dx)
+ if (chnd.conf.erase) {
+ if (chnd.is8320dx)
/* Do Normal Erase Function */
- command_erase2(&chnd, flash_size, 0, 0);
+ command_erase2(&chnd, chnd.flash_size, 0, 0);
else
- command_erase(&chnd, flash_size, 0);
+ command_erase(&chnd, chnd.flash_size, 0);
/* Call DBGR Rest to clear the EC lock status after erasing */
dbgr_reset(&chnd, RSTS_VCCDO_PW_ON|RSTS_HGRST|RSTS_GRST);
}
- if (output_filename) {
- if (is8320dx)
- ret = write_flash2(&chnd, output_filename, 0);
+ if (chnd.conf.output_filename) {
+ if (chnd.is8320dx)
+ ret = write_flash2(&chnd, chnd.conf.output_filename, 0);
else
- ret = write_flash(&chnd, output_filename, 0);
+ ret = write_flash(&chnd, chnd.conf.output_filename, 0);
if (ret)
goto terminate;
- ret = verify_flash(&chnd, output_filename, 0);
+ ret = verify_flash(&chnd, chnd.conf.output_filename, 0);
if (ret)
goto terminate;
}
@@ -1640,10 +1763,10 @@ terminate:
/* Enable EC Host Global Reset to reset EC resource and EC domain. */
dbgr_reset(&chnd, RSTS_VCCDO_PW_ON|RSTS_HGRST|RSTS_GRST);
- /* Close the FTDI USB handle */
- if (chnd.iftype == FTDI_IF) {
- ftdi_usb_close(chnd.ftdi_hnd);
- ftdi_free(chnd.ftdi_hnd);
+ if (chnd.conf.i2c_if->interface_shutdown) {
+ other_ret = chnd.conf.i2c_if->interface_shutdown(&chnd);
+ if (!ret && other_ret)
+ ret = other_ret;
}
return ret;