diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-08-14 18:31:05 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-08-26 23:06:23 +0000 |
commit | e913bc15b8a631757b362da09fc1385a7f509def (patch) | |
tree | 166afea132ba5e162988cb5346eeb48ba054d1a8 /common | |
parent | b22c10ce2e5d8186cff4623dbf6fb18ee6a62017 (diff) | |
download | chrome-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>
Diffstat (limited to 'common')
-rw-r--r-- | common/host_command.c | 2 | ||||
-rw-r--r-- | common/host_command_master.c | 13 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 83 |
3 files changed, 91 insertions, 7 deletions
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 */ |