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>
This commit is contained in:
Rong Chang
2017-02-20 16:15:09 +08:00
committed by chrome-bot
parent d0ee126b4c
commit 9ca4586129
5 changed files with 257 additions and 64 deletions

View File

@@ -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)

View File

@@ -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;
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;
/*
* 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);
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)
{

View File

@@ -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

View File

@@ -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;

View File

@@ -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];
/*
* TODO(crosbug.com/p/62372): This assumes flash protection blocks are all of
* identical sizes, which is incorrect, for example, on STM32F091VC.
* 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);
/*
* 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
/*