summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-08-14 18:31:05 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-08-26 23:06:23 +0000
commite913bc15b8a631757b362da09fc1385a7f509def (patch)
tree166afea132ba5e162988cb5346eeb48ba054d1a8
parentb22c10ce2e5d8186cff4623dbf6fb18ee6a62017 (diff)
downloadchrome-ec-e913bc15b8a631757b362da09fc1385a7f509def.tar.gz
samus: add host commands for flashing zinger RW
This adds a new host commmand for sending RW updates to PD devices. The host command has a variety of sub-commands for performing the update, including: erase RW, reboot, write new hash, write flash. To program zinger RW, you should send host commands in this order: write new hash to all 0's reboot (zinger boots into RO since RW hash doesn't match) erase RW write flash write new hash to match contents of RW reboot This also adds an ectool command to write a new RW. Just pass it the RW .flat or .bin file. BUG=chrome-os-partner:31361 BRANCH=none TEST=ectool --dev=1 --interface=lpc flashpd 0 0 zinger.RW.flat Change-Id: Ia81615001b83ad7ee69b1af2bf1d7059177cde04 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/213239 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--Makefile.toolchain2
-rw-r--r--common/host_command.c2
-rw-r--r--common/host_command_master.c13
-rw-r--r--common/usb_pd_protocol.c83
-rw-r--r--include/ec_commands.h20
-rw-r--r--include/sha1.h5
-rw-r--r--include/usb_pd.h3
-rw-r--r--util/build.mk2
-rw-r--r--util/ectool.c130
9 files changed, 250 insertions, 10 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain
index 6bf27a3f78..43f390cde4 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -53,7 +53,7 @@ LIBFTDI_CFLAGS=$(shell $(PKG_CONFIG) --cflags lib${LIBFTDI_NAME})
LIBFTDI_LDLIBS=$(shell $(PKG_CONFIG) --libs lib${LIBFTDI_NAME})
BUILD_CFLAGS= $(LIBFTDI_CFLAGS) $(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN)
-HOST_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN)
+HOST_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN) -DHOST_TOOLS_BUILD
LDFLAGS=-nostdlib -X --gc-sections
BUILD_LDFLAGS=$(LIBFTDI_LDLIBS)
HOST_TEST_LDFLAGS=-T core/host/host_exe.lds -lrt -pthread -rdynamic -lm\
diff --git a/common/host_command.c b/common/host_command.c
index 22374059c6..6bb6176afd 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -531,7 +531,7 @@ static void host_command_debug_request(struct host_cmd_handler_args *args)
enum ec_status host_command_process(struct host_cmd_handler_args *args)
{
const struct host_command *cmd;
- enum ec_status rv;
+ int rv;
if (hcdebug)
host_command_debug_request(args);
diff --git a/common/host_command_master.c b/common/host_command_master.c
index a669f22111..38acd9a560 100644
--- a/common/host_command_master.c
+++ b/common/host_command_master.c
@@ -89,13 +89,8 @@ static int pd_host_command_internal(int command, int version,
return -ret;
}
- ret = resp_buf[0];
resp_len = resp_buf[1];
- if (ret)
- CPRINTF("[%T command 0x%02x returned error %d]\n", command,
- ret);
-
if (resp_len > (insize + sizeof(rs))) {
/* Do a dummy read to generate stop condition */
i2c_xfer(I2C_PORT_PD_MCU, CONFIG_USB_PD_I2C_SLAVE_ADDR,
@@ -115,6 +110,14 @@ static int pd_host_command_internal(int command, int version,
return -ret;
}
+ /* Check for host command error code */
+ ret = resp_buf[0];
+ if (ret) {
+ CPRINTF("[%T command 0x%02x returned error %d]\n", command,
+ ret);
+ return -ret;
+ }
+
/* Read back response header and start checksum */
sum = 0;
for (i = 0, d = (uint8_t *)&rs; i < sizeof(rs); i++, d++) {
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 9e0115743c..263c9b63e0 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -962,10 +962,16 @@ packet_err:
return bit;
}
-void pd_send_vdm(int port, uint32_t vid, int cmd, uint32_t *data, int count)
+void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
+ int count)
{
int i;
+ if (count > VDO_MAX_SIZE - 1) {
+ CPRINTF("VDM over max size\n");
+ return;
+ }
+
pd[port].vdo_data[0] = VDO(vid, cmd);
pd[port].vdo_count = count + 1;
for (i = 1; i < count + 1; i++)
@@ -1787,4 +1793,79 @@ DECLARE_HOST_COMMAND(EC_CMD_USB_PD_CONTROL,
hc_usb_pd_control,
EC_VER_MASK(0));
+static int hc_remote_flash(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_usb_pd_fw_update *p = args->params;
+ int port = p->port;
+ const uint32_t *data = &(p->size) + 1;
+ int i, size;
+
+ if (p->size + sizeof(*p) > args->params_size)
+ return EC_RES_INVALID_PARAM;
+
+ switch (p->cmd) {
+ case USB_PD_FW_REBOOT:
+ ccprintf("PD Update - Reboot\n");
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_REBOOT, NULL, 0);
+
+ /* Delay to give time for device to reboot */
+ usleep(750 * MSEC);
+ return EC_RES_SUCCESS;
+
+ case USB_PD_FW_FLASH_ERASE:
+ ccprintf("PD Update - Erase RW flash\n");
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_ERASE, NULL, 0);
+
+ /* Wait until VDM is done */
+ while (pd[port].vdm_state > 0)
+ task_wait_event(100*MSEC);
+ break;
+
+ case USB_PD_FW_FLASH_HASH:
+ /* Can only write 20 bytes */
+ if (p->size != 20)
+ return EC_RES_INVALID_PARAM;
+
+ ccprintf("PD Update - Write RW flash hash ");
+ for (i = 0; i < 5; i++)
+ ccprintf("%08x ", *(data + i));
+ ccprintf("\n");
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_HASH, data, 5);
+
+ /* Wait until VDM is done */
+ while (pd[port].vdm_state > 0)
+ task_wait_event(100*MSEC);
+ break;
+
+ case USB_PD_FW_FLASH_WRITE:
+ /* Data size must be a multiple of 4 */
+ if (!p->size || p->size % 4)
+ return EC_RES_INVALID_PARAM;
+
+ size = p->size / 4;
+ ccprintf("PD Update - Write RW flash\n");
+ for (i = 0; i < size; i += VDO_MAX_SIZE - 1) {
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_WRITE,
+ data + i, MIN(size - i, VDO_MAX_SIZE - 1));
+
+ /* Wait until VDM is done */
+ while (pd[port].vdm_state > 0)
+ task_wait_event(10*MSEC);
+ }
+ break;
+
+ default:
+ return EC_RES_INVALID_PARAM;
+ break;
+ }
+
+ if (pd[port].vdm_state < 0)
+ return EC_RES_ERROR;
+ else
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_USB_PD_FW_UPDATE,
+ hc_remote_flash,
+ EC_VER_MASK(0));
+
#endif /* CONFIG_COMMON_RUNTIME */
diff --git a/include/ec_commands.h b/include/ec_commands.h
index a8c9ab450b..83bca00c84 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2528,6 +2528,26 @@ struct ec_params_usb_pd_control {
uint8_t mux;
} __packed;
+/* Write USB-PD device FW */
+#define EC_CMD_USB_PD_FW_UPDATE 0x110
+
+enum usb_pd_fw_update_cmds {
+ USB_PD_FW_REBOOT,
+ USB_PD_FW_FLASH_ERASE,
+ USB_PD_FW_FLASH_WRITE,
+ USB_PD_FW_FLASH_HASH,
+};
+
+struct ec_params_usb_pd_fw_update {
+ uint8_t cmd;
+ uint8_t dev_id;
+ uint8_t port;
+ uint8_t reserved; /* reserved */
+ uint32_t size; /* Size to write in bytes */
+ /* Followed by data to write */
+} __packed;
+
+
/*****************************************************************************/
/*
* Passthru commands
diff --git a/include/sha1.h b/include/sha1.h
index 152c5757d7..79ede0206a 100644
--- a/include/sha1.h
+++ b/include/sha1.h
@@ -9,7 +9,12 @@
#define _SHA1_H
#include "common.h"
+#ifdef HOST_TOOLS_BUILD
+#include <string.h>
+#define DIV_ROUND_UP(x, y) (((x) + ((y) - 1)) / (y))
+#else
#include "util.h"
+#endif
#define SHA1_DIGEST_SIZE 20
#define SHA1_BLOCK_SIZE 64
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 3afef69d1a..83fee88cf0 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -301,7 +301,8 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload);
* @param data Pointer to payload to send
* @param data number of data objects in payload
*/
-void pd_send_vdm(int port, uint32_t vid, int cmd, uint32_t *data, int count);
+void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
+ int count);
/* Power Data Objects for the source and the sink */
extern const uint32_t pd_src_pdo[];
diff --git a/util/build.mk b/util/build.mk
index 0cd5cbecc8..f0e3c6c17e 100644
--- a/util/build.mk
+++ b/util/build.mk
@@ -16,7 +16,7 @@ comm-objs+=comm-lpc.o
else
comm-objs+=comm-i2c.o
endif
-ectool-objs=ectool.o ectool_keyscan.o misc_util.o ec_flash.o $(comm-objs)
+ectool-objs=ectool.o ectool_keyscan.o misc_util.o ec_flash.o $(comm-objs) ../common/sha1.o
lbplay-objs=lbplay.o $(comm-objs)
burn_my_ec-objs=ec_flash.o $(comm-objs) misc_util.o
diff --git a/util/ectool.c b/util/ectool.c
index 4e2f9ff1f2..8f722f974d 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -22,6 +22,7 @@
#include "lock/gec_lock.h"
#include "misc_util.h"
#include "panic.h"
+#include "sha1.h"
/* Command line options */
enum {
@@ -93,6 +94,8 @@ const char help_str[] =
" Erases EC flash\n"
" flashinfo\n"
" Prints information on the EC flash\n"
+ " flashpd\n"
+ " Flash commands over PD\n"
" flashprotect [now] [enable | disable]\n"
" Prints or sets EC flash protection state\n"
" flashread <offset> <size> <outfile>\n"
@@ -775,6 +778,132 @@ int cmd_flash_protect(int argc, char *argv[])
return 0;
}
+/* PD image size is 16k minus 32 bits for the RW hash */
+#define PD_RW_IMAGE_SIZE (16 * 1024 - 32)
+static struct sha1_ctx ctx;
+int cmd_flash_pd(int argc, char *argv[])
+{
+ struct ec_params_usb_pd_fw_update *p =
+ (struct ec_params_usb_pd_fw_update *)ec_outbuf;
+ int i;
+ int rv, fsize, step = 96, padding_size;
+ char *e;
+ char *buf, *fw_padding;
+ uint32_t *data = &(p->size) + 1;
+
+ if (argc < 4) {
+ fprintf(stderr, "Usage: %s <dev_id> <port> <filename>\n",
+ argv[0]);
+ return -1;
+ }
+
+ p->dev_id = strtol(argv[1], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad device ID\n");
+ return -1;
+ }
+
+ p->port = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad port\n");
+ return -1;
+ }
+
+ /* Read the input file */
+ buf = read_file(argv[3], &fsize);
+ if (!buf)
+ return -1;
+
+ /* Verify size of file */
+ if (fsize > PD_RW_IMAGE_SIZE)
+ goto pd_flash_error;
+
+ /* Add padding to image */
+ padding_size = PD_RW_IMAGE_SIZE - fsize;
+ fw_padding = (char *)malloc(padding_size);
+ memset(fw_padding, 0xff, padding_size);
+ fprintf(stderr, "File size %d, Padding size %d\n", fsize, padding_size);
+
+ /* Write expected flash hash to all 0s */
+ fprintf(stderr, "Erasing expected RW hash\n");
+ p->cmd = USB_PD_FW_FLASH_HASH;
+ p->size = 20;
+ for (i = 0; i < 5; i++)
+ *(data + i) = 0;
+ rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0,
+ p, p->size + sizeof(*p), NULL, 0);
+
+ if (rv < 0)
+ goto pd_flash_error;
+
+ /* Reboot */
+ fprintf(stderr, "Rebooting\n");
+ p->cmd = USB_PD_FW_REBOOT;
+ p->size = 0;
+ rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0,
+ p, p->size + sizeof(*p), NULL, 0);
+
+ if (rv < 0)
+ goto pd_flash_error;
+
+ /* Erase RW flash */
+ fprintf(stderr, "Erasing RW flash\n");
+ p->cmd = USB_PD_FW_FLASH_ERASE;
+ p->size = 0;
+ rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0,
+ p, p->size + sizeof(*p), NULL, 0);
+
+ if (rv < 0)
+ goto pd_flash_error;
+
+ /* Write RW flash */
+ fprintf(stderr, "Writing RW flash\n");
+ p->cmd = USB_PD_FW_FLASH_WRITE;
+ p->size = step;
+
+ for (i = 0; i < fsize; i += step) {
+ p->size = MIN(fsize - i, step);
+ memcpy(data, buf + i, p->size);
+ rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0,
+ p, p->size + sizeof(*p), NULL, 0);
+ if (rv < 0)
+ goto pd_flash_error;
+ }
+
+ /*
+ * TODO(crosbug.com/p/31552): Would be better to have sha1 in the RW
+ * binary and we won't have to calculate it here and send it down.
+ */
+ /* Calculate sha1 of new RW flash */
+ sha1_init(&ctx);
+ sha1_update(&ctx, buf, fsize);
+ sha1_update(&ctx, fw_padding, padding_size);
+ sha1_final(&ctx);
+
+ /* Write expected flash hash */
+ fprintf(stderr, "Setting expected RW hash\n");
+ p->cmd = USB_PD_FW_FLASH_HASH;
+ p->size = 20;
+ memcpy(data, ctx.buf.b, p->size);
+ for (i = 0; i < 5; i++)
+ fprintf(stderr, "%08x ", *(data + i));
+ fprintf(stderr, "\n");
+ rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0,
+ p, p->size + sizeof(*p), NULL, 0);
+
+ if (rv < 0)
+ goto pd_flash_error;
+
+ free(buf);
+ fprintf(stderr, "Complete\n");
+ return 0;
+
+pd_flash_error:
+ free(buf);
+ fprintf(stderr, "PD flash error\n");
+ return -1;
+}
+
int cmd_serial_test(int argc, char *argv[])
{
@@ -4570,6 +4699,7 @@ const struct command commands[] = {
{"flashread", cmd_flash_read},
{"flashwrite", cmd_flash_write},
{"flashinfo", cmd_flash_info},
+ {"flashpd", cmd_flash_pd},
{"gpioget", cmd_gpio_get},
{"gpioset", cmd_gpio_set},
{"hangdetect", cmd_hang_detect},