From 4246bfa62f2c4ab273ade29101c46937ca720dae Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Sat, 9 Apr 2016 20:52:35 -0700 Subject: [PATCH] Cr50: New usb_upgrade module for RW updates This re-factors the existing firmware upgrade facility, which worked as a TPM command extension. The same code processing upgrade blocks prepended by the truncated SHA1 and the load address is now used by both extended TPM command and the USB upgrader. To accommodate USB communications using a smaller message payloads a reassembly layer is introduced which accumulates short USB payloads into a single block which can be passed to the firmware upgrade routine. USB encapsulation adds one 4 byte header at the beginning of the block to hold the total block size. The reassembly layer keeps receiving USB messages, concatenating their payloads until the full block is received. A config option is added to make sure the module is not compiled when not needed. BUG=chrome-os-partner:50707 BRANCH=none TEST=make buildall; test on Cr50 - with the rest of the patches applied it is possible to upgrade firmware using the USB utility on the host.. Change-Id: Ib30b381c4ab196ea9d352f3c6b8f46dc23ddd599 Signed-off-by: Bill Richardson Signed-off-by: Vadim Bendebury Reviewed-on: https://chromium-review.googlesource.com/338087 --- board/cr50/board.c | 1 + board/cr50/board.h | 5 + board/cr50/tpm2/upgrade.c | 180 +---------------------------- chip/g/build.mk | 1 + chip/g/upgrade_fw.c | 185 ++++++++++++++++++++++++++++++ chip/g/upgrade_fw.h | 15 +++ chip/g/usb_upgrade.c | 230 ++++++++++++++++++++++++++++++++++++++ chip/g/usb_upgrade.h | 14 +++ include/config.h | 4 + 9 files changed, 456 insertions(+), 179 deletions(-) create mode 100644 chip/g/upgrade_fw.c create mode 100644 chip/g/upgrade_fw.h create mode 100644 chip/g/usb_upgrade.c create mode 100644 chip/g/usb_upgrade.h diff --git a/board/cr50/board.c b/board/cr50/board.c index 702e35f84d..acb30c94c5 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -118,6 +118,7 @@ const void * const usb_strings[] = { [USB_STR_HID_NAME] = USB_STRING_DESC("PokeyPokey"), [USB_STR_AP_NAME] = USB_STRING_DESC("AP"), [USB_STR_EC_NAME] = USB_STRING_DESC("EC"), + [USB_STR_UPGRADE_NAME] = USB_STRING_DESC("Firmware upgrade"), }; BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT); #endif diff --git a/board/cr50/board.h b/board/cr50/board.h index 07cc8cc49e..54726c9227 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -73,6 +73,7 @@ enum usb_strings { USB_STR_HID_NAME, USB_STR_AP_NAME, USB_STR_EC_NAME, + USB_STR_UPGRADE_NAME, USB_STR_COUNT }; @@ -119,4 +120,8 @@ enum usb_strings { */ #define CONFIG_DEBUG_STACK_OVERFLOW #define CONFIG_RW_B + +/* Firmware upgrade options. */ +#define CONFIG_NON_HC_FW_UPDATE + #endif /* __CROS_EC_BOARD_H */ diff --git a/board/cr50/tpm2/upgrade.c b/board/cr50/tpm2/upgrade.c index dcc7acf631..b5d3692467 100644 --- a/board/cr50/tpm2/upgrade.c +++ b/board/cr50/tpm2/upgrade.c @@ -3,185 +3,7 @@ * found in the LICENSE file. */ -#include "byteorder.h" -#include "console.h" -#include "dcrypto/dcrypto.h" #include "extension.h" -#include "flash.h" -#include "hooks.h" -#include "include/compile_time_macros.h" -#include "sha1.h" -#include "uart.h" - -#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args) - -/* Various upgrade extension command return values. */ -enum return_value { - UPGRADE_SUCCESS = 0, - UPGRADE_BAD_ADDR = 1, - UPGRADE_ERASE_FAILURE = 2, - UPGRADE_DATA_ERROR = 3, - UPGRADE_WRITE_FAILURE = 4, - UPGRADE_VERIFY_ERROR = 5, - UPGRADE_GEN_ERROR = 6, -}; - -/* - * The payload of the upgrade command. (Integer values in network byte order). - * - * block digest: the first four bytes of the sha1 digest of the rest of the - * structure. - * block_base: address where this block needs to be written to. - * block_body: variable size data to written at address 'block_base'. - */ -struct upgrade_command { - uint32_t block_digest; - uint32_t block_base; - uint8_t block_body[0]; -} __packed; - -/* - * This array defines two possibe sections available for the firmare update. - * The section whcih does not map the current execting code is picked as the - * valid update area. The values are offsets into the flash space. - */ -const struct section_descriptor { - uint32_t sect_base_offset; - uint32_t sect_top_offset; -} rw_sections[] = { - {CONFIG_RW_MEM_OFF, - CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE}, - {CONFIG_RW_B_MEM_OFF, - CONFIG_RW_B_MEM_OFF + CONFIG_RW_SIZE} -}; - -const struct section_descriptor *valid_section; - -/* Pick the section where updates can go to based on current code address. */ -static void set_valid_section(void) -{ - int i; - uint32_t run_time_offs = (uint32_t) set_valid_section - - CONFIG_PROGRAM_MEMORY_BASE; - - for (i = 0; i < ARRAY_SIZE(rw_sections); i++) { - if ((run_time_offs > rw_sections[i].sect_base_offset) && - (run_time_offs < rw_sections[i].sect_top_offset)) - continue; - valid_section = rw_sections + i; - break; - } -} - -/* Verify that the passed in block fits into the valid area. */ -static int valid_upgrade_chunk(uint32_t block_offset, size_t body_size) -{ - if (valid_section && - (block_offset >= valid_section->sect_base_offset) && - ((block_offset + body_size) < valid_section->sect_top_offset)) - return 1; - - return 0; -} - -static void fw_upgrade_command_handler(void *body, - size_t cmd_size, - size_t *response_size) -{ - struct upgrade_command *cmd_body = body; - uint8_t *rv = body; - uint8_t sha1_digest[SHA1_DIGEST_SIZE]; - size_t body_size; - uint32_t block_offset; - - /* - * A single byte response, unless this is the first message in the - * programming sequence. - */ - *response_size = sizeof(*rv); - - body_size = cmd_size - offsetof(struct upgrade_command, block_body); - if (body_size < 0) { - CPRINTF("%s:%d\n", __func__, __LINE__); - *rv = UPGRADE_GEN_ERROR; - return; - } - - if (!cmd_body->block_base && !body_size) { - /* - * This is the first message of the upgrade process, let's - * determine the valid upgrade section and erase its contents. - */ - set_valid_section(); - - if (flash_physical_erase(valid_section->sect_base_offset, - valid_section->sect_top_offset - - valid_section->sect_base_offset)) { - CPRINTF("%s:%d erase failure of 0x%x..+0x%x\n", - __func__, __LINE__, - valid_section->sect_base_offset, - valid_section->sect_top_offset - - valid_section->sect_base_offset); - *rv = UPGRADE_ERASE_FAILURE; - return; - } - /* - * Successful erase means that we need to return the base - * address of the section to be programmed with the upgrade. - */ - *(uint32_t *)body = htobe32(valid_section->sect_base_offset + - CONFIG_PROGRAM_MEMORY_BASE); - *response_size = sizeof(uint32_t); - return; - } - - /* Check if the block will fit into the valid area. */ - block_offset = be32toh(cmd_body->block_base) - - CONFIG_PROGRAM_MEMORY_BASE; - if (!valid_upgrade_chunk(block_offset, body_size)) { - *rv = UPGRADE_BAD_ADDR; - CPRINTF("%s:%d %x, %d base %x top %x\n", __func__, __LINE__, - block_offset, body_size, - valid_section->sect_base_offset, - valid_section->sect_top_offset); - return; - } - - /* Check if the block was received properly. */ - DCRYPTO_SHA1_hash((uint8_t *)&cmd_body->block_base, - body_size + sizeof(cmd_body->block_base), - sha1_digest); - if (memcmp(sha1_digest, &cmd_body->block_digest, - sizeof(cmd_body->block_digest))) { - *rv = UPGRADE_DATA_ERROR; - CPRINTF("%s:%d sha1 %x not equal received %x at offs. 0x%x\n", - __func__, __LINE__, - *(uint32_t *)sha1_digest, cmd_body->block_digest, - block_offset); - return; - } - - CPRINTF("%s: programming at address 0x%x\n", __func__, - block_offset + CONFIG_PROGRAM_MEMORY_BASE); - if (flash_physical_write(block_offset, body_size, - cmd_body->block_body) != EC_SUCCESS) { - *rv = UPGRADE_WRITE_FAILURE; - CPRINTF("%s:%d upgrade write error\n", - __func__, __LINE__); - return; - } - - /* Werify that data was written properly. */ - if (memcmp(cmd_body->block_body, (void *) - (block_offset + CONFIG_PROGRAM_MEMORY_BASE), - body_size)) { - *rv = UPGRADE_VERIFY_ERROR; - CPRINTF("%s:%d upgrade verification error\n", - __func__, __LINE__); - return; - } - - *rv = UPGRADE_SUCCESS; -} +#include "upgrade_fw.h" DECLARE_EXTENSION_COMMAND(EXTENSION_FW_UPGRADE, fw_upgrade_command_handler); diff --git a/chip/g/build.mk b/chip/g/build.mk index 959a0f51cf..e4a7d60fa8 100644 --- a/chip/g/build.mk +++ b/chip/g/build.mk @@ -40,6 +40,7 @@ chip-$(CONFIG_SPI_MASTER)+=spi_master.o chip-y+= pmu.o chip-y+= trng.o +chip-$(CONFIG_NON_HC_FW_UPDATE)+= upgrade_fw.o chip-$(CONFIG_SPS)+= sps.o chip-$(CONFIG_TPM_SPS)+=sps_tpm.o chip-$(CONFIG_WATCHDOG)+=watchdog.o diff --git a/chip/g/upgrade_fw.c b/chip/g/upgrade_fw.c new file mode 100644 index 0000000000..fc6ca50850 --- /dev/null +++ b/chip/g/upgrade_fw.c @@ -0,0 +1,185 @@ +/* Copyright 2016 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. + */ + +#include "byteorder.h" +#include "console.h" +#include "dcrypto/dcrypto.h" +#include "extension.h" +#include "flash.h" +#include "hooks.h" +#include "include/compile_time_macros.h" +#include "sha1.h" +#include "uart.h" + +#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args) + +/* Various upgrade extension command return values. */ +enum return_value { + UPGRADE_SUCCESS = 0, + UPGRADE_BAD_ADDR = 1, + UPGRADE_ERASE_FAILURE = 2, + UPGRADE_DATA_ERROR = 3, + UPGRADE_WRITE_FAILURE = 4, + UPGRADE_VERIFY_ERROR = 5, + UPGRADE_GEN_ERROR = 6, +}; + +/* + * The payload of the upgrade command. (Integer values in network byte order). + * + * block digest: the first four bytes of the sha1 digest of the rest of the + * structure. + * block_base: address where this block needs to be written to. + * block_body: variable size data to written at address 'block_base'. + */ +struct upgrade_command { + uint32_t block_digest; + uint32_t block_base; + uint8_t block_body[0]; +} __packed; + +/* + * This array defines two possibe sections available for the firmare update. + * The section whcih does not map the current execting code is picked as the + * valid update area. The values are offsets into the flash space. + */ +const struct section_descriptor { + uint32_t sect_base_offset; + uint32_t sect_top_offset; +} rw_sections[] = { + {CONFIG_RW_MEM_OFF, + CONFIG_RW_MEM_OFF + CONFIG_RW_SIZE}, + {CONFIG_RW_B_MEM_OFF, + CONFIG_RW_B_MEM_OFF + CONFIG_RW_SIZE} +}; + +const struct section_descriptor *valid_section; + +/* Pick the section where updates can go to based on current code address. */ +static void set_valid_section(void) +{ + int i; + uint32_t run_time_offs = (uint32_t) set_valid_section - + CONFIG_PROGRAM_MEMORY_BASE; + + for (i = 0; i < ARRAY_SIZE(rw_sections); i++) { + if ((run_time_offs > rw_sections[i].sect_base_offset) && + (run_time_offs < rw_sections[i].sect_top_offset)) + continue; + valid_section = rw_sections + i; + break; + } +} + +/* Verify that the passed in block fits into the valid area. */ +static int valid_upgrade_chunk(uint32_t block_offset, size_t body_size) +{ + if (valid_section && + (block_offset >= valid_section->sect_base_offset) && + ((block_offset + body_size) < valid_section->sect_top_offset)) + return 1; + + return 0; +} + +void fw_upgrade_command_handler(void *body, + size_t cmd_size, + size_t *response_size) +{ + struct upgrade_command *cmd_body = body; + uint8_t *rv = body; + uint8_t sha1_digest[SHA1_DIGEST_SIZE]; + size_t body_size; + uint32_t block_offset; + + /* + * A single byte response, unless this is the first message in the + * programming sequence. + */ + *response_size = sizeof(*rv); + + body_size = cmd_size - offsetof(struct upgrade_command, block_body); + if (body_size < 0) { + CPRINTF("%s:%d\n", __func__, __LINE__); + *rv = UPGRADE_GEN_ERROR; + return; + } + + if (!cmd_body->block_base && !body_size) { + /* + * This is the first message of the upgrade process, let's + * determine the valid upgrade section and erase its contents. + */ + set_valid_section(); + + if (flash_physical_erase(valid_section->sect_base_offset, + valid_section->sect_top_offset - + valid_section->sect_base_offset)) { + CPRINTF("%s:%d erase failure of 0x%x..+0x%x\n", + __func__, __LINE__, + valid_section->sect_base_offset, + valid_section->sect_top_offset - + valid_section->sect_base_offset); + *rv = UPGRADE_ERASE_FAILURE; + return; + } + /* + * Successful erase means that we need to return the base + * address of the section to be programmed with the upgrade. + */ + *(uint32_t *)body = htobe32(valid_section->sect_base_offset + + CONFIG_PROGRAM_MEMORY_BASE); + *response_size = sizeof(uint32_t); + return; + } + + /* Check if the block will fit into the valid area. */ + block_offset = be32toh(cmd_body->block_base) - + CONFIG_PROGRAM_MEMORY_BASE; + if (!valid_upgrade_chunk(block_offset, body_size)) { + *rv = UPGRADE_BAD_ADDR; + CPRINTF("%s:%d %x, %d base %x top %x\n", __func__, __LINE__, + block_offset, body_size, + valid_section->sect_base_offset, + valid_section->sect_top_offset); + return; + } + + /* Check if the block was received properly. */ + DCRYPTO_SHA1_hash((uint8_t *)&cmd_body->block_base, + body_size + sizeof(cmd_body->block_base), + sha1_digest); + if (memcmp(sha1_digest, &cmd_body->block_digest, + sizeof(cmd_body->block_digest))) { + *rv = UPGRADE_DATA_ERROR; + CPRINTF("%s:%d sha1 %x not equal received %x at offs. 0x%x\n", + __func__, __LINE__, + *(uint32_t *)sha1_digest, cmd_body->block_digest, + block_offset); + return; + } + + CPRINTF("%s: programming at address 0x%x\n", __func__, + block_offset + CONFIG_PROGRAM_MEMORY_BASE); + if (flash_physical_write(block_offset, body_size, + cmd_body->block_body) != EC_SUCCESS) { + *rv = UPGRADE_WRITE_FAILURE; + CPRINTF("%s:%d upgrade write error\n", + __func__, __LINE__); + return; + } + + /* Werify that data was written properly. */ + if (memcmp(cmd_body->block_body, (void *) + (block_offset + CONFIG_PROGRAM_MEMORY_BASE), + body_size)) { + *rv = UPGRADE_VERIFY_ERROR; + CPRINTF("%s:%d upgrade verification error\n", + __func__, __LINE__); + return; + } + + *rv = UPGRADE_SUCCESS; +} diff --git a/chip/g/upgrade_fw.h b/chip/g/upgrade_fw.h new file mode 100644 index 0000000000..1e6c595fb7 --- /dev/null +++ b/chip/g/upgrade_fw.h @@ -0,0 +1,15 @@ +/* Copyright 2016 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. + */ + +#ifndef __EC_CHIP_G_UPGRADE_FW_H +#define __EC_CHIP_G_UPGRADE_FW_H + +#include + +void fw_upgrade_command_handler(void *body, + size_t cmd_size, + size_t *response_size); + +#endif /* ! __EC_CHIP_G_UPGRADE_FW_H */ diff --git a/chip/g/usb_upgrade.c b/chip/g/usb_upgrade.c new file mode 100644 index 0000000000..54e4fb6d1c --- /dev/null +++ b/chip/g/usb_upgrade.c @@ -0,0 +1,230 @@ +/* Copyright 2016 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. + */ + +#include "byteorder.h" +#include "common.h" +#include "console.h" +#include "consumer.h" +#include "queue_policies.h" +#include "shared_mem.h" +#include "system.h" +#include "upgrade_fw.h" +#include "usb-stream.h" +#include "usb_upgrade.h" + +#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) + +/* + * This file is an adaptation layer between the USB interface and the firmware + * update engine. The engine expects to receive long blocks of data, 1K or so + * in size, prepended by the offset where the data needs to be programmed into + * the flash and a 4 byte integrity check value. + * + * The USB transfer, on the other hand, operates on much shorter chunks of + * data, typically 64 bytes in this case. This module reassembles firmware + * programming blocks from the USB chunks, and invokes the programmer passing + * it the full block. + * + * The programmer reports results by putting the return value of one or four + * bytes into the same buffer where the block was passed in. This wrapper + * retrieves the programmer's return value, normalizes it to 4 bytes and sends + * it back to the host. + * + * In the end of the successful image transfer and programming, the host send + * the reset command, and the device reboots itself. + */ + +struct consumer const upgrade_consumer; +struct usb_stream_config const usb_upgrade; + +static struct queue const upgrade_to_usb = QUEUE_DIRECT(64, uint8_t, + null_producer, + usb_upgrade.consumer); +static struct queue const usb_to_upgrade = QUEUE_DIRECT(64, uint8_t, + usb_upgrade.producer, + upgrade_consumer); + +USB_STREAM_CONFIG_FULL(usb_upgrade, + USB_IFACE_UPGRADE, + USB_CLASS_VENDOR_SPEC, + UNOFFICIAL_USB_SUBCLASS_GOOGLE_CR50, + 0xff, /* vendor-specific protocol */ + USB_STR_UPGRADE_NAME, + USB_EP_UPGRADE, + USB_MAX_PACKET_SIZE, + USB_MAX_PACKET_SIZE, + usb_to_upgrade, + upgrade_to_usb) + + +/* The receiver can be in one of the states below. */ +enum rx_state { + rx_idle, /* Nothing happened yet. */ + rx_inside_block, /* Assembling a block to pass to the programmer. */ + rx_outside_block, /* Waiting for the next block to start or for the + reset command. */ + rx_awaiting_reset /* Waiting for reset confirmation. */ +}; + +/* This is the format of the header the programmer expects. */ +struct upgrade_command { + uint32_t block_digest; /* first 4 bytes of sha1 of the rest of the + block. */ + uint32_t block_base; /* Offset of this block into the flash SPI. */ +}; + +/* This is the format of the header the host uses. */ +struct update_pdu_header { + uint32_t block_size; /* Total size of the block, including this + field. */ + union { + struct upgrade_command cmd; + uint32_t resp; /* The programmer puts response to the same + buffer where the command was. */ + }; + /* The actual payload goes here. */ +}; + +enum rx_state rx_state_ = rx_idle; +static uint8_t *block_buffer; +static uint32_t block_size; +static uint32_t block_index; + +/* Called to deal with data from the host */ +static void upgrade_out_handler(struct consumer const *consumer, size_t count) +{ + struct update_pdu_header updu; + size_t resp_size; + uint32_t resp_value; + + if (rx_state_ == rx_idle) { + /* This better be the first block, of zero size. */ + if (count != sizeof(struct update_pdu_header)) { + CPRINTS("FW update: wrong first block size %d\n", + count); + return; + } + QUEUE_REMOVE_UNITS(consumer->queue, &updu, count); + + CPRINTS("FW update: starting...\n"); + + fw_upgrade_command_handler(&updu.cmd, count - + offsetof(struct update_pdu_header, + cmd), + &resp_size); + + if (resp_size == 4) { + resp_value = updu.resp; /* Already in network order. */ + rx_state_ = rx_outside_block; + } else { + /* This must be a single byte error code. */ + resp_value = htobe32(*((uint8_t *)&updu.resp)); + } + /* Let the host know what upgrader had to say. */ + QUEUE_ADD_UNITS(&upgrade_to_usb, &resp_value, + sizeof(resp_value)); + return; + } + + if (rx_state_ == rx_awaiting_reset) { + /* + * Any USB data received in this state triggers reset, no + * response required. + */ + CPRINTS("reboot hard"); + cflush(); + system_reset(SYSTEM_RESET_HARD); + while (1) + ; + } + + if (rx_state_ == rx_outside_block) { + /* + * Expecting to receive the beginning of the block or the + * reset command if all data blocks have been processed. + */ + if (count == 4) { + uint32_t command; + + QUEUE_REMOVE_UNITS(consumer->queue, &command, + sizeof(command)); + command = be32toh(command); + if (command == UPGRADE_DONE) { + CPRINTS("FW update: done\n"); + resp_value = 0; + QUEUE_ADD_UNITS(&upgrade_to_usb, &resp_value, + sizeof(resp_value)); + rx_state_ = rx_awaiting_reset; + return; + } + } + + if (count < sizeof(updu)) { + CPRINTS("FW update: error: first chunk of %d bytes\n", + count); + rx_state_ = rx_idle; + return; + } + + QUEUE_REMOVE_UNITS(consumer->queue, &updu, sizeof(updu)); + + /* Let's allocate a large enough buffer. */ + block_size = be32toh(updu.block_size) - + offsetof(struct update_pdu_header, cmd); + if (shared_mem_acquire(block_size, (char **)&block_buffer) + != EC_SUCCESS) { + /* TODO:(vbendeb) report out of memory here. */ + CPRINTS("FW update: error: failed to alloc %d bytes.\n", + block_size); + return; + } + + /* + * Copy the rest of the message into the block buffer to pass + * to the upgrader. + */ + block_index = sizeof(updu) - + offsetof(struct update_pdu_header, cmd); + memcpy(block_buffer, &updu.cmd, block_index); + QUEUE_REMOVE_UNITS(consumer->queue, + block_buffer + block_index, + count - sizeof(updu)); + block_index += count - sizeof(updu); + block_size -= block_index; + rx_state_ = rx_inside_block; + return; + } + + /* Must be inside block. */ + QUEUE_REMOVE_UNITS(consumer->queue, block_buffer + block_index, count); + block_index += count; + block_size -= count; + + if (block_size) + return; /* More to come. */ + + /* + * Ok, the enter block has been received and reassembled, pass it to + * the updater for verification and programming. + */ + fw_upgrade_command_handler(block_buffer, block_index, &resp_size); + + shared_mem_release(block_buffer); + resp_value = block_buffer[0]; + QUEUE_ADD_UNITS(&upgrade_to_usb, &resp_value, sizeof(resp_value)); + rx_state_ = rx_outside_block; +} + +static void upgrade_flush(struct consumer const *consumer) +{ +} + +struct consumer const upgrade_consumer = { + .queue = &usb_to_upgrade, + .ops = &((struct consumer_ops const) { + .written = upgrade_out_handler, + .flush = upgrade_flush, + }), +}; diff --git a/chip/g/usb_upgrade.h b/chip/g/usb_upgrade.h new file mode 100644 index 0000000000..7fe25b5895 --- /dev/null +++ b/chip/g/usb_upgrade.h @@ -0,0 +1,14 @@ +/* Copyright 2016 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. + */ + +#ifndef __CROS_EC_USB_UPGRADE_H +#define __CROS_EC_USB_UPGRADE_H + +#define UNOFFICIAL_USB_SUBCLASS_GOOGLE_CR50 0x53 + +/* Commands from host */ +#define UPGRADE_DONE 0xB007AB1E + +#endif /* __CROS_EC_USB_UPGRADE_H */ diff --git a/include/config.h b/include/config.h index d31270008f..2d5cac6189 100644 --- a/include/config.h +++ b/include/config.h @@ -2085,6 +2085,10 @@ #undef CONFIG_RO_HEAD_ROOM #undef CONFIG_RW_HEAD_ROOM +/* Firmware upgrade options. */ +/* Firmware updates using other than HC channel(s). */ +#undef CONFIG_NON_HC_FW_UPDATE + /*****************************************************************************/ /* * Include board and core configs, since those hold the CONFIG_ constants for a