Tim Wawrzynczak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/36207 )
Change subject: ec/google/chromeec: Add EC driver support for software sync ......................................................................
ec/google/chromeec: Add EC driver support for software sync
Quite a few new functions added here in order to support the use-case of performing EC software sync within coreboot.
Most of these functions are related to retrieving the EC's hash, and writing a new image into the EC's flash.
BUG=b:112198832 BRANCH=none TEST=With whole patch series, successfully performed EC software sync
Change-Id: I0d3c5184dbe96f04b92878f2c19c7875503a910a Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org --- M src/ec/google/chromeec/ec.c M src/ec/google/chromeec/ec.h 2 files changed, 333 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/07/36207/1
diff --git a/src/ec/google/chromeec/ec.c b/src/ec/google/chromeec/ec.c index 7c294b6..0c9f3ab 100644 --- a/src/ec/google/chromeec/ec.c +++ b/src/ec/google/chromeec/ec.c @@ -33,6 +33,7 @@ #include "ec_commands.h"
#define INVALID_HCMD 0xFF +#define EC_VER_MASK(version) BIT(version)
/* * Map UHEPI masks to non UHEPI commands in order to support old EC FW @@ -498,6 +499,299 @@ return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature); }
+int google_chromeec_get_cmd_versions(int command, uint32_t *pmask) +{ + struct chromeec_command cmd; + struct ec_params_get_cmd_versions_v1 params = { + .cmd = command, + }; + struct ec_response_get_cmd_versions resp; + + *pmask = 0; + + cmd.cmd_code = EC_CMD_GET_CMD_VERSIONS; + cmd.cmd_version = 1; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(resp); + cmd.cmd_data_out = &resp; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + *pmask = resp.version_mask; + return 0; +} + +/** + * Return non-zero if the EC supports the command and version + * + * @param cmd Command to check + * @param ver Version to check + * @return non-zero if command version supported; 0 if not. + */ +static int cmd_version_supported(int cmd, int ver) +{ + uint32_t mask = 0; + + if (google_chromeec_get_cmd_versions(cmd, &mask)) + return 0; + + return (mask & EC_VER_MASK(ver)) ? 1 : 0; +} + +int google_chromeec_get_vboot_hash(u32 offset, + struct ec_response_vboot_hash *resp) +{ + struct chromeec_command cmd; + struct ec_params_vboot_hash params = { + .cmd = EC_VBOOT_HASH_GET, + .offset = offset, + }; + + cmd.cmd_code = EC_CMD_VBOOT_HASH; + cmd.cmd_version = 0; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(*resp); + cmd.cmd_data_out = resp; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + return 0; +} + +int google_chromeec_start_vboot_hash(enum ec_vboot_hash_type hash_type, + u32 hash_offset, + struct ec_response_vboot_hash *resp) +{ + struct chromeec_command cmd; + struct ec_params_vboot_hash params = { + .cmd = EC_VBOOT_HASH_START, + .hash_type = hash_type, + .nonce_size = 0, + .offset = hash_offset, + }; + + cmd.cmd_code = EC_CMD_VBOOT_HASH; + cmd.cmd_version = 0; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(*resp); + cmd.cmd_data_out = resp; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + return 0; +} + +int google_chromeec_flash_protect(u32 mask, u32 flags, + struct ec_response_flash_protect *resp) +{ + struct chromeec_command cmd; + struct ec_params_flash_protect params = { + .mask = mask, + .flags = flags, + }; + + cmd.cmd_code = EC_CMD_FLASH_PROTECT; + cmd.cmd_version = EC_VER_FLASH_PROTECT; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(*resp); + cmd.cmd_data_out = resp; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + return 0; +} + +int google_chromeec_flash_region_info(enum ec_flash_region region, u32 *offset, + u32 *size) +{ + struct chromeec_command cmd; + struct ec_params_flash_region_info params = { + .region = region, + }; + struct ec_response_flash_region_info resp; + + cmd.cmd_code = EC_CMD_FLASH_REGION_INFO; + cmd.cmd_version = EC_VER_FLASH_REGION_INFO; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(resp); + cmd.cmd_data_out = &resp; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + if (offset) + *offset = resp.offset; + if (size) + *size = resp.size; + + return 0; +} + +int google_chromeec_flash_erase(u32 region_offset, u32 region_size) +{ + struct chromeec_command cmd; + struct ec_params_flash_erase params = { + .offset = region_offset, + .size = region_size, + }; + + cmd.cmd_code = EC_CMD_FLASH_ERASE; + cmd.cmd_version = 0; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = 0; + cmd.cmd_data_out = NULL; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + return 0; +} + +int google_chromeec_flash_info(struct ec_response_flash_info *info) +{ + struct chromeec_command cmd; + + cmd.cmd_code = EC_CMD_FLASH_INFO; + cmd.cmd_version = 0; + cmd.cmd_size_in = 0; + cmd.cmd_data_in = NULL; + cmd.cmd_size_out = sizeof(*info); + cmd.cmd_data_out = info; + cmd.cmd_dev_index = 0; + + if (google_chromeec_command(&cmd) != 0) + return -1; + + return 0; +} + +int google_chromeec_flash_write_burst_size(void) +{ + struct ec_response_flash_info info; + uint32_t pdata_max_size = (EC_LPC_HOST_PACKET_SIZE - + sizeof(struct ec_params_flash_write)) - + sizeof(struct ec_host_request); + + /* + * Determine whether we can use version 1 of the command with more + * data, or only version 0. + */ + if (!cmd_version_supported(EC_CMD_FLASH_WRITE, EC_VER_FLASH_WRITE)) + return EC_FLASH_WRITE_VER0_SIZE; + + /* + * Determine step size. This must be a multiple of the write block + * size, and must also fit into the host parameter buffer. + */ + if (google_chromeec_flash_info(&info)) + return 0; + + return (pdata_max_size / info.write_block_size) * info.write_block_size; +} + +/* Write a block into EC flash */ +int google_chromeec_flash_write_block(const u8 *data, u32 offset, u32 size) +{ + uint8_t *buf; + struct ec_params_flash_write *p; + uint32_t bufsize = sizeof(*p) + size; + int rv; + struct chromeec_command cmd; + + assert(data); + + /* Make sure request fits in the allowed packet size */ + if (bufsize > EC_LPC_HOST_PACKET_SIZE) + return -1; + + buf = crosec_get_buffer(bufsize, 0); + if (buf == NULL) + return -1; + + p = (struct ec_params_flash_write *)buf; + p->offset = offset; + p->size = size; + memcpy(p + 1, data, size); + + cmd.cmd_code = EC_CMD_FLASH_WRITE; + cmd.cmd_version = EC_VER_FLASH_WRITE; + cmd.cmd_size_in = bufsize; + cmd.cmd_data_in = buf; + cmd.cmd_size_out = 0; + cmd.cmd_data_out = NULL; + cmd.cmd_dev_index = 0; + + rv = google_chromeec_command(&cmd); + + return rv; +} + +/* EFS verification of flash */ +int google_chromeec_efs_verify(enum ec_flash_region region) +{ + struct chromeec_command cmd; + struct ec_params_efs_verify params = { + .region = region, + }; + int rv; + + cmd.cmd_code = EC_CMD_EFS_VERIFY; + cmd.cmd_version = 0; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = 0; + cmd.cmd_data_out = NULL; + cmd.cmd_dev_index = 0; + + /* It's okay if the EC doesn't support EFS */ + rv = google_chromeec_command(&cmd); + if (rv != 0 && (cmd.cmd_code == EC_RES_INVALID_COMMAND)) { + return 0; + } + + return rv; +} + +int google_chromeec_test(void) +{ + struct chromeec_command cmd; + struct ec_params_hello params = { + .in_data = 0x12345678, + }; + struct ec_response_hello resp = {}; + int rv; + + cmd.cmd_code = EC_CMD_HELLO; + cmd.cmd_version = 0; + cmd.cmd_size_in = sizeof(params); + cmd.cmd_data_in = ¶ms; + cmd.cmd_size_out = sizeof(resp); + cmd.cmd_data_out = &resp; + cmd.cmd_dev_index = 0; + + rv = google_chromeec_command(&cmd); + if (rv || (resp.out_data != params.in_data + 0x01020304)) + return -1; + + return 0; +} + int google_chromeec_set_sku_id(u32 skuid) { struct chromeec_command cmd; diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h index 019f9c1..20e5bec 100644 --- a/src/ec/google/chromeec/ec.h +++ b/src/ec/google/chromeec/ec.h @@ -178,4 +178,43 @@ /* Log host events to eventlog based on the mask provided. */ void google_chromeec_log_events(uint64_t mask);
+/* + * The following functions are for vboot EC software sync. + * They return 0 on success, non-zero for failure. + */ + +/* Protect/un-protect EC flash regions */ +int google_chromeec_flash_protect(u32 mask, u32 flags, + struct ec_response_flash_protect *resp); +/* Calculate image hash for vboot */ +int google_chromeec_start_vboot_hash(enum ec_vboot_hash_type hash_type, + u32 offset, + struct ec_response_vboot_hash *resp); +/* Return the vboot image hash */ +int google_chromeec_get_vboot_hash(u32 offset, + struct ec_response_vboot_hash *resp); +/* Get offset and size of the specified flash region */ +int google_chromeec_flash_region_info(enum ec_flash_region region, u32 *offset, + u32 *size); +/* Erase a region of flash */ +int google_chromeec_flash_erase(u32 region_offset, u32 region_size); + +/* Return information about the entire flash */ +int google_chromeec_flash_info(struct ec_response_flash_info *info); + +/* Verify flash using EFS if available */ +int google_chromeec_efs_verify(enum ec_flash_region region); + +/* Get available versions of the specified command */ +int google_chromeec_get_cmd_versions(int command, uint32_t *pmask); + +/* Test if the EC is responding */ +int google_chromeec_test(void); + +/* Get the EC's flash write burst size */ +int google_chromeec_flash_write_burst_size(void); + +/* Write a block into EC flash */ +int google_chromeec_flash_write_block(const u8 *data, u32 offset, u32 size); + #endif /* _EC_GOOGLE_CHROMEEC_EC_H */