summaryrefslogtreecommitdiff
path: root/util/iteflash.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /util/iteflash.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14588.123.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'util/iteflash.c')
-rw-r--r--util/iteflash.c2445
1 files changed, 0 insertions, 2445 deletions
diff --git a/util/iteflash.c b/util/iteflash.c
deleted file mode 100644
index a4a166d3d8..0000000000
--- a/util/iteflash.c
+++ /dev/null
@@ -1,2445 +0,0 @@
-/* Copyright 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * ITE83xx SoC in-system programming tool
- */
-
-/* remove when ftdi_usb_purge_buffers has been replaced to follow libftdi */
-#define _FTDI_DISABLE_DEPRECATED
-
-#include <errno.h>
-#include <fcntl.h>
-#include <ftdi.h>
-#include <getopt.h>
-#include <linux/i2c-dev.h>
-#include <linux/i2c.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include "compile_time_macros.h"
-#include "usb_if.h"
-
-/* Default FTDI device : Servo v2. */
-#define SERVO_USB_VID 0x18d1
-#define SERVO_USB_PID 0x5002
-#define SERVO_INTERFACE INTERFACE_B
-
-/* Default CCD device: Cr50. */
-#define CR50_USB_VID 0x18d1
-#define CR50_USB_PID 0x5014
-
-/* Cr50 exposed properties of the USB I2C endpoint. */
-#define CR50_I2C_SUBCLASS 82
-#define CR50_I2C_PROTOCOL 1
-
-#define CROS_CMD_ADDR 0x78 /* USB_I2C_CMD_ADDR 0xF0 >> 1 */
-#define CROS_CMD_ITE_SYNC 0
-
-/* DBGR I2C addresses */
-#define I2C_CMD_ADDR 0x5A
-#define I2C_DATA_ADDR 0x35
-#define I2C_BLOCK_ADDR 0x79
-
-#define FTDI_I2C_FREQ 400000
-
-/* I2C pins on the FTDI interface */
-#define SCL_BIT BIT(0)
-#define SDA_BIT BIT(1)
-
-/* Chip ID register value */
-#define CHIP_ID 0x8380
-
-/* Embedded flash page size */
-#define PAGE_SIZE (1<<8)
-
-/* Embedded flash block write size for different programming modes. */
-#define FTDI_BLOCK_WRITE_SIZE (1<<16)
-
-/* JEDEC SPI Flash commands */
-#define SPI_CMD_PAGE_PROGRAM 0x02
-#define SPI_CMD_WRITE_DISABLE 0x04
-#define SPI_CMD_READ_STATUS 0x05
-#define SPI_CMD_WRITE_ENABLE 0x06
-#define SPI_CMD_FAST_READ 0x0B
-#define SPI_CMD_CHIP_ERASE 0x60
-#define SPI_CMD_SECTOR_ERASE_1K 0xD7
-#define SPI_CMD_SECTOR_ERASE_4K 0x20
-#define SPI_CMD_WORD_PROGRAM 0xAD
-#define SPI_CMD_EWSR 0x50 /* Enable Write Status Register */
-#define SPI_CMD_WRSR 0x01 /* Write Status Register */
-#define SPI_CMD_RDID 0x9F /* Read Flash ID */
-
-/* Size for FTDI outgoing buffer */
-#define FTDI_CMD_BUF_SIZE (1<<12)
-
-/* Reset Status */
-#define RSTS_VCCDO_PW_ON 0x40
-#define RSTS_VFSPIPG 0x20
-#define RSTS_HGRST 0x08
-#define RSTS_GRST 0x04
-
-/* I2C MUX Configuration: TCA9543 or PCA9546 */
-#define I2C_MUX_CMD_ADDR 0x70
-#define I2C_MUX_CMD_NONE 0x00
-#define I2C_MUX_CMD_INAS 0x01
-#define I2C_MUX_CMD_EC 0x02
-
-/* Eflash Type*/
-#define EFLASH_TYPE_8315 0x01
-#define EFLASH_TYPE_KGD 0x02
-#define EFLASH_TYPE_NONE 0xFF
-
-uint8_t eflash_type;
-uint8_t spi_cmd_sector_erase;
-
-/* Embedded flash number of pages in a sector erase */
-uint8_t sector_erase_pages;
-
-
-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 {
- char *input_filename;
- char *output_filename;
- int send_waveform; /* boolean */
- int erase; /* boolean */
- int i2c_mux; /* boolean */
- int debug; /* boolean */
- int disable_watchdog; /* boolean */
- int disable_protect_path; /* boolean */
- int block_write_size;
- int usb_interface;
- int usb_vid;
- int usb_pid;
- int verify; /* boolean */
- char *usb_serial;
- char *i2c_dev_path;
- const struct i2c_interface *i2c_if;
- size_t range_base;
- size_t range_size;
-};
-
-struct common_hnd {
- struct iteflash_config conf;
- int flash_size;
- int flash_cmd_v2; /* boolean */
- int dbgr_addr_3bytes; /* boolean */
- union {
- int i2c_dev_fd;
- struct usb_endpoint uep;
- struct ftdi_context *ftdi_hnd;
- };
-};
-
-struct cmds {
- uint8_t addr;
- uint8_t cmd;
-};
-
-/* 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 default_block_write_size;
-};
-
-static int spi_flash_command_short(struct common_hnd *chnd,
- uint8_t cmd, char *desc);
-
-static void null_and_free(void **ptr)
-{
- void *holder;
-
- if (*ptr) {
- holder = *ptr;
- *ptr = NULL;
- free(holder);
- }
-}
-
-/* This releases any memory owned by *conf. This does NOT free conf itself! */
-/* Not all pointers in conf necessarily point to memory owned by it. */
-static void config_release(struct iteflash_config *conf)
-{
- null_and_free((void **)&conf->input_filename);
- null_and_free((void **)&conf->output_filename);
- null_and_free((void **)&conf->usb_serial);
- null_and_free((void **)&conf->i2c_dev_path);
-}
-
-/* number of bytes to send consecutively before checking for ACKs */
-#define FTDI_TX_BUFFER_LIMIT 32
-
-static inline int i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
- uint8_t *data, int write, int numbytes)
-{
- /* If we got a termination signal, stop sending data */
- if (exit_requested)
- return -1;
-
- return chnd->conf.i2c_if->byte_transfer(chnd, addr, data, write,
- numbytes);
-}
-
-static int linux_i2c_byte_transfer(struct common_hnd *chnd, uint8_t addr,
- uint8_t *data, int write, int numbytes)
-{
- static const int nmsgs = 1;
- int ret, extra_int;
- struct i2c_msg i2cmsg = {};
- struct i2c_rdwr_ioctl_data msgset = {};
-
- i2cmsg.addr = addr;
- if (!write)
- i2cmsg.flags |= I2C_M_RD;
- i2cmsg.buf = data;
- i2cmsg.len = numbytes;
-
- msgset.msgs = &i2cmsg;
- msgset.nmsgs = nmsgs;
-
- ret = ioctl(chnd->i2c_dev_fd, I2C_RDWR, &msgset);
- if (ret < 0) {
- extra_int = errno;
- fprintf(stderr, "%s: ioctl() failed with return value %d and "
- "errno %d\n", __func__, ret, extra_int);
- if (ret == -1 && extra_int)
- ret = -abs(extra_int);
- } else if (ret < nmsgs) {
- fprintf(stderr, "%s: failed to send %d of %d I2C messages\n",
- __func__, (nmsgs - ret), nmsgs);
- ret = -1;
- } else {
- ret = 0;
- }
- return ret;
-}
-
-static int i2c_add_send_byte(struct ftdi_context *ftdi, uint8_t *buf,
- 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[FTDI_TX_BUFFER_LIMIT];
- uint8_t *b = ptr;
- uint8_t failed_ack = 0;
-
- for (i = 0; i < tcnt; i++) {
- /* WORKAROUND: force SDA before sending the next byte */
- *b++ = SET_BITS_LOW; *b++ = SDA_BIT; *b++ = SCL_BIT | SDA_BIT;
- /* write byte */
- *b++ = MPSSE_DO_WRITE | MPSSE_BITMODE | MPSSE_WRITE_NEG;
- *b++ = 0x07; *b++ = *tbuf++;
- /* prepare for ACK */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT;
- /* read ACK */
- *b++ = MPSSE_DO_READ | MPSSE_BITMODE | MPSSE_LSB;
- *b++ = 0;
- *b++ = SEND_IMMEDIATE;
-
- tx_buffered++;
-
- /*
- * On the last byte, or every FTDI_TX_BUFFER_LIMIT bytes, read
- * the ACK bits.
- */
- if (i == tcnt-1 || (tx_buffered == FTDI_TX_BUFFER_LIMIT)) {
- /* write data */
- ret = ftdi_write_data(ftdi, buf, b - buf);
- if (ret < 0) {
- fprintf(stderr, "failed to write byte\n");
- return ret;
- }
-
- /* read ACK bits */
- remaining_data = tx_buffered;
- ack_idx = 0;
- do {
- ret = ftdi_read_data(ftdi, &ack[ack_idx],
- remaining_data);
- if (ret < 0) {
- fprintf(stderr, "read ACK failed\n");
- return ret;
- }
- remaining_data -= ret;
- ack_idx += ret;
- } while (remaining_data);
- for (j = 0; j < tx_buffered; j++) {
- if ((ack[j] & 0x80) != 0)
- failed_ack = ack[j];
- }
-
- /* check ACK bits */
- if (ret < 0 || failed_ack) {
- if (debug)
- fprintf(stderr,
- "write ACK fail: %d, 0x%02x\n",
- ret, failed_ack);
- return -ENXIO;
- }
-
- /* reset for next set of transactions */
- b = ptr;
- tx_buffered = 0;
- }
- }
- return 0;
-}
-
-static int i2c_add_recv_bytes(struct ftdi_context *ftdi, uint8_t *buf,
- uint8_t *ptr, uint8_t *rbuf, int rcnt)
-{
- int ret, i, rbuf_idx;
- uint8_t *b = ptr;
-
- for (i = 0; i < rcnt; i++) {
- /* set SCL low */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT;
- /* read the byte on the wire */
- *b++ = MPSSE_DO_READ; *b++ = 0; *b++ = 0;
-
- if (i == rcnt - 1) {
- /* NACK last byte */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT;
- *b++ = MPSSE_DO_WRITE | MPSSE_BITMODE | MPSSE_WRITE_NEG;
- *b++ = 0; *b++ = 0xff; *b++ = SEND_IMMEDIATE;
- } else {
- /* ACK all other bytes */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT | SDA_BIT;
- *b++ = MPSSE_DO_WRITE | MPSSE_BITMODE | MPSSE_WRITE_NEG;
- *b++ = 0; *b++ = 0; *b++ = SEND_IMMEDIATE;
- }
- }
-
- ret = ftdi_write_data(ftdi, buf, b - buf);
- if (ret < 0) {
- fprintf(stderr, "failed to prepare read\n");
- return ret;
- }
-
- rbuf_idx = 0;
- do {
- ret = ftdi_read_data(ftdi, &rbuf[rbuf_idx], rcnt);
- if (ret < 0) {
- fprintf(stderr, "read byte failed\n");
- break;
- }
- rcnt -= ret;
- rbuf_idx += ret;
- } while (rcnt);
-
- return ret;
-}
-
-#define USB_I2C_HEADER_SIZE 4
-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 +
- (((!write * numbytes) > 0x7f) ? 2 : 0)];
- size_t response_size;
- size_t extra = 0;
-
- /*
- * Build a message following format described in ./include/usb_i2c.h.
- *
- * Hardcode port, the lowest 4 bits of the first byte, to 0; may need
- * to make this a command line option.
- */
- usb_buffer[0] = 0;
-
- usb_buffer[1] = addr;
- if (write) {
- /*
- * Write count might spill over into the top 4 bits of the
- * first byte. We trust the caller not to pass numbytes
- * exceeding (2^12 - 1).
- */
- if (numbytes > 255)
- usb_buffer[0] |= (numbytes >> 4) & 0xf0;
- usb_buffer[2] = numbytes & 0xff;
- usb_buffer[3] = 0;
- memcpy(usb_buffer + USB_I2C_HEADER_SIZE, data, numbytes);
- } else {
- usb_buffer[2] = 0;
- if (numbytes < 0x80) {
- usb_buffer[3] = numbytes;
- } else {
- usb_buffer[3] = (numbytes & 0x7f) | 0x80;
- usb_buffer[4] = numbytes >> 7;
- usb_buffer[5] = 0;
- extra = 2;
- }
- }
-
- response_size = 0;
- usb_trx(&chnd->uep, usb_buffer,
- write ? sizeof(usb_buffer) : USB_I2C_HEADER_SIZE + extra,
- usb_buffer, sizeof(usb_buffer), 1, &response_size);
-
- if (response_size < (USB_I2C_HEADER_SIZE + (write ? 0 : numbytes))) {
- fprintf(stderr, "%s: got too few bytes (%zd) in response\n",
- __func__, response_size);
- return -1;
- }
-
- if (usb_buffer[0]) {
- uint32_t rv;
-
- /*
- * Error is reported as a 16 bit value in little endian byte
- * order.
- */
- rv = usb_buffer[1];
- rv = (rv << 8) + usb_buffer[0];
-
- fprintf(stderr, "%s: usb i2c error %d\n",
- __func__,
- (((uint16_t)usb_buffer[1]) << 8) + usb_buffer[0]);
-
- return -rv;
- }
-
- if (!write)
- memcpy(data, usb_buffer + USB_I2C_HEADER_SIZE, numbytes);
-
- return 0;
-}
-
-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];
- uint8_t *b;
- uint8_t slave_addr;
- struct ftdi_context *ftdi;
-
- ret = 0;
- b = buf;
- ftdi = chnd->ftdi_hnd;
-
- /* START condition */
- /* SCL & SDA high */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = 0;
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = 0;
- /* SCL high, SDA low */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SDA_BIT;
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SDA_BIT;
- /* SCL low, SDA low */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT | SDA_BIT;
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SCL_BIT | SDA_BIT;
-
- /* send address */
- slave_addr = (addr << 1) | (write ? 0 : 1);
- ret = i2c_add_send_byte(ftdi, buf, b, &slave_addr, 1, chnd->conf.debug);
- if (ret < 0) {
- if (chnd->conf.debug)
- fprintf(stderr, "address %02x failed\n", addr);
- ret = -ENXIO;
- goto exit_xfer;
- }
-
- b = buf;
- if (write) /* write data */
- 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);
-
-exit_xfer:
- b = buf;
- /* STOP condition */
- /* SCL high, SDA low */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SDA_BIT;
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = SDA_BIT;
- /* SCL high, SDA high */
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = 0;
- *b++ = SET_BITS_LOW; *b++ = 0; *b++ = 0;
-
- rets = ftdi_write_data(ftdi, buf, b - buf);
- if (rets < 0)
- fprintf(stderr, "failed to send STOP\n");
- return ret;
-}
-
-static int i2c_write_byte(struct common_hnd *chnd, uint8_t cmd, uint8_t data)
-{
- int ret;
-
- ret = i2c_byte_transfer(chnd, I2C_CMD_ADDR, &cmd, 1, 1);
- if (ret < 0)
- return -EIO;
- ret = i2c_byte_transfer(chnd, I2C_DATA_ADDR, &data, 1, 1);
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-static int i2c_read_byte(struct common_hnd *chnd, uint8_t cmd, uint8_t *data)
-{
- int ret;
-
- ret = i2c_byte_transfer(chnd, I2C_CMD_ADDR, &cmd, 1, 1);
- if (ret < 0)
- return -EIO;
- ret = i2c_byte_transfer(chnd, I2C_DATA_ADDR, data, 0, 1);
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Configure I2C MUX to choose EC Prog channel */
-static int config_i2c_mux(struct common_hnd *chnd, uint8_t cmd)
-{
- int ret;
-
- ret = i2c_byte_transfer(chnd, I2C_MUX_CMD_ADDR, &cmd, 1, 1);
- if (ret < 0) {
- fprintf(stderr, "Failed to configure I2C MUX.");
- return -EIO;
- }
-
- return 0;
-}
-
-/* Get 3rd Byte Chip ID */
-static int get_3rd_chip_id_byte(struct common_hnd *chnd, uint8_t *chip_id)
-{
- int ret = 0;
-
- ret = i2c_write_byte(chnd, 0x80, 0xf0);
- ret |= i2c_write_byte(chnd, 0x2f, 0x20);
- ret |= i2c_write_byte(chnd, 0x2e, 0x85);
- ret |= i2c_read_byte(chnd, 0x30, chip_id);
-
- if (ret < 0)
- fprintf(stderr, "Failed to get id of 3rd byte.");
-
- return ret;
-}
-
-static int check_flashid(struct common_hnd *chnd)
-{
- int ret = 0;
- uint8_t id[16], i;
- struct cmds commands[] = {
- {0x07, 0x7f},
- {0x06, 0xff},
- {0x04, 0x00},
- {0x05, 0xfe},
- {0x08, 0x00},
- {0x05, 0xfd},
- {0x08, 0x9f}
- };
-
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- ret = i2c_write_byte(chnd, commands[i].addr, commands[i].cmd);
- if (ret) {
- fprintf(stderr, "Flash ID Failed : cmd %x ,data %x\n",
- commands[i].addr, commands[i].cmd);
- return ret;
- }
- }
-
- ret = i2c_byte_transfer(chnd, I2C_DATA_ADDR, id, 0, 16);
-
- if (ret < 0)
- fprintf(stderr, "Check Flash ID FAILED\n");
-
- if ((id[0] == 0xFF) && (id[1] == 0xFF) && (id[2] == 0xFE)) {
- printf("EFLASH TYPE = 8315\n\r");
- eflash_type = EFLASH_TYPE_8315;
- } else if ((id[0] == 0xC8) || (id[0] == 0xEF)) {
- printf("EFLASH TYPE = KGD\n\r");
- eflash_type = EFLASH_TYPE_KGD;
- } else {
- printf("Invalid EFLASH TYPE : ");
- printf("FLASH ID = %02x %02x %02x\n\r", id[0], id[1], id[2]);
- eflash_type = EFLASH_TYPE_NONE;
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* Fills in chnd->flash_size */
-static int check_chipid(struct common_hnd *chnd)
-{
- int ret;
- uint8_t ver = 0xff;
- uint32_t id = 0xffff;
- uint16_t v2[7] = {128, 192, 256, 384, 512, 0, 1024};
- /*
- * Chip Version is mapping from bit 3-0
- * Flash size is mapping from bit 7-4
- *
- * Chip Version (bit 3-0)
- * 0: AX
- * 1: BX
- * 2: CX
- * 3: DX
- *
- * CX before flash size (bit 7-4)
- * 0:128KB
- * 4:192KB
- * 8:256KB
- *
- * DX flash size(bit 7-4)
- * 0:128KB
- * 2:192KB
- * 4:256KB
- * 6:384KB
- * 8:512KB
- *
- * flash size(bit 7-4) of it8xxx1 or it8xxx2 series
- * 0:128KB
- * 4:256KB
- * 8:512KB
- * C:1024KB
- */
-
- ret = i2c_read_byte(chnd, 0x00, (uint8_t *)&id + 1);
- if (ret < 0)
- return ret;
- ret = i2c_read_byte(chnd, 0x01, (uint8_t *)&id);
- if (ret < 0)
- return ret;
- ret = i2c_read_byte(chnd, 0x02, &ver);
- if (ret < 0)
- return ret;
-
- if ((id & 0xff00) != (CHIP_ID & 0xff00)) {
- id |= 0xff0000;
- ret = get_3rd_chip_id_byte(chnd, (uint8_t *)&id+2);
- if (ret < 0)
- return ret;
-
- if ((id & 0xf000f) == 0x80001 || (id & 0xf000f) == 0x80002) {
- chnd->flash_cmd_v2 = 1;
- chnd->dbgr_addr_3bytes = 1;
- } else {
- fprintf(stderr, "Invalid chip id: %05x\n", id);
- return -EINVAL;
- }
- } else {
- chnd->dbgr_addr_3bytes = 0;
- if ((ver & 0x0f) >= 0x03)
- chnd->flash_cmd_v2 = 1;
- else
- chnd->flash_cmd_v2 = 0;
- }
- /* compute embedded flash size from CHIPVER field */
- if (chnd->flash_cmd_v2)
- chnd->flash_size = v2[(ver & 0xF0)>>5] * 1024;
- else
- chnd->flash_size = (128 + (ver & 0xF0)) * 1024;
-
- if (chnd->flash_size == 0) {
- fprintf(stderr, "Invalid Flash Size");
- return -EINVAL;
- }
-
- printf("CHIPID %05x, CHIPVER %02x, Flash size %d kB\n", id, ver,
- chnd->flash_size / 1024);
-
- return 0;
-}
-
-/* DBGR Reset */
-static int dbgr_reset(struct common_hnd *chnd, unsigned char val)
-{
- int ret = 0;
-
- /* Reset CPU only, and we keep power state until flashing is done. */
- if (chnd->dbgr_addr_3bytes)
- ret |= i2c_write_byte(chnd, 0x80, 0xf0);
-
- ret |= i2c_write_byte(chnd, 0x2f, 0x20);
- ret |= i2c_write_byte(chnd, 0x2e, 0x06);
-
- /* Enable the Reset Status by val */
- ret |= i2c_write_byte(chnd, 0x30, val);
-
- ret |= i2c_write_byte(chnd, 0x27, 0x80);
- if (ret < 0)
- fprintf(stderr, "DBGR RESET FAILED\n");
-
- return 0;
-}
-
-/* Exit DBGR mode */
-static int exit_dbgr_mode(struct common_hnd *chnd)
-{
- int ret = 0;
-
- printf("Exit DBGR mode...\n");
- if (chnd->dbgr_addr_3bytes)
- ret |= i2c_write_byte(chnd, 0x80, 0xf0);
- ret |= i2c_write_byte(chnd, 0x2f, 0x1c);
- ret |= i2c_write_byte(chnd, 0x2e, 0x08);
- ret |= i2c_write_byte(chnd, 0x30, BIT(4));
-
- if (ret < 0)
- fprintf(stderr, "EXIT DBGR MODE FAILED\n");
-
- return 0;
-}
-
-/* DBGR reset GPIOs to default */
-static int dbgr_reset_gpio(struct common_hnd *chnd)
-{
- int ret = 0;
-
- printf("Reset GPIOs to default.\n");
- if (chnd->dbgr_addr_3bytes)
- ret |= i2c_write_byte(chnd, 0x80, 0xf0);
- ret |= i2c_write_byte(chnd, 0x2f, 0x20);
- ret |= i2c_write_byte(chnd, 0x2e, 0x07);
- ret |= i2c_write_byte(chnd, 0x30, BIT(1));
-
- if (ret < 0)
- fprintf(stderr, "DBGR RESET GPIO FAILED\n");
-
- return 0;
-}
-
-/* disable watchdog */
-static int dbgr_disable_watchdog(struct common_hnd *chnd)
-{
- int ret = 0;
-
- printf("Disabling watchdog...\n");
- if (chnd->dbgr_addr_3bytes)
- ret |= i2c_write_byte(chnd, 0x80, 0xf0);
-
- ret |= i2c_write_byte(chnd, 0x2f, 0x1f);
- ret |= i2c_write_byte(chnd, 0x2e, 0x05);
- ret |= i2c_write_byte(chnd, 0x30, 0x30);
-
- if (ret < 0)
- fprintf(stderr, "DBGR DISABLE WATCHDOG FAILED!\n");
-
- return ret;
-}
-
-/* disable protect path from DBGR */
-static int dbgr_disable_protect_path(struct common_hnd *chnd)
-{
- int ret = 0, i;
-
- printf("Disabling protect path...\n");
-
- if (chnd->dbgr_addr_3bytes)
- ret |= i2c_write_byte(chnd, 0x80, 0xf0);
-
- ret |= i2c_write_byte(chnd, 0x2f, 0x20);
- for (i = 0; i < 32; i++) {
- ret |= i2c_write_byte(chnd, 0x2e, 0xa0+i);
- ret |= i2c_write_byte(chnd, 0x30, 0);
- }
-
- if (ret < 0)
- fprintf(stderr, "DISABLE PROTECT PATH FROM DBGR FAILED!\n");
-
- return ret;
-}
-
-/* Enter follow mode and FSCE# high level */
-static int spi_flash_follow_mode(struct common_hnd *chnd, char *desc)
-{
- int ret = 0;
-
- ret |= i2c_write_byte(chnd, 0x07, 0x7f);
- ret |= i2c_write_byte(chnd, 0x06, 0xff);
- ret |= i2c_write_byte(chnd, 0x05, 0xfe);
- ret |= i2c_write_byte(chnd, 0x04, 0x00);
- ret |= i2c_write_byte(chnd, 0x08, 0x00);
-
- ret = (ret ? -EIO : 0);
- if (ret < 0)
- fprintf(stderr, "Flash %s enter follow mode FAILED (%d)\n",
- desc, ret);
-
- return ret;
-}
-
-/* Exit follow mode */
-static int spi_flash_follow_mode_exit(struct common_hnd *chnd, char *desc)
-{
- int ret = 0;
-
- ret |= i2c_write_byte(chnd, 0x07, 0x00);
- ret |= i2c_write_byte(chnd, 0x06, 0x00);
-
- ret = (ret ? -EIO : 0);
- if (ret < 0)
- fprintf(stderr, "Flash %s exit follow mode FAILED (%d)\n",
- desc, ret);
-
- return ret;
-}
-
-/* Stop EC by sending follow mode command */
-static int dbgr_stop_ec(struct common_hnd *chnd)
-{
- int ret = 0;
-
- ret |= spi_flash_follow_mode(chnd, "enter follow mode");
- ret |= spi_flash_follow_mode_exit(chnd, "exit follow mode");
-
- if (ret < 0)
- fprintf(stderr, "DBGR STOP EC FAILED!\n");
-
- return ret;
-}
-
-/* SPI Flash generic command, short version */
-static int spi_flash_command_short(struct common_hnd *chnd,
- uint8_t cmd, char *desc)
-{
- int ret = 0;
-
- ret |= i2c_write_byte(chnd, 0x05, 0xfe);
- ret |= i2c_write_byte(chnd, 0x08, 0x00);
- ret |= i2c_write_byte(chnd, 0x05, 0xfd);
- ret |= i2c_write_byte(chnd, 0x08, cmd);
-
- ret = (ret ? -EIO : 0);
- if (ret < 0)
- fprintf(stderr, "Flash CMD %s FAILED (%d)\n", desc, ret);
-
- return ret;
-}
-
-/* SPI Flash set erase page */
-static int spi_flash_set_erase_page(struct common_hnd *chnd,
- int page, char *desc)
-{
- int ret = 0;
-
- ret |= i2c_write_byte(chnd, 0x08, page >> 8);
- ret |= i2c_write_byte(chnd, 0x08, page & 0xff);
- ret |= i2c_write_byte(chnd, 0x08, 0);
-
- ret = (ret ? -EIO : 0);
- if (ret < 0)
- fprintf(stderr, "Flash %s set page FAILED (%d)\n", desc, ret);
-
- return ret;
-}
-
-/* Poll SPI Flash Read Status register until BUSY is reset */
-static int spi_poll_busy(struct common_hnd *chnd, char *desc)
-{
- uint8_t reg = 0xff;
- int ret = -EIO;
-
- if (spi_flash_command_short(chnd, SPI_CMD_READ_STATUS,
- "read status for busy bit") < 0) {
- fprintf(stderr, "Flash %s wait busy cleared FAILED\n", desc);
- goto failed_read_status;
- }
-
- while (1) {
- if (i2c_byte_transfer(chnd, I2C_DATA_ADDR, &reg, 0, 1) < 0) {
- fprintf(stderr, "Flash polling busy cleared FAILED\n");
- break;
- }
-
- if ((reg & 0x01) == 0) {
- /* busy bit cleared */
- ret = 0;
- break;
- }
- }
-failed_read_status:
- return ret;
-}
-
-static int spi_check_write_enable(struct common_hnd *chnd, char *desc)
-{
- uint8_t reg = 0xff;
- int ret = -EIO;
-
- if (spi_flash_command_short(chnd, SPI_CMD_READ_STATUS,
- "read status for write enable bit") < 0) {
- fprintf(stderr, "Flash %s wait WE FAILED\n", desc);
- goto failed_read_status;
- }
-
- while (1) {
- if (i2c_byte_transfer(chnd, I2C_DATA_ADDR, &reg, 0, 1) < 0) {
- fprintf(stderr, "Flash polling WE FAILED\n");
- break;
- }
-
- if ((reg & 0x03) == 2) {
- /* busy bit cleared and WE bit set */
- ret = 0;
- break;
- }
- }
-failed_read_status:
- return ret;
-}
-
-static int ftdi_config_i2c(struct ftdi_context *ftdi)
-{
- int ret;
- static const uint16_t divisor =
- 60000000 / (2 * FTDI_I2C_FREQ * 3 / 2 /* 3-phase CLK */) - 1;
- uint8_t clock_buf[] = {
- EN_3_PHASE,
- DIS_DIV_5,
- TCK_DIVISOR,
- divisor & 0xff,
- divisor >> 8};
-
- ret = ftdi_set_latency_timer(ftdi, 16 /* ms */);
- if (ret < 0)
- fprintf(stderr, "Cannot set latency\n");
-
- ret = ftdi_set_bitmode(ftdi, 0, BITMODE_RESET);
- if (ret < 0) {
- fprintf(stderr, "Cannot reset MPSSE\n");
- return -EIO;
- }
- ret = ftdi_set_bitmode(ftdi, 0, BITMODE_MPSSE);
- if (ret < 0) {
- fprintf(stderr, "Cannot enable MPSSE\n");
- return -EIO;
- }
-
- ret = ftdi_usb_purge_buffers(ftdi);
- if (ret < 0)
- fprintf(stderr, "Cannot purge buffers\n");
-
- /* configure the clock */
- ret = ftdi_write_data(ftdi, clock_buf, sizeof(clock_buf));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-/* Special waveform definition */
-#define SPECIAL_LEN_USEC 50000ULL /* us */
-#define SPECIAL_FREQ 400000ULL
-
-#define SPECIAL_PATTERN 0x0000020301010302ULL
-#define SPECIAL_PATTERN_SDA_L_SCL_L 0x0000000000000000ULL
-#define SPECIAL_PATTERN_SDA_H_SCL_L 0x0202020202020202ULL
-#define SPECIAL_PATTERN_SDA_L_SCL_H 0x0101010101010101ULL
-#define SPECIAL_PATTERN_SDA_H_SCL_H 0x0303030303030303ULL
-#define TICK_COUNT 24
-
-#define MSEC 1000
-#define USEC 1000000
-
-#define SPECIAL_BUFFER_SIZE \
- (((SPECIAL_LEN_USEC * SPECIAL_FREQ * 2 / USEC) + 7) & ~7)
-
-static int connect_to_ccd_i2c_bridge(struct common_hnd *chnd)
-{
- int rv;
-
- rv = usb_findit(chnd->conf.usb_serial, chnd->conf.usb_vid,
- chnd->conf.usb_pid, CR50_I2C_SUBCLASS,
- CR50_I2C_PROTOCOL, &chnd->uep);
-
- if (rv) {
- fprintf(stderr, "%s: usb_findit returned error %d\n",
- __func__, rv);
- }
-
- return rv;
-}
-
-static int ccd_trigger_special_waveform(struct common_hnd *chnd)
-{
- uint8_t response[20];
- size_t rsize;
- uint8_t req[] = {
- 0, /* Port 0. Might be necessary to modify. */
- CROS_CMD_ADDR, /* Chrome OS dedicated address. */
- 1, /* Will send a single byte command. */
- 0, /* No need to read back anything. */
- CROS_CMD_ITE_SYNC
- };
-
- usb_trx(&chnd->uep, req, sizeof(req), response, sizeof(response), 1,
- &rsize);
-
- if (rsize < USB_I2C_HEADER_SIZE)
- return -1;
-
- if (response[0])
- return -response[0];
- /*
- * The target is about to get reset, let's shut down the USB
- * connection.
- */
- usb_shut_down(&chnd->uep);
-
- sleep(3);
-
- return connect_to_ccd_i2c_bridge(chnd);
-}
-
-static int ftdi_send_special_waveform(struct common_hnd *chnd)
-{
- int ret;
- int i;
- uint64_t *wave;
- struct ftdi_context *ftdi = chnd->ftdi_hnd;
- uint8_t release_lines[] = {SET_BITS_LOW, 0, 0};
-
- 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");
- goto free_and_return;
- }
-
- /*
- * set the clock divider, so we output a new bitbang value every
- * 2.5us.
- */
- ret = ftdi_set_baudrate(ftdi, 160000);
- if (ret) {
- fprintf(stderr, "failed to set bitbang clock\n");
- 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");
- goto free_and_return;
- }
-
- /* do usb special waveform */
- wave[0] = 0x0;
- ftdi_write_data(ftdi, (uint8_t *)wave, 1);
- usleep(5000);
-
- /* program each special tick */
- for (i = 0; i < TICK_COUNT; ) {
- wave[i++] = SPECIAL_PATTERN_SDA_L_SCL_L;
- wave[i++] = SPECIAL_PATTERN_SDA_H_SCL_L;
- wave[i++] = SPECIAL_PATTERN_SDA_L_SCL_L;
- }
- wave[19] = SPECIAL_PATTERN_SDA_H_SCL_H;
-
- /* fill the buffer with the waveform pattern */
- for (i = TICK_COUNT; i < SPECIAL_BUFFER_SIZE / sizeof(uint64_t); i++)
- wave[i] = SPECIAL_PATTERN;
-
- ret = ftdi_write_data(ftdi, (uint8_t *)wave, SPECIAL_BUFFER_SIZE);
- if (ret < 0)
- fprintf(stderr, "Cannot output special waveform\n");
- else
- /* no error */
- ret = 0;
-
- /* clean everything to go back to regular I2C communication */
- ftdi_usb_purge_buffers(ftdi);
- ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET);
- 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)
-{
- const int max_iterations = 10;
- int ret;
- int iterations;
-
- 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;
- }
-
- iterations = 0;
-
- do {
- ret = chnd->conf.i2c_if->send_special_waveform(chnd);
- if (ret)
- break;
-
- /* wait for PLL stable for 5ms (plus remaining USB transfers) */
- usleep(10 * MSEC);
-
- /* Stop EC ASAP after sending special waveform. */
- if (dbgr_stop_ec(chnd) >= 0) {
- /*
- * If we can talk to chip, then we can break the retry
- * loop.
- */
- ret = check_chipid(chnd);
- } else {
- ret = -1;
- if (!(iterations % max_iterations))
- fprintf(stderr, "!please reset EC if flashing"
- " sequence is not starting!\n");
- }
- } while (ret && (iterations++ < max_iterations));
-
- if (ret)
- fprintf(stderr, "Failed to send special waveform!\n");
- else
- printf("Done with sending special waveform.\n");
-
- return ret;
-}
-
-static int windex;
-static const char wheel[] = {'|', '/', '-', '\\' };
-static void draw_spinner(uint32_t remaining, uint32_t size)
-{
- int percent = (size - remaining)*100/size;
- fprintf(stderr, "\r%c%3d%%", wheel[windex++], percent);
- windex %= sizeof(wheel);
-}
-
-/* Note: this function must be called in follow mode */
-static int spi_send_cmd_fast_read(struct common_hnd *chnd, uint32_t addr)
-{
- int ret = 0;
- uint8_t cmd = 0x9;
-
- /* Fast Read command */
- ret = spi_flash_command_short(chnd, SPI_CMD_FAST_READ, "fast read");
- /* Send address */
- ret |= i2c_write_byte(chnd, 0x08, ((addr >> 16) & 0xff)); /* addr_h */
- ret |= i2c_write_byte(chnd, 0x08, ((addr >> 8) & 0xff)); /* addr_m */
- ret |= i2c_write_byte(chnd, 0x08, (addr & 0xff)); /* addr_l */
- /* fake byte */
- ret |= i2c_write_byte(chnd, 0x08, 0x00);
- /* use i2c block read command */
- ret |= i2c_byte_transfer(chnd, I2C_CMD_ADDR, &cmd, 1, 1);
- if (ret < 0)
- fprintf(stderr, "Send fast read command failed\n");
-
- return ret;
-}
-
-static int command_read_pages(struct common_hnd *chnd, uint32_t address,
- uint32_t size, uint8_t *buffer)
-{
- int res = -EIO;
- uint32_t remaining = size;
- int cnt;
-
- if (address & 0xFF) {
- fprintf(stderr, "page read requested at non-page boundary: "
- "0x%X\n", address);
- return -EINVAL;
- }
-
- if (spi_flash_follow_mode(chnd, "fast read") < 0)
- goto failed_read;
-
- if (spi_send_cmd_fast_read(chnd, address) < 0)
- goto failed_read;
-
- while (remaining) {
- cnt = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
- draw_spinner(remaining, size);
-
- /* read page data */
- res = i2c_byte_transfer(chnd, I2C_BLOCK_ADDR, buffer, 0, cnt);
- if (res < 0) {
- fprintf(stderr, "page data read failed\n");
- goto failed_read;
- }
-
- address += cnt;
- remaining -= cnt;
- buffer += cnt;
-
- /* We need to resend fast read command at 256KB boundary. */
- if (!(address % 0x40000) && remaining) {
- if (spi_send_cmd_fast_read(chnd, address) < 0)
- goto failed_read;
- }
- }
- /* No error so far */
- res = size;
-failed_read:
- if (spi_flash_follow_mode_exit(chnd, "fast read") < 0)
- res = -EIO;
-
- return res;
-}
-
-static bool is_empty_page(uint8_t *buffer, int size)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (buffer[i] != 0xFF)
- return false;
- }
-
- return true;
-}
-
-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.block_write_size;
- uint32_t remaining = size;
- int cnt;
- uint8_t addr_H, addr_M, addr_L;
- uint8_t data;
-
- if (spi_flash_follow_mode(chnd, "AAI write") < 0)
- goto failed_write;
-
- while (remaining) {
- cnt = (remaining > block_write_size) ?
- block_write_size : remaining;
- addr_H = (address >> 16) & 0xFF;
- addr_M = (address >> 8) & 0xFF;
- addr_L = address & 0xFF;
-
- draw_spinner(remaining, size);
-
- /* Write enable */
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_ENABLE,
- "write enable for AAI write") < 0)
- goto failed_write;
-
- /* Check write enable bit */
- if (spi_check_write_enable(chnd, "AAI write") < 0)
- goto failed_write;
-
- /* Setup write */
- if (spi_flash_command_short(chnd, SPI_CMD_WORD_PROGRAM,
- "AAI write") < 0)
- goto failed_write;
-
- /* Set eflash page address */
- res = i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_H, 1, 1);
- res |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_M, 1, 1);
- res |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_L, 1, 1);
- if (res < 0) {
- fprintf(stderr, "Flash write set page FAILED (%d)\n",
- res);
- goto failed_write;
- }
-
- /* Wait until not busy */
- if (spi_poll_busy(chnd, "AAI write") < 0)
- goto failed_write;
-
- /* 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;
-
- if (res < 0) {
- fprintf(stderr, "Flash data write failed\n");
- goto failed_write;
- }
-
- data = 0xFF;
- res = i2c_byte_transfer(chnd, I2C_DATA_ADDR, &data, 1, 1);
- res |= i2c_write_byte(chnd, 0x10, 0x00);
- if (res < 0) {
- fprintf(stderr, "Flash end data write FAILED (%d)\n",
- res);
- goto failed_write;
- }
-
- /* Write disable */
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable for AAI write") < 0)
- goto failed_write;
-
- /* Wait until available */
- if (spi_poll_busy(chnd, "write disable for AAI write") < 0)
- goto failed_write;
-
- address += cnt;
- remaining -= cnt;
- }
- draw_spinner(remaining, size);
- /* No error so far */
- res = size;
-failed_write:
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable exit AAI write") < 0)
- res = -EIO;
-
- if (spi_flash_follow_mode_exit(chnd, "AAI write") < 0)
- res = -EIO;
-
- return res;
-}
-
-/*
- * Test for spi page program command
- */
-static int command_write_pages3(struct common_hnd *chnd, uint32_t address,
- uint32_t size, uint8_t *buffer)
-{
- int ret = 0;
- uint8_t addr_H, addr_M, addr_L;
-
- /* SMB_SPI_Flash_Write_Enable */
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_ENABLE,
- "SPI Command Write Enable") < 0) {
- ret = -EIO;
- goto failed_write;
- }
-
- if (spi_flash_command_short(chnd, SPI_CMD_PAGE_PROGRAM,
- "SPI_CMD_PAGE_PROGRAM") < 0) {
- ret = -EIO;
- goto failed_write;
- }
-
- addr_H = (address >> 16) & 0xFF;
- addr_M = (address >> 8) & 0xFF;
- addr_L = address & 0xFF;
-
- ret = i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_H, 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_M, 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_L, 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_BLOCK_ADDR, buffer, 1, size);
- if (ret < 0)
- goto failed_write;
-
- /* Wait until not busy */
- if (spi_poll_busy(chnd, "Page Program") < 0)
- ret = -EIO;
-
- /* No error so far */
-failed_write:
- return ret;
-}
-
-
-
-static int command_erase(struct common_hnd *chnd, uint32_t len, uint32_t off)
-{
- int res = -EIO;
- int page = 0;
- uint32_t remaining = len;
-
- printf("Erasing chip...\n");
-
- if (off != 0 || len != chnd->flash_size) {
- fprintf(stderr, "Only full chip erase is supported\n");
- return -EINVAL;
- }
-
- if (spi_flash_follow_mode(chnd, "erase") < 0)
- goto failed_erase;
-
- while (remaining) {
- draw_spinner(remaining, len);
-
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_ENABLE,
- "write enable for erase") < 0)
- goto failed_erase;
-
- if (spi_check_write_enable(chnd, "erase") < 0)
- goto failed_erase;
-
- /* do chip erase */
- if (remaining == chnd->flash_size) {
- if (spi_flash_command_short(chnd, SPI_CMD_CHIP_ERASE,
- "chip erase") < 0)
- goto failed_erase;
- goto wait_busy_cleared;
- }
-
- /* do sector erase */
- if (spi_flash_command_short(chnd, spi_cmd_sector_erase,
- "sector erase") < 0)
- goto failed_erase;
-
- if (spi_flash_set_erase_page(chnd, page, "sector erase") < 0)
- goto failed_erase;
-
-wait_busy_cleared:
- if (spi_poll_busy(chnd, "erase") < 0)
- goto failed_erase;
-
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable for erase") < 0)
- goto failed_erase;
-
- if (remaining == chnd->flash_size) {
- remaining = 0;
- draw_spinner(remaining, len);
- } else {
- page += sector_erase_pages;
- remaining -= sector_erase_pages * PAGE_SIZE;
- }
- }
-
- /* No error so far */
- printf("\n\rErasing Done.\n");
- res = 0;
-
-failed_erase:
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable exit erase") < 0)
- res = -EIO;
-
- if (spi_flash_follow_mode_exit(chnd, "erase") < 0)
- res = -EIO;
-
- return res;
-}
-
-/*
- * This function can Erase First Sector or Erase All Sector by reset value
- * Some F/W will produce the H/W watchdog reset and it will happen
- * reset issue while flash.
- * Add such function to prevent the reset issue.
- */
-static int command_erase2(struct common_hnd *chnd, uint32_t len,
- uint32_t off, uint32_t reset)
-{
- int res = -EIO;
- int page = 0;
- uint32_t remaining = len;
-
- /*
- * TODOD(b/<>):
- * Using sector erase instead of chip erase
- * For some new chip , the chip erase may not work
- * well on the original flow
- */
-
- printf("Erasing flash...erase size=%d\n", len);
-
- if (off != 0 || len != chnd->flash_size) {
- fprintf(stderr, "Only full chip erase is supported\n");
- return -EINVAL;
- }
-
- if (spi_flash_follow_mode(chnd, "erase") < 0)
- goto failed_erase;
-
- while (remaining) {
-
- draw_spinner(remaining, len);
-
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_ENABLE,
- "write enable for erase") < 0)
- goto failed_erase;
-
- if (spi_check_write_enable(chnd, "erase") < 0)
- goto failed_erase;
-
- /* do sector erase */
- if (spi_flash_command_short(chnd, spi_cmd_sector_erase,
- "sector erase") < 0)
- goto failed_erase;
-
- if (spi_flash_set_erase_page(chnd, page, "sector erase") < 0)
- goto failed_erase;
-
- if (spi_poll_busy(chnd, "erase") < 0)
- goto failed_erase;
-
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable for erase") < 0)
- goto failed_erase;
-
- if (reset) {
- printf("\n\rreset to prevent the watchdog reset...\n");
- break;
- }
-
- page += sector_erase_pages;
- remaining -= sector_erase_pages * PAGE_SIZE;
- draw_spinner(remaining, len);
-
- }
-
- /* No error so far */
- printf("\n\rErasing Done.\n");
- res = 0;
-
-failed_erase:
- if (spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "write disable exit erase") < 0)
- res = -EIO;
-
- if (spi_flash_follow_mode_exit(chnd, "erase") < 0)
- res = -EIO;
-
- return res;
-}
-
-/* Return zero on success, a negative error value on failures. */
-static int read_flash(struct common_hnd *chnd)
-{
- int res;
- FILE *hnd;
- uint8_t *buffer;
- const char *filename = chnd->conf.input_filename;
- size_t offset = chnd->conf.range_base;
- size_t size;
-
- if (!offset && !chnd->conf.range_size) {
- size = chnd->flash_size;
- } else {
- /*
- * Zero conf.range_size means the user did not enter range
- * size in the command line.
- */
- if (chnd->conf.range_size)
- size = chnd->conf.range_size;
- else
- size = chnd->flash_size - offset;
-
- if (!size) {
- fprintf(stderr,
- "Error: not reading a zero sized range!\n");
- return -EINVAL;
- }
-
- if ((size + offset) > chnd->flash_size) {
- fprintf(stderr,
- "Error: Read range exceeds flash size!\n");
- return -EINVAL;
- }
- }
-
- buffer = malloc(size);
- if (!buffer) {
- fprintf(stderr, "Cannot allocate %zd bytes\n", size);
- return -ENOMEM;
- }
-
- hnd = fopen(filename, "w");
- if (!hnd) {
- fprintf(stderr, "Cannot open file %s for writing\n", filename);
- free(buffer);
- return -EIO;
- }
-
- printf("Reading %zd bytes at %#08zx\n", size, offset);
- res = command_read_pages(chnd, offset, size, buffer);
- if (res > 0) {
- if (fwrite(buffer, res, 1, hnd) != 1)
- fprintf(stderr, "Cannot write %s\n", filename);
- }
- printf("\r %d bytes read.\n", res);
-
- fclose(hnd);
- free(buffer);
- return (res < 0) ? res : 0;
-}
-
-/* Return zero on success, a negative error value on failures. */
-static int write_flash(struct common_hnd *chnd, const char *filename,
- uint32_t offset)
-{
- int res, written;
- FILE *hnd;
- int size = chnd->flash_size;
- uint8_t *buffer = malloc(size);
-
- if (!buffer) {
- fprintf(stderr, "%s: Cannot allocate %d bytes\n", __func__,
- size);
- return -ENOMEM;
- }
-
- hnd = fopen(filename, "r");
- if (!hnd) {
- fprintf(stderr, "%s: Cannot open file %s for reading\n",
- __func__, filename);
- free(buffer);
- return -EIO;
- }
- res = fread(buffer, 1, size, hnd);
- if (res <= 0) {
- fprintf(stderr, "%s: Failed to read %d bytes from %s with "
- "ferror() %d\n", __func__, size, filename, ferror(hnd));
- free(buffer);
- fclose(hnd);
- return -EIO;
- }
- fclose(hnd);
-
- printf("Writing %d bytes at 0x%08x\n", res, offset);
- written = command_write_pages(chnd, offset, res, buffer);
- if (written != res) {
- fprintf(stderr, "%s: Error writing to flash\n", __func__);
- free(buffer);
- return -EIO;
- }
- printf("\n\rWriting Done.\n");
-
- free(buffer);
- return 0;
-}
-
-/*
- * Return zero on success, a negative error value on failures.
- *
- * Change the program command to match the ITE Download
- * The original flow may not work on the DX chip.
- *
- */
-static int write_flash2(struct common_hnd *chnd, const char *filename,
- uint32_t offset)
-{
- int res;
- int block_write_size = chnd->conf.block_write_size;
- FILE *hnd;
- int size = chnd->flash_size;
- int cnt, two_bytes_sent, ret;
- uint8_t addr_h, addr_m, addr_l, data_ff = 0xff;
- uint8_t *buffer = malloc(size);
-
- if (!buffer) {
- fprintf(stderr, "%s: Cannot allocate %d bytes\n", __func__,
- size);
- return -ENOMEM;
- }
-
- hnd = fopen(filename, "r");
- if (!hnd) {
- fprintf(stderr, "%s: Cannot open file %s for reading\n",
- __func__, filename);
- free(buffer);
- return -EIO;
- }
- res = fread(buffer, 1, size, hnd);
- if (res <= 0) {
- fprintf(stderr, "%s: Failed to read %d bytes from %s with "
- "ferror() %d\n", __func__, size, filename, ferror(hnd));
- fclose(hnd);
- free(buffer);
- return -EIO;
- }
- fclose(hnd);
-
- /* Enter follow mode */
- if (spi_flash_follow_mode(chnd, "AAI write") < 0) {
- ret = -EIO;
- goto failed_enter_mode;
- }
-
- printf("Writing %d bytes at 0x%08x.......\n", res, offset);
-
-__send_aai_cmd:
- addr_h = (offset >> 16) & 0xff;
- addr_m = (offset >> 8) & 0xff;
- addr_l = offset & 0xff;
-
- /* write enable command */
- ret = spi_flash_command_short(chnd, SPI_CMD_WRITE_ENABLE, "SPI WE");
- /* AAI command */
- ret |= spi_flash_command_short(chnd, SPI_CMD_WORD_PROGRAM, "SPI AAI");
- /* address of AAI command */
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_h, 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_m, 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &addr_l, 1, 1);
- /* Send first two bytes of buffe */
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &buffer[offset], 1, 1);
- ret |= i2c_byte_transfer(chnd, I2C_DATA_ADDR, &buffer[offset+1], 1, 1);
- /* we had sent two bytes */
- offset += 2;
- res -= 2;
- two_bytes_sent = 1;
- /* Wait until not busy */
- if (spi_poll_busy(chnd, "wait busy bit cleared at AAI write ") < 0) {
- ret = -EIO;
- goto failed_write;
- }
- /* enable quick AAI mode */
- ret |= i2c_write_byte(chnd, 0x10, 0x20);
- if (ret < 0)
- goto failed_write;
-
- while (res) {
- cnt = (res > block_write_size) ? block_write_size : res;
- /* we had sent two bytes */
- if (two_bytes_sent) {
- two_bytes_sent = 0;
- cnt -= 2;
- }
- if (i2c_byte_transfer(chnd, I2C_BLOCK_ADDR, &buffer[offset],
- 1, cnt) < 0) {
- ret = -EIO;
- goto failed_write;
- }
-
- res -= cnt;
- offset += cnt;
- draw_spinner(res, res + offset);
-
- /* We need to resend aai write command at 256KB boundary. */
- if (!(offset % 0x40000) && res) {
- /* disable quick AAI mode */
- i2c_byte_transfer(chnd, I2C_DATA_ADDR, &data_ff, 1, 1);
- i2c_write_byte(chnd, 0x10, 0x00);
- /* write disable command */
- spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "SPI write disable");
- goto __send_aai_cmd;
- }
- }
-
-failed_write:
- /* disable quick AAI mode */
- i2c_byte_transfer(chnd, I2C_DATA_ADDR, &data_ff, 1, 1);
- i2c_write_byte(chnd, 0x10, 0x00);
- /* write disable command */
- spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "SPI write disable");
-failed_enter_mode:
- /* exit follow mode */
- spi_flash_follow_mode_exit(chnd, "AAI write");
-
- if (ret < 0)
- printf("\n\rWriting Failed.\n");
- else
- printf("\n\rWriting Done.\n");
-
- free(buffer);
-
- return ret;
-}
-
-/*
- * Return zero on success, a negative error value on failures.
- *
- * Change the program command to match the ITE Download
- * The original flow may not work on the DX chip.
- *
- */
-static int write_flash3(struct common_hnd *chnd, const char *filename,
- uint32_t offset)
-{
- int res, ret = 0;
- int block_write_size = chnd->conf.block_write_size;
- FILE *hnd;
- int size = chnd->flash_size;
- int cnt;
- uint8_t *buf = malloc(size);
-
- if (!buf) {
- fprintf(stderr, "%s: Cannot allocate %d bytes\n", __func__,
- size);
- return -ENOMEM;
- }
-
- hnd = fopen(filename, "r");
- if (!hnd) {
- fprintf(stderr, "%s: Cannot open file %s for reading\n",
- __func__, filename);
- free(buf);
- return -EIO;
- }
- res = fread(buf, 1, size, hnd);
- if (res <= 0) {
- fprintf(stderr, "%s: Failed to read %d bytes from %s with "
- "ferror() %d\n", __func__, size, filename, ferror(hnd));
- fclose(hnd);
- free(buf);
- return -EIO;
- }
- fclose(hnd);
-
- printf("Writing %d bytes at 0x%08x.......\n", res, offset);
-
- /* Enter follow mode */
- ret = spi_flash_follow_mode(chnd, "Page program");
- if (ret < 0)
- goto failed_write;
-
- /* Page program instruction allows up to 256 bytes */
- if (block_write_size > 256)
- block_write_size = 256;
-
- while (res) {
- cnt = (res > block_write_size) ? block_write_size : res;
- if (chnd->conf.erase && is_empty_page(&buf[offset], cnt)) {
- /* do nothing */
- } else if (command_write_pages3(chnd, offset, cnt, &buf[offset])
- < 0) {
- ret = -EIO;
- goto failed_write;
- }
-
- res -= cnt;
- offset += cnt;
- draw_spinner(res, res + offset);
- }
-
-failed_write:
- free(buf);
- spi_flash_command_short(chnd, SPI_CMD_WRITE_DISABLE,
- "SPI write disable");
- spi_flash_follow_mode_exit(chnd, "Page program");
- if (ret < 0)
- fprintf(stderr, "%s: Error writing to flash\n", __func__);
- else
- printf("\n\rWriting Done.\n");
-
- return ret;
-}
-
-
-
-/* Return zero on success, a non-zero value on failures. */
-static int verify_flash(struct common_hnd *chnd, const char *filename,
- uint32_t offset)
-{
- int res;
- int file_size;
- FILE *hnd;
- uint8_t *buffer = malloc(chnd->flash_size);
- uint8_t *buffer2 = malloc(chnd->flash_size);
-
- if (!buffer || !buffer2) {
- fprintf(stderr, "%s: Cannot allocate %d bytes\n", __func__,
- chnd->flash_size);
- free(buffer);
- free(buffer2);
- return -ENOMEM;
- }
-
- hnd = fopen(filename, "r");
- if (!hnd) {
- fprintf(stderr, "%s: Cannot open file %s for reading\n",
- __func__, filename);
- res = -EIO;
- goto exit;
- }
-
- file_size = fread(buffer, 1, chnd->flash_size, hnd);
- if (file_size <= 0) {
- fprintf(stderr, "%s: Failed to read %d bytes from %s with "
- "ferror() %d\n", __func__, chnd->flash_size, filename,
- ferror(hnd));
- fclose(hnd);
- res = -EIO;
- goto exit;
- }
- fclose(hnd);
-
- printf("Verify %d bytes at 0x%08x\n", file_size, offset);
- res = command_read_pages(chnd, offset, chnd->flash_size, buffer2);
- if (res > 0)
- res = memcmp(buffer, buffer2, file_size);
-
- printf("\n\rVerify %s\n", res ? "Failed!" : "Done.");
-
-exit:
- free(buffer);
- free(buffer2);
- return res;
-}
-
-static struct ftdi_context *open_ftdi_device(int vid, int pid,
- int interface, const char *serial)
-{
- struct ftdi_context *ftdi;
- int ret;
-
- ftdi = ftdi_new();
- if (!ftdi) {
- fprintf(stderr, "Cannot allocate context memory\n");
- return NULL;
- }
-
- ret = ftdi_set_interface(ftdi, interface);
- if (ret < 0) {
- fprintf(stderr, "cannot set ftdi interface %d: %s(%d)\n",
- interface, ftdi_get_error_string(ftdi), ret);
- goto open_failed;
- }
- ret = ftdi_usb_open_desc(ftdi, vid, pid, NULL, serial);
- if (ret < 0) {
- fprintf(stderr, "unable to open ftdi device: %s(%d)\n",
- ftdi_get_error_string(ftdi), ret);
- goto open_failed;
- }
- return ftdi;
-
-open_failed:
- ftdi_free(ftdi);
- return NULL;
-}
-
-static int linux_i2c_interface_init(struct common_hnd *chnd)
-{
- int err;
-
- if (!chnd->conf.i2c_dev_path) {
- fprintf(stderr, "Must set --i2c_dev_path when using "
- "Linux i2c-dev interface.\n");
- return -1;
- }
- printf("Attempting to open Linux i2c-dev path %s\n",
- chnd->conf.i2c_dev_path);
- chnd->i2c_dev_fd = open(chnd->conf.i2c_dev_path, O_RDWR);
- if (chnd->i2c_dev_fd < 0) {
- err = errno;
- perror("Failed to open Linux i2c-dev file path with error");
- fprintf(stderr, "Linux i2c-dev file path from --i2c_dev_path "
- "is: %s\n", chnd->conf.i2c_dev_path);
- return err ? err : -1;
- }
- printf("Successfully opened Linux i2c-dev path %s\n",
- chnd->conf.i2c_dev_path);
- return 0;
-}
-
-static int linux_i2c_interface_shutdown(struct common_hnd *chnd)
-{
- int err;
-
- printf("Attempting to close Linux i2c-dev file descriptor %d\n",
- chnd->i2c_dev_fd);
- if (close(chnd->i2c_dev_fd)) {
- err = errno;
- perror("Failed to close Linux i2c-dev file descriptor with "
- "error");
- return err ? err : -1;
- }
- printf("Successfully closed Linux i2c-dev file descriptor %d\n",
- chnd->i2c_dev_fd);
- return 0;
-}
-
-static int ccd_i2c_interface_init(struct common_hnd *chnd)
-{
- chnd->conf.usb_vid = CR50_USB_VID;
- chnd->conf.usb_pid = CR50_USB_PID;
- return connect_to_ccd_i2c_bridge(chnd);
-}
-
-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)
-{
- return chnd->conf.send_waveform ? 0 : ftdi_config_i2c(chnd->ftdi_hnd);
-}
-
-/* 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 linux_i2c_interface = {
- .interface_init = linux_i2c_interface_init,
- .interface_shutdown = linux_i2c_interface_shutdown,
- .byte_transfer = linux_i2c_byte_transfer,
- /*
- * 254 bytes is the largest size that works with Servo Micro as of
- * 2018-11-30. Odd numbers up to 255 result in corruption, and 256 or
- * greater fails with a timeout from the I2C bus. Fixing that so this
- * can be increased to match FTDI_BLOCK_WRITE_SIZE would be a useful
- * speedup.
- *
- * 254 byte block sizes cause corruption with Ampton (using any kind of
- * servo). 128 bytes is the largest block_write_size compatible with
- * both Ampton and Servo Micro.
- *
- * See https://issuetracker.google.com/79684405 for background.
- */
- .default_block_write_size = 128,
-};
-
-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,
- .default_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,
- .default_block_write_size = FTDI_BLOCK_WRITE_SIZE,
-};
-
-static int post_waveform_work(struct common_hnd *chnd)
-{
- int ret;
-
- if (chnd->conf.i2c_if->interface_post_waveform) {
- ret = chnd->conf.i2c_if->interface_post_waveform(chnd);
- if (ret)
- return ret;
- }
-
- if (chnd->conf.disable_watchdog) {
- ret = dbgr_disable_watchdog(chnd);
- if (ret)
- return ret;
- }
-
- if (chnd->conf.disable_protect_path) {
- ret = dbgr_disable_protect_path(chnd);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int strdup_with_errmsg(const char *source, char **dest, const char *name)
-{
- int ret = 0;
- *dest = strdup(source);
- if (!(*dest)) {
- ret = errno ? errno : -1;
- fprintf(stderr, "strdup() of %zu size string from %s failed.\n",
- strlen(source), name);
- }
- return ret;
-}
-
-static const struct option longopts[] = {
- {"block-write-size", 1, 0, 'b'},
- {"debug", 0, 0, 'd'},
- {"erase", 0, 0, 'e'},
- {"help", 0, 0, 'h'},
- {"i2c-dev-path", 1, 0, 'D'},
- {"i2c-interface", 1, 0, 'c'},
- {"i2c-mux", 0, 0, 'm'},
- {"interface", 1, 0, 'i'},
- {"nodisable-protect-path", 0, 0, 'Z'},
- {"nodisable-watchdog", 0, 0, 'z'},
- {"noverify", 0, 0, 'n'},
- {"product", 1, 0, 'p'},
- {"range", 1, 0, 'R'},
- {"read", 1, 0, 'r'},
- {"send-waveform", 1, 0, 'W'},
- {"serial", 1, 0, 's'},
- {"vendor", 1, 0, 'v'},
- {"write", 1, 0, 'w'},
- {NULL, 0, 0, 0}
-};
-
-static void display_usage(const char *program)
-{
- fprintf(stderr, "Usage: %s [-d] [-v <VID>] [-p <PID>] \\\n"
- "\t[-c <linux|ccd|ftdi>] [-D /dev/i2c-<N>] [-i <1|2>] [-S] \\\n"
- "\t[-s <serial>] [-e] [-r <file>] [-W <0|1|false|true>] \\\n"
- "\t[-w <file>] [-R base[:size]] [-m] [-b <size>]\n",
- program);
- fprintf(stderr, "-d, --debug : Output debug traces.\n");
- fprintf(stderr, "-e, --erase : Erase all the flash content.\n");
- fprintf(stderr, "-c, --i2c-interface <linux|ccd|ftdi> : I2C interface "
- "to use\n");
- fprintf(stderr, "-D, --i2c-dev-path /dev/i2c-<N> : Path to "
- "Linux i2c-dev file e.g. /dev/i2c-5;\n"
- "\tonly applicable with --i2c-interface=linux\n");
- fprintf(stderr, "-i, --interface <1> : FTDI interface: A=1, B=2,"
- " ...\n");
- fprintf(stderr, "-m, --i2c-mux : Enable i2c-mux (to EC).\n"
- "\tSpecify this flag only if the board has an I2C MUX and\n"
- "\tyou are not using servod.\n");
- fprintf(stderr, "-n, --noverify : Don't auto verify.\n");
- fprintf(stderr, "-b, --block-write-size <size> : Perform writes in\n"
- "\tblocks of this many bytes.\n");
- fprintf(stderr, "-p, --product <0x1234> : USB product ID\n");
- fprintf(stderr, "-R, --range base[:size] : Allow to read or write"
- " just a slice\n"
- "\tof the file, starting at <base>:<size> bytes, or til\n"
- "\tthe end of the file if <size> is not specified, expressed\n"
- "\tin hex.\n");
- fprintf(stderr, "-r, --read <file> : Read the flash content and"
- " write it into <file>.\n");
- fprintf(stderr, "-s, --serial <serialname> : USB serial string\n");
- fprintf(stderr, "-v, --vendor <0x1234> : USB vendor ID\n");
- fprintf(stderr, "-W, --send-waveform <0|1|false|true> : Send the"
- " special waveform.\n"
- "\tDefault is true. Set to false if ITE direct firmware\n"
- "\tupdate mode has already been enabled.\n");
- fprintf(stderr, "-w, --write <file> : Write <file> to flash.\n");
- fprintf(stderr, "-z, --nodisable-watchdog : Do *not* disable EC "
- "watchdog.\n");
- fprintf(stderr, "-Z, --nodisable-protect-path : Do *not* disable EC "
- "protect path.\n");
-}
-
-/*
- * Parses -R command line option parameter, returns zero on success and
- * -1 on errors (non hex values, missing values, etc.).
- */
-static int parse_range_options(char *str, struct iteflash_config *conf)
-{
- char *size;
-
- if (!str) {
- fprintf(stderr, "missing range base address specification\n");
- return -1;
- }
-
- conf->range_base = strtoull(str, &size, 16);
- if (!size || !*size)
- return 0;
-
- if (*size++ != ':') {
- fprintf(stderr, "wrong range base address specification\n");
- return -1;
- }
-
- if (!*size) {
- fprintf(stderr, "missing range size specification\n");
- return -1;
- }
-
- conf->range_size = strtoull(size, &size, 16);
- if ((size && *size) || !conf->range_size) {
- fprintf(stderr, "wrong range size specification\n");
- return -1;
- }
-
- return 0;
-}
-
-static int parse_parameters(int argc, char **argv, struct iteflash_config *conf)
-{
- int opt, idx, ret = 0;
-
- while (!ret &&
- (opt = getopt_long(argc, argv, "?b:c:D:dehi:mp:R:r:s:uv:W:w:Zz",
- longopts, &idx)) != -1) {
- switch (opt) {
- case 'b':
- conf->block_write_size = strtol(optarg, NULL, 10);
- break;
- case 'c':
- if (!strcasecmp(optarg, "linux")) {
- conf->i2c_if = &linux_i2c_interface;
- } else 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);
- ret = -1;
- }
- break;
- case 'D':
- ret = strdup_with_errmsg(optarg, &conf->i2c_dev_path,
- "-D / --i2c-dev-path");
- break;
- case 'd':
- conf->debug = 1;
- break;
- case 'e':
- conf->erase = 1;
- break;
- case 'h':
- case '?':
- display_usage(argv[0]);
- ret = 2;
- break;
- case 'i':
- conf->usb_interface = strtol(optarg, NULL, 10);
- break;
- case 'm':
- conf->i2c_mux = 1;
- break;
- case 'n':
- conf->verify = 0;
- break;
- case 'p':
- conf->usb_pid = strtol(optarg, NULL, 16);
- break;
- case 'R':
- ret = parse_range_options(optarg, conf);
- break;
- case 'r':
- ret = strdup_with_errmsg(optarg, &conf->input_filename,
- "-r / --read");
- break;
- case 's':
- ret = strdup_with_errmsg(optarg, &conf->usb_serial,
- "-s / --serial");
- break;
- case 'v':
- conf->usb_vid = strtol(optarg, NULL, 16);
- break;
- case 'W':
- if (!strcmp(optarg, "0") ||
- !strcasecmp(optarg, "false")) {
- conf->send_waveform = 0;
- break;
- }
- if (!strcmp(optarg, "1") ||
- !strcasecmp(optarg, "true")) {
- conf->send_waveform = 1;
- break;
- }
- fprintf(stderr, "Unexpected -W / --special-waveform "
- "value: %s\n", optarg);
- ret = -1;
- break;
- case 'w':
- ret = strdup_with_errmsg(optarg, &conf->output_filename,
- "-w / --write");
- break;
- case 'z':
- conf->disable_watchdog = 0;
- break;
- case 'Z':
- conf->disable_protect_path = 0;
- break;
- }
- }
-
- if (ret)
- config_release(conf);
- return ret;
-}
-
-static void sighandler(int signum)
-{
- int status;
- printf("\nCaught signal %d: %s\nExiting...\n",
- signum, strsignal(signum));
- wait(&status);
- exit_requested = status;
-}
-
-static void register_sigaction(void)
-{
- struct sigaction sigact;
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = sighandler;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- sigaction(SIGINT, &sigact, NULL);
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGQUIT, &sigact, NULL);
-}
-
-int main(int argc, char **argv)
-{
- int ret = 1, other_ret;
- struct common_hnd chnd = {
- /* Default flag settings. */
- .conf = {
- .send_waveform = 1,
- .disable_watchdog = 1,
- .disable_protect_path = 1,
- .usb_interface = SERVO_INTERFACE,
- .usb_vid = SERVO_USB_VID,
- .usb_pid = SERVO_USB_PID,
- .verify = 1,
- .i2c_if = &ftdi_i2c_interface,
- },
- };
-
- /* Parse command line options */
- other_ret = parse_parameters(argc, argv, &chnd.conf);
- if (other_ret)
- return other_ret;
-
- /* Fill in block_write_size if not set from command line. */
- if (!chnd.conf.block_write_size)
- chnd.conf.block_write_size =
- chnd.conf.i2c_if->default_block_write_size;
-
- /* Open the communications channel. */
- if (chnd.conf.i2c_if->interface_init &&
- chnd.conf.i2c_if->interface_init(&chnd))
- goto return_after_parse;
-
- /* Register signal handler after opening the communications channel. */
- register_sigaction();
-
- if (chnd.conf.i2c_mux) {
- printf("configuring I2C MUX to EC.\n");
-
- if (config_i2c_mux(&chnd, I2C_MUX_CMD_EC))
- goto return_after_init;
- }
-
- /* Trigger embedded monitor detection */
- if (chnd.conf.send_waveform) {
- if (send_special_waveform(&chnd))
- goto return_after_init;
- } else {
- /* Stop EC ASAP after sending special waveform. */
- dbgr_stop_ec(&chnd);
-
- 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 return_after_init;
- }
- }
-
- /* Turn off power rails by reset GPIOs to default (input). */
- dbgr_reset_gpio(&chnd);
-
- check_flashid(&chnd);
-
- ret = post_waveform_work(&chnd);
- if (ret)
- goto return_after_init;
-
- if (chnd.conf.input_filename) {
- ret = read_flash(&chnd);
- if (ret)
- goto return_after_init;
- }
-
- switch (eflash_type) {
- case EFLASH_TYPE_8315:
- sector_erase_pages = 4;
- spi_cmd_sector_erase = SPI_CMD_SECTOR_ERASE_1K;
- break;
- case EFLASH_TYPE_KGD:
- sector_erase_pages = 16;
- spi_cmd_sector_erase = SPI_CMD_SECTOR_ERASE_4K;
- break;
- default:
- printf("Invalid EFLASH TYPE!");
- ret = -EINVAL;
- break;
- }
-
- if (ret)
- goto return_after_init;
-
- if (chnd.conf.erase) {
- if (chnd.flash_cmd_v2)
- /* Do Normal Erase Function */
- command_erase2(&chnd, chnd.flash_size, 0, 0);
- else
- 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 (chnd.conf.output_filename) {
- if (chnd.flash_cmd_v2)
- switch (eflash_type) {
- case EFLASH_TYPE_8315:
- ret = write_flash2(&chnd,
- chnd.conf.output_filename, 0);
- break;
- case EFLASH_TYPE_KGD:
- ret = write_flash3(&chnd,
- chnd.conf.output_filename, 0);
- break;
- default:
- printf("Invalid EFLASH TYPE!");
- ret = -EINVAL;
- break;
- }
- else
- ret = write_flash(&chnd, chnd.conf.output_filename, 0);
- if (ret)
- goto return_after_init;
- if (chnd.conf.verify) {
- ret = verify_flash(&chnd, chnd.conf.output_filename, 0);
- if (ret)
- goto return_after_init;
- }
- }
-
- /* Normal exit */
- ret = 0;
-
- return_after_init:
- /*
- * Exit DBGR mode. This ensures EC won't hold clock/data pins of I2C.
- * Avoid resetting EC here because flash_ec will after iteflash exits.
- * This avoids double reset after flash sequence.
- */
- exit_dbgr_mode(&chnd);
-
- if (chnd.conf.i2c_mux) {
- printf("configuring I2C MUX to none.\n");
- config_i2c_mux(&chnd, I2C_MUX_CMD_NONE);
- }
-
- if (chnd.conf.i2c_if->interface_shutdown) {
- other_ret = chnd.conf.i2c_if->interface_shutdown(&chnd);
- if (!ret && other_ret)
- ret = other_ret;
- }
-
- return_after_parse:
- config_release(&chnd.conf);
- return ret;
-}