From 5691ac816805781a27b5da84cab9c600b77b9dcb Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Wed, 17 Jul 2013 11:09:58 -0700 Subject: Add EC_CMD_GET_FLASH_INFO version 1 This adds two new fields: the ideal write size for best EC flashing performance (e.g., page mode instead of word mode), and a flags field with a flag to indicate whether the EC erases its bits to 0 or 1. The EC still supports the old version 0 command, since u-boot and flashrom expect that to work. BUG=chrome-os-partner:20973 BRANCH=(all haswell); this will speed up flashing and software sync TEST=ectool flashinfo 1. old EC, new ectool -> only reports version 0 info 2. new EC, old ectool -> only reports version 0 info 3. new EC, new ectool -> reports new fields Change-Id: I484327fe22a58d2b69d7f6ac767b2d3e81b3e0b7 Signed-off-by: Randall Spangler Reviewed-on: https://gerrit.chromium.org/gerrit/62378 Reviewed-by: David Hendricks --- chip/host/config_chip.h | 1 + chip/lm4/config_chip.h | 3 +++ chip/stm32/config-stm32f100.h | 4 ++++ chip/stm32/config-stm32f10x.h | 4 ++++ chip/stm32/config-stm32l15x.h | 12 ++++++++++++ common/flash_common.c | 44 ++++++++++++++++++++++++++++++++++++++----- include/ec_commands.h | 32 +++++++++++++++++++++++++++++++ util/ectool.c | 20 ++++++++++++++++++-- 8 files changed, 113 insertions(+), 7 deletions(-) diff --git a/chip/host/config_chip.h b/chip/host/config_chip.h index 44ed02841a..1cbf7710d4 100644 --- a/chip/host/config_chip.h +++ b/chip/host/config_chip.h @@ -17,6 +17,7 @@ extern char __host_flash[CONFIG_FLASH_PHYSICAL_SIZE]; #define CONFIG_FLASH_BANK_SIZE 0x1000 #define CONFIG_FLASH_ERASE_SIZE 0x0400 /* erase bank size */ #define CONFIG_FLASH_WRITE_SIZE 0x0002 /* minimum write size */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE 0x0080 /* ideal write size */ #define CONFIG_RAM_BASE 0x0 /* Not supported */ #define CONFIG_RAM_SIZE 0x0 /* Not supported */ diff --git a/chip/lm4/config_chip.h b/chip/lm4/config_chip.h index 1c7fdfb48b..8d1077f12c 100644 --- a/chip/lm4/config_chip.h +++ b/chip/lm4/config_chip.h @@ -45,6 +45,9 @@ #define CONFIG_FLASH_ERASE_SIZE 0x00000400 /* erase bank size */ #define CONFIG_FLASH_WRITE_SIZE 0x00000004 /* minimum write size */ +/* Ideal flash write size fills the 32-entry flash write buffer */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE (32 * 4) + /* This is the physical size of the flash on the chip. We'll reserve one bank * in order to emulate per-bank write-protection UNTIL REBOOT. The hardware * doesn't support a write-protect pin, and if we make the write-protection diff --git a/chip/stm32/config-stm32f100.h b/chip/stm32/config-stm32f100.h index b23814f4ad..ab4440f34d 100644 --- a/chip/stm32/config-stm32f100.h +++ b/chip/stm32/config-stm32f100.h @@ -10,6 +10,10 @@ #define CONFIG_FLASH_BANK_SIZE 0x1000 #define CONFIG_FLASH_ERASE_SIZE 0x0400 /* erase bank size */ #define CONFIG_FLASH_WRITE_SIZE 0x0002 /* minimum write size */ + +/* No page mode on STM32F, so no benefit to larger write sizes */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE 0x0002 + #define CONFIG_RAM_BASE 0x20000000 #define CONFIG_RAM_SIZE 0x00002000 diff --git a/chip/stm32/config-stm32f10x.h b/chip/stm32/config-stm32f10x.h index 71c512618c..a201f52c4f 100644 --- a/chip/stm32/config-stm32f10x.h +++ b/chip/stm32/config-stm32f10x.h @@ -10,6 +10,10 @@ #define CONFIG_FLASH_BANK_SIZE 0x1000 #define CONFIG_FLASH_ERASE_SIZE 0x0400 /* erase bank size */ #define CONFIG_FLASH_WRITE_SIZE 0x0002 /* minimum write size */ + +/* No page mode on STM32F, so no benefit to larger write sizes */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE 0x0002 + #define CONFIG_RAM_BASE 0x20000000 #define CONFIG_RAM_SIZE (10 * 1024) diff --git a/chip/stm32/config-stm32l15x.h b/chip/stm32/config-stm32l15x.h index c03ff5d8e9..ad3e95e099 100644 --- a/chip/stm32/config-stm32l15x.h +++ b/chip/stm32/config-stm32l15x.h @@ -9,8 +9,20 @@ #define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE #define CONFIG_FLASH_BANK_SIZE 0x1000 #define CONFIG_FLASH_ERASE_SIZE 0x0100 /* erase bank size */ + +/* + * TODO(rspangler): Technically we can write in word-mode (4 bytes at a time), + * but that's really slow, and older host interfaces which can't ask about the + * ideal size would then end up writing in that mode instead of the faster page + * mode. So lie about the write size for now. Once all software (flashrom, + * u-boot, ectool) which cares has been updated to know about ver.1 of + * EC_CMD_GET_FLASH_INFO, we can remove this workaround. + */ #define CONFIG_FLASH_WRITE_SIZE 0x0080 +/* Ideal write size in page-mode */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE 0x0080 + #define CONFIG_RAM_BASE 0x20000000 #define CONFIG_RAM_SIZE 0x00004000 diff --git a/common/flash_common.c b/common/flash_common.c index 16ad911594..6f79f544a0 100644 --- a/common/flash_common.c +++ b/common/flash_common.c @@ -340,8 +340,10 @@ static int command_flash_info(int argc, char **argv) ccprintf("Physical:%4d KB\n", CONFIG_FLASH_PHYSICAL_SIZE / 1024); ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE / 1024); - ccprintf("Write: %4d B\n", CONFIG_FLASH_WRITE_SIZE); - ccprintf("Erase: %4d B\n", CONFIG_FLASH_ERASE_SIZE); + ccprintf("Write: %4d B (ideal %d B)\n", CONFIG_FLASH_WRITE_SIZE, + CONFIG_FLASH_WRITE_IDEAL_SIZE); + ccprintf("Erase: %4d B (to %d-bits)\n", CONFIG_FLASH_ERASE_SIZE, + CONFIG_FLASH_ERASED_VALUE32 ? 1 : 0); ccprintf("Protect: %4d B\n", CONFIG_FLASH_BANK_SIZE); i = flash_get_protect(); @@ -472,18 +474,50 @@ DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp, static int flash_command_get_info(struct host_cmd_handler_args *args) { - struct ec_response_flash_info *r = args->response; + struct ec_response_flash_info_1 *r = args->response; r->flash_size = CONFIG_FLASH_SIZE; r->write_block_size = CONFIG_FLASH_WRITE_SIZE; r->erase_block_size = CONFIG_FLASH_ERASE_SIZE; r->protect_block_size = CONFIG_FLASH_BANK_SIZE; - args->response_size = sizeof(*r); + + if (args->version == 0) { + /* Only version 0 fields returned */ + args->response_size = sizeof(struct ec_response_flash_info); + } else { + /* Fill in full version 1 struct */ + + /* + * Compute the ideal amount of data for the host to send us, + * based on the maximum response size and the ideal write size. + */ + r->write_ideal_size = + (args->response_max - + sizeof(struct ec_params_flash_write)) & + ~(CONFIG_FLASH_WRITE_IDEAL_SIZE - 1); + /* + * If we can't get at least one ideal block, then just want + * as high a multiple of the minimum write size as possible. + */ + if (!r->write_ideal_size) + r->write_ideal_size = + (args->response_max - + sizeof(struct ec_params_flash_write)) & + ~(CONFIG_FLASH_WRITE_SIZE - 1); + + r->flags = 0; + +#if (CONFIG_FLASH_ERASED_VALUE32 == 0) + r->flags |= EC_FLASH_INFO_ERASE_TO_0; +#endif + + args->response_size = sizeof(*r); + } return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_FLASH_INFO, flash_command_get_info, - EC_VER_MASK(0)); + EC_VER_MASK(0) | EC_VER_MASK(1)); static int flash_command_read(struct host_cmd_handler_args *args) { diff --git a/include/ec_commands.h b/include/ec_commands.h index c4ac2b5721..f725b0b784 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -572,6 +572,7 @@ struct ec_response_get_protocol_info { /* Get flash info */ #define EC_CMD_FLASH_INFO 0x10 +/* Version 0 returns these fields */ struct ec_response_flash_info { /* Usable flash size, in bytes */ uint32_t flash_size; @@ -592,6 +593,37 @@ struct ec_response_flash_info { uint32_t protect_block_size; } __packed; +/* Flags for version 1+ flash info command */ +/* EC flash erases bits to 0 instead of 1 */ +#define EC_FLASH_INFO_ERASE_TO_0 (1 << 0) + +/* + * Version 1 returns the same initial fields as version 0, with additional + * fields following. + * + * gcc anonymous structs don't seem to get along with the __packed directive; + * if they did we'd define the version 0 struct as a sub-struct of this one. + */ +struct ec_response_flash_info_1 { + /* Version 0 fields; see above for description */ + uint32_t flash_size; + uint32_t write_block_size; + uint32_t erase_block_size; + uint32_t protect_block_size; + + /* Version 1 adds these fields: */ + /* + * Ideal write size in bytes. Writes will be fastest if size is + * exactly this and offset is a multiple of this. For example, an EC + * may have a write buffer which can do half-page operations if data is + * aligned, and a slower word-at-a-time write mode. + */ + uint32_t write_ideal_size; + + /* Flags; see EC_FLASH_INFO_* */ + uint32_t flags; +} __packed; + /* * Read flash * diff --git a/util/ectool.c b/util/ectool.c index 1faf78f814..b68b5007a3 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -485,10 +485,20 @@ int cmd_reboot_ec(int argc, char *argv[]) int cmd_flash_info(int argc, char *argv[]) { - struct ec_response_flash_info r; + struct ec_response_flash_info_1 r; + int cmdver = 1; + int rsize = sizeof(r); int rv; - rv = ec_command(EC_CMD_FLASH_INFO, 0, NULL, 0, &r, sizeof(r)); + memset(&r, 0, sizeof(r)); + + if (!ec_cmd_version_supported(EC_CMD_FLASH_INFO, cmdver)) { + /* Fall back to version 0 command */ + cmdver = 0; + rsize = sizeof(struct ec_response_flash_info); + } + + rv = ec_command(EC_CMD_FLASH_INFO, cmdver, NULL, 0, &r, rsize); if (rv < 0) return rv; @@ -496,6 +506,12 @@ int cmd_flash_info(int argc, char *argv[]) r.flash_size, r.write_block_size, r.erase_block_size, r.protect_block_size); + if (cmdver >= 1) { + /* Fields added in ver.1 available */ + printf("WriteIdealSize %d\nFlags 0x%x\n", + r.write_ideal_size, r.flags); + } + return 0; } -- cgit v1.2.1