diff options
Diffstat (limited to 'util/iteflash.c')
-rw-r--r-- | util/iteflash.c | 2445 |
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, ®, 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, ®, 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; -} |