summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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},