summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRong Chang <rongchang@google.com>2017-02-20 16:15:09 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-06-02 16:59:36 -0700
commit9ca4586129844b86ca4b346860ab658754228d2b (patch)
treee8bd729cb6cca3f76b9aca3a9a0b0f1d204d6ef4
parentd0ee126b4cdc368c36ae6660d66fed1524476e59 (diff)
downloadchrome-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.S3
-rw-r--r--common/flash.c207
-rw-r--r--include/config.h6
-rw-r--r--include/ec_commands.h49
-rw-r--r--include/flash.h56
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
/*