summaryrefslogtreecommitdiff
path: root/chip/stm32/flash-stm32f4.c
diff options
context:
space:
mode:
authorGwendal Grignou <gwendal@chromium.org>2015-04-03 16:02:16 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-03 02:02:42 -0700
commit35f4d8acaa40050f10158459a04e0bf9b24149c6 (patch)
tree2fd1c6127874023ca44be4f3022704fdb29aa2f4 /chip/stm32/flash-stm32f4.c
parent5c9118b311ed1d4059b9e51c3defcf5bce62de04 (diff)
downloadchrome-ec-35f4d8acaa40050f10158459a04e0bf9b24149c6.tar.gz
Add flash command support to boards with STM32F4
Add support to write and erase all flash with flashrom. Add support to use all the memory. Note that PSTATE must not used its own page, as the STM32F4 use big pages. BUG=b:38018926 BRANCH=none TEST=With flashrom, write all, RO, RW regions. Use flash command on the console, including flashwp Change-Id: I4f0aee1b3a4f342bdf4ca97bf5d8e8bcc153fd9c Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/264032 Commit-Ready: Wei-Ning Huang <wnhuang@chromium.org> Tested-by: Wei-Ning Huang <wnhuang@chromium.org> Reviewed-by: Alexandru M Stan <amstan@chromium.org>
Diffstat (limited to 'chip/stm32/flash-stm32f4.c')
-rw-r--r--chip/stm32/flash-stm32f4.c354
1 files changed, 32 insertions, 322 deletions
diff --git a/chip/stm32/flash-stm32f4.c b/chip/stm32/flash-stm32f4.c
index 6b6b64f73a..95af3f1820 100644
--- a/chip/stm32/flash-stm32f4.c
+++ b/chip/stm32/flash-stm32f4.c
@@ -13,110 +13,53 @@
#include "hooks.h"
#include "registers.h"
#include "system.h"
-#include "panic.h"
-#include "watchdog.h"
-
-
-#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
+#include "util.h"
+/*****************************************************************************/
+/* Physical layer APIs */
/*
- * Approximate number of CPU cycles per iteration of the loop when polling
- * the flash status
+ * 8 "erase" sectors : 16KB/16KB/16KB/16KB/64KB/128KB/128KB/128KB
*/
-#define CYCLE_PER_FLASH_LOOP 10
-
-/* Flash page programming timeout. This is 2x the datasheet max. */
-#define FLASH_TIMEOUT_US 16000
-
-static inline int calculate_flash_timeout(void)
-{
- return (FLASH_TIMEOUT_US *
- (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP);
-}
-
-
-/* Flag indicating whether we have locked down entire flash */
-static int entire_flash_locked;
-
-#define FLASH_SYSJUMP_TAG 0x5750 /* "WP" - Write Protect */
-#define FLASH_HOOK_VERSION 1
-/* The previous write protect state before sys jump */
-struct flash_wp_state {
- int entire_flash_locked;
+struct ec_flash_bank const flash_bank_array[] = {
+ {
+ .count = 4,
+ .size_exp = __fls(SIZE_16KB),
+ .write_size_exp = __fls(CONFIG_FLASH_WRITE_SIZE),
+ .erase_size_exp = __fls(SIZE_16KB),
+ .protect_size_exp = __fls(SIZE_16KB),
+ },
+ {
+ .count = 1,
+ .size_exp = __fls(SIZE_64KB),
+ .write_size_exp = __fls(CONFIG_FLASH_WRITE_SIZE),
+ .erase_size_exp = __fls(SIZE_64KB),
+ .protect_size_exp = __fls(SIZE_64KB),
+ },
+ {
+ .count = (CONFIG_FLASH_SIZE - SIZE_128KB) / SIZE_128KB,
+ .write_size_exp = __fls(CONFIG_FLASH_WRITE_SIZE),
+ .size_exp = __fls(SIZE_128KB),
+ .erase_size_exp = __fls(SIZE_128KB),
+ .protect_size_exp = __fls(SIZE_128KB),
+ },
};
/*****************************************************************************/
/* Physical layer APIs */
-/* Flash unlocking keys */
-#define PRG_LOCK 0
-#define KEY1 0x45670123
-#define KEY2 0xCDEF89AB
-
-static int unlock(void)
+int flash_physical_get_protect(int bank)
{
- /*
- * We may have already locked the flash module and get a bus fault
- * in the attempt to unlock. Need to disable bus fault handler now.
- */
- ignore_bus_fault(1);
-
- /* unlock CR if needed */
- if (STM32_FLASH_CR & FLASH_CR_LOCK) {
- STM32_FLASH_KEYR = KEY1;
- STM32_FLASH_KEYR = KEY2;
- }
-
- /* Re-enable bus fault handler */
- ignore_bus_fault(0);
-
- return (STM32_FLASH_CR & FLASH_CR_LOCK) ?
- EC_ERROR_UNKNOWN : EC_SUCCESS;
-}
-
-static void lock(void)
-{
- STM32_FLASH_CR = FLASH_CR_LOCK;
-}
-
-
-int flash_physical_get_protect(int block)
-{
- /* TODO: not sure if write protect can be implemented like this. */
- return 0;
+ return !(STM32_OPTB_WP & STM32_OPTB_nWRP(bank));
}
uint32_t flash_physical_get_protect_flags(void)
{
- return entire_flash_locked ? EC_FLASH_PROTECT_ALL_NOW : 0;
-}
-
-int flash_physical_protect_now(int all)
-{
- if (all) {
- /*
- * Lock by writing a wrong key to FLASH_KEYR. This triggers a
- * bus fault, so we need to disable bus fault handler while
- * doing this.
- *
- * This incorrect key fault causes the flash to become
- * permanenlty locked until reset, a correct keyring write
- * will not unlock it. In this way we can implement system
- * write protect.
- */
- ignore_bus_fault(1);
- STM32_FLASH_KEYR = 0xffffffff;
- ignore_bus_fault(0);
-
- entire_flash_locked = 1;
+ uint32_t flags = 0;
- /* Check if lock happened */
- if (STM32_FLASH_CR & FLASH_CR_LOCK)
- return EC_SUCCESS;
- }
+ if ((STM32_OPTB_WP & STM32_OPTB_nWRP_ALL) == 0)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
- /* No way to protect just the RO flash until next boot */
- return EC_ERROR_INVAL;
+ return flags;
}
uint32_t flash_physical_get_valid_flags(void)
@@ -147,238 +90,5 @@ uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
int flash_physical_restore_state(void)
{
- uint32_t reset_flags = system_get_reset_flags();
- int version, size;
- const struct flash_wp_state *prev;
-
- /*
- * If we have already jumped between images, an earlier image could
- * have applied write protection. Nothing additional needs to be done.
- */
- if (reset_flags & RESET_FLAG_SYSJUMP) {
- prev = (const struct flash_wp_state *)system_get_jump_tag(
- FLASH_SYSJUMP_TAG, &version, &size);
- if (prev && version == FLASH_HOOK_VERSION &&
- size == sizeof(*prev))
- entire_flash_locked = prev->entire_flash_locked;
- return 1;
- }
-
return 0;
}
-
-static int flash_idle(void)
-{
- timestamp_t deadline;
-
- deadline.val = get_time().val + FLASH_TIMEOUT_US;
- /* Wait for flash op to complete.
- * This function is used for both reads and writes, so
- * we need a long timeout, but a relatively short poll interval.
- */
- while ((STM32_FLASH_SR & FLASH_SR_BUSY) &&
- (get_time().val < deadline.val)) {
- usleep(1);
- }
-
- if (STM32_FLASH_SR & FLASH_SR_BUSY)
- return EC_ERROR_TIMEOUT;
-
- return EC_SUCCESS;
-}
-
-static void clear_flash_errors(void)
-{
- /* Clear previous error status */
- STM32_FLASH_SR = FLASH_SR_ERR_MASK;
-}
-
-/*****************************************************************************/
-/* Physical layer APIs */
-
-int flash_physical_protect_at_boot(uint32_t new_flags)
-{
- return EC_SUCCESS;
-}
-
-int flash_physical_write(int offset, int size, const char *data)
-{
- uint32_t *address = (uint32_t *)(CONFIG_MAPPED_STORAGE_BASE + offset);
- int res = EC_SUCCESS;
-
- if (unlock() != EC_SUCCESS) {
- res = EC_ERROR_UNKNOWN;
- goto exit_wr;
- }
-
- /* Wait for busy to clear */
- res = flash_idle();
- if (res)
- goto exit_wr;
- clear_flash_errors();
-
- /* set PG bit */
- STM32_FLASH_CR &= ~FLASH_CR_PSIZE_MASK;
- STM32_FLASH_CR |= FLASH_CR_PSIZE(FLASH_CR_PSIZE_32);
- STM32_FLASH_CR |= FLASH_CR_PG;
-
- for (; size > 0; size -= sizeof(uint32_t)) {
- /*
- * Reload the watchdog timer to avoid watchdog reset when doing
- * long writing with interrupt disabled.
- */
- watchdog_reload();
-
- res = flash_idle();
- if (res)
- goto exit_wr;
-
- /* write the word */
- *address = data[0] + (data[1] << 8) +
- (data[2] << 16) + (data[3] << 24);
-
- address++;
- data += sizeof(uint32_t);
-
- res = flash_idle();
- if (res)
- goto exit_wr;
-
- if (STM32_FLASH_SR & FLASH_SR_BUSY) {
- res = EC_ERROR_TIMEOUT;
- goto exit_wr;
- }
-
- /* Check for error conditions - erase failed, voltage error,
- * protection error.
- */
- if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) {
- res = EC_ERROR_UNKNOWN;
- goto exit_wr;
- }
- }
-
-exit_wr:
- /* Disable PG bit */
- STM32_FLASH_CR &= ~FLASH_CR_PG;
-
- lock();
-
- return res;
-}
-
-
-
-/* "@Internal Flash /0x08000000/04*016Kg,01*064Kg,03*128Kg" */
-struct flash_sector {
- int base;
- int size;
-};
-static const struct flash_sector sectors[] = {
- {(0 * 1024), (16 * 1024)},
- {(16 * 1024), (16 * 1024)},
- {(32 * 1024), (16 * 1024)},
- {(48 * 1024), (16 * 1024)},
- {(64 * 1024), (64 * 1024)},
- {(128 * 1024), (128 * 1024)},
- {(256 * 1024), (128 * 1024)},
- {(384 * 1024), (128 * 1024)}
-};
-static const int num_sectors = ARRAY_SIZE(sectors);
-
-int flash_physical_erase(int offset, int size)
-{
- int res = EC_SUCCESS;
- int start_sector;
- int end_sector;
-
- /* Check that offset/size align with sectors. */
- for (start_sector = 0; start_sector < num_sectors; start_sector++)
- if (offset == sectors[start_sector].base)
- break;
- for (end_sector = start_sector; end_sector < num_sectors; end_sector++)
- if ((offset + size) ==
- (sectors[end_sector].base + sectors[end_sector].size))
- break;
-
- /* We can only erase on sector boundaries. */
- if ((start_sector >= num_sectors) || (end_sector >= num_sectors))
- return EC_ERROR_PARAM1;
-
- if (unlock() != EC_SUCCESS)
- return EC_ERROR_UNKNOWN;
-
- res = flash_idle();
- if (res)
- goto exit_er;
-
- clear_flash_errors();
-
- for (; start_sector <= end_sector; start_sector++) {
- /* Do nothing if already erased */
- if (flash_is_erased(sectors[start_sector].base,
- sectors[start_sector].size))
- continue;
-
- res = flash_idle();
- if (res)
- goto exit_er;
-
- /* set Sector Erase bit and select sector */
- STM32_FLASH_CR = (STM32_FLASH_CR & ~FLASH_CR_SNB_MASK) |
- FLASH_CR_SER | FLASH_CR_SNB(start_sector);
-
- /* set STRT bit : start erase */
- STM32_FLASH_CR |= FLASH_CR_STRT;
-
- /*
- * Reload the watchdog timer to avoid watchdog reset during a
- * long erase operation.
- */
- watchdog_reload();
-
- /* Wait for erase to complete, this will be awhile */
- res = flash_idle();
- if (res)
- goto exit_er;
- /*
- * Check for error conditions - erase failed, voltage error,
- * protection error
- */
- if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) {
- res = EC_ERROR_UNKNOWN;
- goto exit_er;
- }
- }
-
-exit_er:
- /* reset PER bit */
- STM32_FLASH_CR &= ~FLASH_CR_SER;
-
- lock();
-
- return res;
-}
-
-/*****************************************************************************/
-/* High-level APIs */
-
-int flash_pre_init(void)
-{
- return EC_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Hooks */
-
-static void flash_preserve_state(void)
-{
- struct flash_wp_state state;
-
- state.entire_flash_locked = entire_flash_locked;
-
- system_add_jump_tag(FLASH_SYSJUMP_TAG, FLASH_HOOK_VERSION,
- sizeof(state), &state);
-}
-DECLARE_HOOK(HOOK_SYSJUMP, flash_preserve_state, HOOK_PRIO_DEFAULT);
-