diff options
author | Rong Chang <rongchang@google.com> | 2017-02-20 16:15:09 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-02 16:59:36 -0700 |
commit | 9ca4586129844b86ca4b346860ab658754228d2b (patch) | |
tree | e8bd729cb6cca3f76b9aca3a9a0b0f1d204d6ef4 | |
parent | d0ee126b4cdc368c36ae6660d66fed1524476e59 (diff) | |
download | chrome-ec-9ca4586129844b86ca4b346860ab658754228d2b.tar.gz |
common: Add support for flash with regions of different size
Add support to handle devices with flash regions of different sizes.
BRANCH=none
TEST=compile
BUG=b:38018926
Change-Id: I8f842abaa50de724df60dd7e19f9e97cb9660367
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/264031
Reviewed-by: Alexandru M Stan <amstan@chromium.org>
-rw-r--r-- | common/firmware_image.lds.S | 3 | ||||
-rw-r--r-- | common/flash.c | 207 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | include/ec_commands.h | 49 | ||||
-rw-r--r-- | include/flash.h | 56 |
5 files changed, 257 insertions, 64 deletions
diff --git a/common/firmware_image.lds.S b/common/firmware_image.lds.S index 30d7ebb0cc..fe41992df9 100644 --- a/common/firmware_image.lds.S +++ b/common/firmware_image.lds.S @@ -14,7 +14,6 @@ MEMORY } SECTIONS { - . = ALIGN(CONFIG_FLASH_BANK_SIZE); #if defined(NPCX_RO_HEADER) /* Replace *_MEM_OFF with *_STORAGE_OFF to indicate flat file contains header * or some struture which doesn't belong to FW */ @@ -25,7 +24,6 @@ SECTIONS #endif *(.image.RO) } > FLASH =0xff - . = ALIGN(CONFIG_FLASH_BANK_SIZE); #ifdef CONFIG_RWSIG_TYPE_RWSIG .image.RO.key : AT(CONFIG_RO_PUBKEY_ADDR) { @@ -44,7 +42,6 @@ SECTIONS CONFIG_SHAREDLIB_MEM_OFF) { *(.image.libsharedobjs) } > FLASH =0xff - . = ALIGN(CONFIG_FLASH_BANK_SIZE); #endif #if defined(NPCX_RO_HEADER) diff --git a/common/flash.c b/common/flash.c index d070e5f6b3..3ce7b79496 100644 --- a/common/flash.c +++ b/common/flash.c @@ -102,11 +102,56 @@ const uint32_t pstate_data __attribute__((section(".rodata.pstate"))) = #endif /* !CONFIG_FLASH_PSTATE_BANK */ #endif /* CONFIG_FLASH_PSTATE */ +#ifdef CONFIG_FLASH_MULTIPLE_REGION +int flash_bank_size(int bank) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) { + if (bank < flash_bank_array[i].count) + return 1 << flash_bank_array[i].size_exp; + bank -= flash_bank_array[i].count; + } + return -1; +} + +int flash_bank_index(int offset) +{ + int bank_offset = 0, i; + + for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) { + int all_sector_size = flash_bank_array[i].count << + flash_bank_array[i].size_exp; + if (offset >= all_sector_size) { + offset -= all_sector_size; + bank_offset += flash_bank_array[i].count; + continue; + } + if (offset & ((1 << flash_bank_array[i].size_exp) - 1)) + return -1; + return bank_offset + (offset >> flash_bank_array[i].size_exp); + } + if (offset != 0) + return -1; + return bank_offset; +} + +int flash_bank_count(int offset, int size) +{ + int begin = flash_bank_index(offset); + int end = flash_bank_index(offset + size); + + if (begin == -1 || end == -1) + return -1; + return end - begin; +} +#endif /* CONFIG_FLASH_MULTIPLE_REGION */ + int flash_range_ok(int offset, int size_req, int align) { if (offset < 0 || size_req < 0 || - offset + size_req > CONFIG_FLASH_SIZE || - (offset | size_req) & (align - 1)) + offset + size_req > CONFIG_FLASH_SIZE || + (offset | size_req) & (align - 1)) return 0; /* Invalid range */ return 1; @@ -445,8 +490,10 @@ int flash_write(int offset, int size, const char *data) int flash_erase(int offset, int size) { +#ifndef CONFIG_FLASH_MULTIPLE_REGION if (!flash_range_ok(offset, size, CONFIG_FLASH_ERASE_SIZE)) return EC_ERROR_INVAL; /* Invalid range */ +#endif #ifdef CONFIG_VBOOT_HASH /* @@ -732,48 +779,60 @@ int flash_set_protect(uint32_t mask, uint32_t flags) static int command_flash_info(int argc, char **argv) { - int i; + int i, flags; ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE / 1024); ccprintf("Write: %4d B (ideal %d B)\n", CONFIG_FLASH_WRITE_SIZE, CONFIG_FLASH_WRITE_IDEAL_SIZE); +#ifdef CONFIG_FLASH_MULTIPLE_REGION + ccprintf("Regions:\n"); + for (i = 0; i < ARRAY_SIZE(flash_bank_array); i++) { + ccprintf(" %d region%s:\n", + flash_bank_array[i].count, + (flash_bank_array[i].count == 1 ? "" : "s")); + ccprintf(" Erase: %4d B (to %d-bits)\n", + 1 << flash_bank_array[i].erase_size_exp, + CONFIG_FLASH_ERASED_VALUE32 ? 1 : 0); + ccprintf(" Size/Protect: %4d B\n", + 1 << flash_bank_array[i].size_exp); + } +#else 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(); +#endif + flags = flash_get_protect(); ccprintf("Flags: "); - if (i & EC_FLASH_PROTECT_GPIO_ASSERTED) + if (flags & EC_FLASH_PROTECT_GPIO_ASSERTED) ccputs(" wp_gpio_asserted"); - if (i & EC_FLASH_PROTECT_RO_AT_BOOT) + if (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ccputs(" ro_at_boot"); - if (i & EC_FLASH_PROTECT_ALL_AT_BOOT) + if (flags & EC_FLASH_PROTECT_ALL_AT_BOOT) ccputs(" all_at_boot"); - if (i & EC_FLASH_PROTECT_RO_NOW) + if (flags & EC_FLASH_PROTECT_RO_NOW) ccputs(" ro_now"); - if (i & EC_FLASH_PROTECT_ALL_NOW) + if (flags & EC_FLASH_PROTECT_ALL_NOW) ccputs(" all_now"); #ifdef CONFIG_FLASH_PROTECT_RW - if (i & EC_FLASH_PROTECT_RW_AT_BOOT) + if (flags & EC_FLASH_PROTECT_RW_AT_BOOT) ccputs(" rw_at_boot"); - if (i & EC_FLASH_PROTECT_RW_NOW) + if (flags & EC_FLASH_PROTECT_RW_NOW) ccputs(" rw_now"); #endif - if (i & EC_FLASH_PROTECT_ERROR_STUCK) + if (flags & EC_FLASH_PROTECT_ERROR_STUCK) ccputs(" STUCK"); - if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT) + if (flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT) ccputs(" INCONSISTENT"); #ifdef CONFIG_ROLLBACK - if (i & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) + if (flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) ccputs(" rollback_at_boot"); - if (i & EC_FLASH_PROTECT_ROLLBACK_NOW) + if (flags & EC_FLASH_PROTECT_ROLLBACK_NOW) ccputs(" rollback_now"); #endif ccputs("\n"); ccputs("Protected now:"); - for (i = 0; i < CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE; - i++) { + for (i = 0; i < PHYSICAL_BANKS; i++) { if (!(i & 31)) ccputs("\n "); else if (!(i & 7)) @@ -791,7 +850,7 @@ DECLARE_SAFE_CONSOLE_COMMAND(flashinfo, command_flash_info, static int command_flash_erase(int argc, char **argv) { int offset = -1; - int size = CONFIG_FLASH_ERASE_SIZE; + int size = -1; int rv; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) @@ -805,13 +864,13 @@ static int command_flash_erase(int argc, char **argv) return flash_erase(offset, size); } DECLARE_CONSOLE_COMMAND(flasherase, command_flash_erase, - "offset [size]", + "offset size", "Erase flash"); static int command_flash_write(int argc, char **argv) { int offset = -1; - int size = CONFIG_FLASH_ERASE_SIZE; + int size = -1; int rv; char *data; int i; @@ -846,7 +905,7 @@ static int command_flash_write(int argc, char **argv) return rv; } DECLARE_CONSOLE_COMMAND(flashwrite, command_flash_write, - "offset [size]", + "offset size", "Write pattern to flash"); static int command_flash_read(int argc, char **argv) @@ -965,50 +1024,92 @@ DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp, static int flash_command_get_info(struct host_cmd_handler_args *args) { - struct ec_response_flash_info_1 *r = args->response; + const struct ec_params_flash_info_2 *p_2 = args->params; + struct ec_response_flash_info_2 *r_2 = args->response; +#ifdef CONFIG_FLASH_MULTIPLE_REGION + int banks_size = ARRAY_SIZE(flash_bank_array); + const struct ec_flash_bank *banks = flash_bank_array; +#else + struct ec_response_flash_info_1 *r_1 = args->response; +#if CONFIG_FLASH_BANK_SIZE < CONFIG_FLASH_ERASE_SIZE +#error "Flash: Bank size expected bigger or equal to erase size." +#endif + struct ec_flash_bank single_bank = { + .count = CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE, + .size_exp = __fls(CONFIG_FLASH_BANK_SIZE), + .write_size_exp = __fls(CONFIG_FLASH_WRITE_SIZE), + .erase_size_exp = __fls(CONFIG_FLASH_ERASE_SIZE), + .protect_size_exp = __fls(CONFIG_FLASH_BANK_SIZE), + }; + int banks_size = 1; + const struct ec_flash_bank *banks = &single_bank; +#endif + int banks_len; + int ideal_size; + + /* + * Compute the ideal amount of data for the host to send us, + * based on the maximum response size and the ideal write size. + */ + 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 (!ideal_size) + ideal_size = (args->response_max - + sizeof(struct ec_params_flash_write)) & + ~(CONFIG_FLASH_WRITE_SIZE - 1); - r->flash_size = CONFIG_FLASH_SIZE - EC_FLASH_REGION_START; - r->write_block_size = CONFIG_FLASH_WRITE_SIZE; - r->erase_block_size = CONFIG_FLASH_ERASE_SIZE; - r->protect_block_size = CONFIG_FLASH_BANK_SIZE; + if (args->version >= 2) { + args->response_size = sizeof(struct ec_response_flash_info_2); + r_2->flash_size = CONFIG_FLASH_SIZE - EC_FLASH_REGION_START; +#if (CONFIG_FLASH_ERASED_VALUE32 == 0) + r_2->flags = EC_FLASH_INFO_ERASE_TO_0; +#else + r_2->flags = 0; +#endif + r_2->write_ideal_size = ideal_size; + r_2->num_banks_total = banks_size; + r_2->num_banks_desc = MIN(banks_size, p_2->num_banks_desc); + banks_len = r_2->num_banks_desc * sizeof(struct ec_flash_bank); + memcpy(r_2->banks, banks, banks_len); + args->response_size += banks_len; + return EC_RES_SUCCESS; + } +#ifdef CONFIG_FLASH_MULTIPLE_REGION + return EC_RES_INVALID_PARAM; +#else + r_1->flash_size = CONFIG_FLASH_SIZE - EC_FLASH_REGION_START; + r_1->flags = 0; + r_1->write_block_size = CONFIG_FLASH_WRITE_SIZE; + r_1->erase_block_size = CONFIG_FLASH_ERASE_SIZE; + r_1->protect_block_size = CONFIG_FLASH_BANK_SIZE; if (args->version == 0) { /* Only version 0 fields returned */ args->response_size = sizeof(struct ec_response_flash_info); } else { + args->response_size = sizeof(struct ec_response_flash_info_1); /* 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; - + r_1->write_ideal_size = ideal_size; #if (CONFIG_FLASH_ERASED_VALUE32 == 0) - r->flags |= EC_FLASH_INFO_ERASE_TO_0; + r_1->flags |= EC_FLASH_INFO_ERASE_TO_0; #endif - - args->response_size = sizeof(*r); } return EC_RES_SUCCESS; +#endif /* CONFIG_FLASH_MULTIPLE_REGION */ } +#ifdef CONFIG_FLASH_MULTIPLE_REGION +#define FLASH_INFO_VER EC_VER_MASK(2) +#else +#define FLASH_INFO_VER (EC_VER_MASK(0) | EC_VER_MASK(1) | EC_VER_MASK(2)) +#endif DECLARE_HOST_COMMAND(EC_CMD_FLASH_INFO, - flash_command_get_info, - EC_VER_MASK(0) | EC_VER_MASK(1)); + flash_command_get_info, FLASH_INFO_VER); + static int flash_command_read(struct host_cmd_handler_args *args) { diff --git a/include/config.h b/include/config.h index a6b037f429..8ecf705054 100644 --- a/include/config.h +++ b/include/config.h @@ -1035,6 +1035,12 @@ * screw, of course). */ #define CONFIG_FLASH_PSTATE_BANK +/* + * For flash that is segemented in different regions. + */ +#undef CONFIG_FLASH_MULTIPLE_REGION +/* Number of regions of different size/type */ +#undef CONFIG_FLASH_REGION_TYPE_COUNT /* Total size of writable flash */ #undef CONFIG_FLASH_SIZE diff --git a/include/ec_commands.h b/include/ec_commands.h index 40fbf0403b..998d5a1624 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1097,6 +1097,7 @@ struct __ec_align4 ec_response_get_features { /* Get flash info */ #define EC_CMD_FLASH_INFO 0x0010 +#define EC_VER_FLASH_INFO 2 /* Version 0 returns these fields */ struct __ec_align4 ec_response_flash_info { @@ -1130,6 +1131,12 @@ struct __ec_align4 ec_response_flash_info { * gcc anonymous structs don't seem to get along with the __packed directive; * if they did we'd define the version 0 structure as a sub-structure of this * one. + * + * Version 2 supports flash banks of different sizes: + * The caller specified the number of banks it has preallocated + * (num_banks_desc) + * The EC returns the number of banks describing the flash memory. + * It adds banks descriptions up to num_banks_desc. */ struct __ec_align4 ec_response_flash_info_1 { /* Version 0 fields; see above for description */ @@ -1151,6 +1158,42 @@ struct __ec_align4 ec_response_flash_info_1 { uint32_t flags; }; +struct __ec_align4 ec_params_flash_info_2 { + /* Number of banks to describe */ + uint16_t num_banks_desc; + /* Reserved; set 0; ignore on read */ + uint8_t reserved[2]; +}; + +struct ec_flash_bank { + /* Number of sector is in this bank. */ + uint16_t count; + /* Size in power of 2 of each sector (8 --> 256 bytes) */ + uint8_t size_exp; + /* Minimal write size for the sectors in this bank */ + uint8_t write_size_exp; + /* Erase size for the sectors in this bank */ + uint8_t erase_size_exp; + /* Size for write protection, usually identical to erase size. */ + uint8_t protect_size_exp; + /* Reserved; set 0; ignore on read */ + uint8_t reserved[2]; +}; + +struct __ec_align4 ec_response_flash_info_2 { + /* Total flash in the EC. */ + uint32_t flash_size; + /* Flags; see EC_FLASH_INFO_* */ + uint32_t flags; + /* Maximum size to use to send data to write to the EC. */ + uint32_t write_ideal_size; + /* Number of banks present in the EC. */ + uint16_t num_banks_total; + /* Number of banks described in banks array. */ + uint16_t num_banks_desc; + struct ec_flash_bank banks[0]; +}; + /* * Read flash * @@ -1986,7 +2029,7 @@ struct __ec_todo_packed ec_response_motion_sensor_data { union { int16_t data[3]; struct __ec_todo_packed { - uint16_t rsvd; + uint16_t reserved; uint32_t timestamp; }; struct __ec_todo_unpacked { @@ -2186,7 +2229,7 @@ struct __ec_todo_packed ec_params_motion_sense { uint8_t spoof_enable; /* Ignored, used for alignment. */ - uint8_t rsvd; + uint8_t reserved; /* Individual component values to spoof. */ int16_t components[3]; @@ -2847,7 +2890,7 @@ union __ec_align_offset1 ec_response_get_next_data { struct __ec_todo_unpacked { /* For aligning the fifo_info */ - uint8_t rsvd[3]; + uint8_t reserved[3]; struct ec_response_motion_sense_fifo_info info; } sensor_fifo; diff --git a/include/flash.h b/include/flash.h index 5963020c8a..cdd8148d03 100644 --- a/include/flash.h +++ b/include/flash.h @@ -11,11 +11,51 @@ #include "common.h" #include "ec_commands.h" /* For EC_FLASH_PROTECT_* flags */ -/* Number of physical flash banks */ +#ifdef CONFIG_FLASH_MULTIPLE_REGION +extern struct ec_flash_bank const flash_bank_array[ + CONFIG_FLASH_REGION_TYPE_COUNT]; + +/* + * Return the bank the offset is in. + * Return -1 if the offset is not at the beginning of that bank. + */ +int flash_bank_index(int offset); + /* - * TODO(crosbug.com/p/62372): This assumes flash protection blocks are all of - * identical sizes, which is incorrect, for example, on STM32F091VC. + * Number of banks between offset and offset+size. + * + * offset and offset + size should be addresses at the beginning of bank: + * 0 32 + * +-------------------+--------... + * | bank 0 | bank 1 ... + * +-------------------+--------... + * In that case, begin = 0, end = 1, return is 1. + * otherwise, this is an error: + * 0 32 64 + * +----------+--------+--------... + * | bank 0 | bank 1 ... + * +----------+--------+--------... + * begin = 0, end = -1.... + * The idea is to prevent erasing more than you think. */ +int flash_bank_count(int offset, int size); + +/* + * Return the size of the specified bank in bytes. + * Return -1 if the bank is too large. + */ +int flash_bank_size(int bank); + +/* Number of physical flash banks */ +#define PHYSICAL_BANKS CONFIG_FLASH_MULTIPLE_REGION + +/* WP region offset and size in units of flash banks */ +#define WP_BANK_OFFSET flash_bank_index(CONFIG_WP_STORAGE_OFF) +#define WP_BANK_COUNT \ + (flash_bank_count(CONFIG_WP_STORAGE_OFF, CONFIG_WP_STORAGE_SIZE)) + +#else /* CONFIG_FLASH_MULTIPLE_REGION */ +/* Number of physical flash banks */ #ifndef PHYSICAL_BANKS #define PHYSICAL_BANKS (CONFIG_FLASH_SIZE / CONFIG_FLASH_BANK_SIZE) #endif @@ -25,18 +65,24 @@ #ifndef WP_BANK_COUNT #define WP_BANK_COUNT (CONFIG_WP_STORAGE_SIZE / CONFIG_FLASH_BANK_SIZE) #endif +#endif /* CONFIG_FLASH_MULTIPLE_REGION */ /* Persistent protection state flash offset / size / bank */ #if defined(CONFIG_FLASH_PSTATE) && defined(CONFIG_FLASH_PSTATE_BANK) + +#ifdef CONFIG_FLASH_MULTIPLE_REGION +#error "Not supported." +#endif + #ifndef PSTATE_BANK #define PSTATE_BANK (CONFIG_FW_PSTATE_OFF / CONFIG_FLASH_BANK_SIZE) #endif #ifndef PSTATE_BANK_COUNT #define PSTATE_BANK_COUNT (CONFIG_FW_PSTATE_SIZE / CONFIG_FLASH_BANK_SIZE) #endif -#else +#else /* CONFIG_FLASH_PSTATE && CONFIG_FLASH_PSTATE_BANK */ #define PSTATE_BANK_COUNT 0 -#endif +#endif /* CONFIG_FLASH_PSTATE && CONFIG_FLASH_PSTATE_BANK */ #ifdef CONFIG_ROLLBACK /* |