From 275f873534c54941f1976d21a5d84dc21df02759 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Tue, 30 Jan 2018 17:01:50 +0100 Subject: stm32: add internal flash support for STM32H7 family The STM32H7 family has 2 banks of flash (with 2 hardware controllers able to do 2 parallel operations at the same time). Each bank of flash has 4 or 8 128-kB erase blocks (1MB and 2MB variants). The flash can only be written by 256-bit word (with an additional 10-bit ECC computed by the hardware). For the flash write-protection, we cannot use our 'classical' PSTATE scheme as the erase-blocks are too large (128-kB) to dedicate one to this and the embedded word in the RO partition would not work as the flash has ECC and triggers bus-fault when the ECC is incorrect (which includes the case where the 256-bit word is written a second time). So we will do the following: - use the RSS1 bit in the option bytes as the Write-Protect enabled bit. - if the WP GPIO is set, lock at startup the option bytes until next reboot. Signed-off-by: Vincent Palatin BRANCH=none BUG=b:67081508 TEST=run flashinfo/flashwp/flashwrite/flasherase commands on the EC console. Change-Id: I823fce3bd42b4df212cf0b8ceceaca84109b78e6 Reviewed-on: https://chromium-review.googlesource.com/901423 Commit-Ready: Vincent Palatin Tested-by: Vincent Palatin Reviewed-by: Nicolas Boichat --- chip/stm32/clock-stm32h7.c | 4 +- chip/stm32/config-stm32h7x3.h | 23 ++- chip/stm32/config_chip.h | 2 + chip/stm32/flash-stm32h7.c | 468 ++++++++++++++++++++++++++++++++++++++++++ chip/stm32/registers.h | 70 ++++++- core/cortex-m/panic.c | 5 + 6 files changed, 564 insertions(+), 8 deletions(-) create mode 100644 chip/stm32/flash-stm32h7.c diff --git a/chip/stm32/clock-stm32h7.c b/chip/stm32/clock-stm32h7.c index 291579ed16..9dd1f94f95 100644 --- a/chip/stm32/clock-stm32h7.c +++ b/chip/stm32/clock-stm32h7.c @@ -146,8 +146,8 @@ static void clock_set_osc(enum clock_osc osc) /* Adjust flash latency */ val = STM32_FLASH_ACR_WRHIGHFREQ_185MHZ | (2 << STM32_FLASH_ACR_LATENCY_SHIFT); - STM32_FLASH_ACR = val; - while (val != STM32_FLASH_ACR) + STM32_FLASH_ACR(0) = val; + while (val != STM32_FLASH_ACR(0)) ; /* Switch to PLL */ diff --git a/chip/stm32/config-stm32h7x3.h b/chip/stm32/config-stm32h7x3.h index 9b4dde19c9..72b9bd21de 100644 --- a/chip/stm32/config-stm32h7x3.h +++ b/chip/stm32/config-stm32h7x3.h @@ -4,7 +4,17 @@ */ /* Memory mapping */ -#define CONFIG_FLASH_SIZE (1048 * 1024) +#define CONFIG_FLASH_SIZE (2048 * 1024) +#define CONFIG_FLASH_ERASE_SIZE (128 * 1024) /* erase bank size */ +/* always use 256-bit writes due to ECC */ +#define CONFIG_FLASH_WRITE_SIZE 32 /* minimum write size */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE 32 + +/* + * What the code is calling 'bank' is really the size of the block used for + * write-protected, here it's 128KB sector (same as erase size). + */ +#define CONFIG_FLASH_BANK_SIZE (128 * 1024) /* Erasing 128K can take up to 2s, need to defer erase. */ #define CONFIG_FLASH_DEFERRED_ERASE @@ -22,8 +32,8 @@ #define CONFIG_RO_MEM_OFF 0 #define CONFIG_RO_SIZE (128 * 1024) -#define CONFIG_RW_MEM_OFF (128 * 1024) -#define CONFIG_RW_SIZE (896 * 1024) +#define CONFIG_RW_MEM_OFF (CONFIG_FLASH_SIZE / 2) +#define CONFIG_RW_SIZE (512 * 1024) #define CONFIG_RO_STORAGE_OFF 0 #define CONFIG_RW_STORAGE_OFF 0 @@ -40,8 +50,11 @@ #undef I2C_PORT_COUNT #define I2C_PORT_COUNT 4 -/* Use PSTATE embedded in the RO image, not in its own erase block */ -#define CONFIG_FLASH_PSTATE +/* + * Cannot use PSTATE: + * 128kB blocks are too large and ECC prevents re-writing PSTATE word. + */ +#undef CONFIG_FLASH_PSTATE #undef CONFIG_FLASH_PSTATE_BANK /* Number of IRQ vectors on the NVIC */ diff --git a/chip/stm32/config_chip.h b/chip/stm32/config_chip.h index f9dcc2fda7..1d7f95115d 100644 --- a/chip/stm32/config_chip.h +++ b/chip/stm32/config_chip.h @@ -125,8 +125,10 @@ */ #define CONFIG_UART_TX_DMA +#ifndef CHIP_FAMILY_STM32H7 /* Flash protection applies to the next boot, not the current one */ #define CONFIG_FLASH_PROTECT_NEXT_BOOT +#endif /* !CHIP_FAMILY_STM32H7 */ /* Chip needs to do custom pre-init */ #define CONFIG_CHIP_PRE_INIT diff --git a/chip/stm32/flash-stm32h7.c b/chip/stm32/flash-stm32h7.c new file mode 100644 index 0000000000..d697faf4dd --- /dev/null +++ b/chip/stm32/flash-stm32h7.c @@ -0,0 +1,468 @@ +/* Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* Flash memory module for STM32H7 family */ + +#include "common.h" +#include "clock.h" +#include "flash.h" +#include "hooks.h" +#include "registers.h" +#include "panic.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" +#include "watchdog.h" + +/* + * Approximate number of CPU cycles per iteration of the loop when polling + * the flash status + */ +#define CYCLE_PER_FLASH_LOOP 2 + +/* Flash 256-bit word programming timeout. */ +#define FLASH_TIMEOUT_US 600 + +/* + * Flash 128-KB block erase timeout. + * Datasheet says maximum is about 4 seconds in x8. + * Real delay seems to be: < 1 second in x64, < 2 seconds in x8. + */ +#define FLASH_ERASE_TIMEOUT_US (4200 * MSEC) + +/* + * Option bytes programming timeout. + * No specification, real delay seems to be around 300ms. + */ +#define FLASH_OPT_PRG_TIMEOUT_US (1000 * MSEC) + +/* + * All variants have 2 banks (as in parallel hardware / controllers) + * not what is called 'bank' in the common code (ie Write-Protect sectors) + * both have the same number of 128KB blocks. + */ +#define HWBANK_SIZE (CONFIG_FLASH_SIZE / 2) +#define BLOCKS_PER_HWBANK (HWBANK_SIZE / CONFIG_FLASH_ERASE_SIZE) +#define BLOCKS_HWBANK_MASK ((1 << BLOCKS_PER_HWBANK) - 1) + +/* + * We can tune the power consumption vs erase/write speed + * by default, go fast (and consume current) + */ +#define DEFAULT_PSIZE FLASH_CR_PSIZE_DWORD + +/* Can no longer write/erase flash until next reboot */ +static int access_disabled; +/* Can no longer modify write-protection in option bytes until next reboot */ +static int option_disabled; +/* Is physical flash stuck protected? (avoid reboot loop) */ +static int stuck_locked; + +static inline int calculate_flash_timeout(void) +{ + return (FLASH_TIMEOUT_US * + (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP); +} + +static int unlock(int bank) +{ + /* unlock CR only if needed */ + if (STM32_FLASH_CR(bank) & FLASH_CR_LOCK) { + /* + * 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); + + STM32_FLASH_KEYR(bank) = FLASH_KEYR_KEY1; + STM32_FLASH_KEYR(bank) = FLASH_KEYR_KEY2; + ignore_bus_fault(0); + } + + return (STM32_FLASH_CR(bank) & FLASH_CR_LOCK) ? EC_ERROR_UNKNOWN + : EC_SUCCESS; +} + +static void lock(int bank) +{ + STM32_FLASH_CR(bank) |= FLASH_CR_LOCK; +} + +static int unlock_optb(void) +{ + if (option_disabled) + return EC_ERROR_ACCESS_DENIED; + + if (unlock(0)) + return EC_ERROR_UNKNOWN; + + /* + * Always use bank 0 flash controller as there is only one option bytes + * set for both banks. + */ + if (STM32_FLASH_OPTCR(0) & FLASH_OPTCR_OPTLOCK) { + /* + * 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); + + STM32_FLASH_OPTKEYR(0) = FLASH_OPTKEYR_KEY1; + STM32_FLASH_OPTKEYR(0) = FLASH_OPTKEYR_KEY2; + ignore_bus_fault(0); + } + + return STM32_FLASH_OPTCR(0) & FLASH_OPTCR_OPTLOCK ? EC_ERROR_UNKNOWN + : EC_SUCCESS; +} + +static int commit_optb(void) +{ + /* might use this before timer_init, cannot use get_time/usleep */ + int timeout = (FLASH_OPT_PRG_TIMEOUT_US * + (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP); + + STM32_FLASH_OPTCR(0) |= FLASH_OPTCR_OPTSTART; + + while (STM32_FLASH_OPTSR_CUR(0) & FLASH_OPTSR_BUSY && timeout-- > 0) + ; + + STM32_FLASH_OPTCR(0) |= FLASH_OPTCR_OPTLOCK; + lock(0); + + return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT; +} + +static void protect_blocks(uint32_t blocks) +{ + if (unlock_optb()) + return; + STM32_FLASH_WPSN_PRG(0) |= blocks & BLOCKS_HWBANK_MASK; + STM32_FLASH_WPSN_PRG(1) |= (blocks >> BLOCKS_PER_HWBANK) + & BLOCKS_HWBANK_MASK; + commit_optb(); +} + +/* use the option bytes RSS1 bit as 'Write Protect enabled' flag. */ +static int is_wp_enabled(void) +{ + return !!(STM32_FLASH_OPTSR_CUR(0) & FLASH_OPTSR_RSS1); +} + +static int set_wp(int enabled) +{ + int rv; + + rv = unlock_optb(); + if (rv) + return rv; + if (enabled) + STM32_FLASH_OPTSR_PRG(0) |= FLASH_OPTSR_RSS1; + else + STM32_FLASH_OPTSR_PRG(0) &= ~FLASH_OPTSR_RSS1; + + return commit_optb(); +} + +/*****************************************************************************/ +/* Physical layer APIs */ + +int flash_physical_write(int offset, int size, const char *data) +{ + int res = EC_SUCCESS; + int bank = offset / HWBANK_SIZE; + uint32_t *address = (void *)(CONFIG_PROGRAM_MEMORY_BASE + offset); + int timeout = calculate_flash_timeout(); + int i; + int unaligned = (uint32_t)data & (CONFIG_FLASH_WRITE_SIZE - 1); + uint32_t *data32 = (void *)data; + + if (access_disabled) + return EC_ERROR_ACCESS_DENIED; + + /* work on a single hardware bank at a time */ + if ((offset + size) / HWBANK_SIZE != bank) + return EC_ERROR_INVAL; + + if (unlock(bank) != EC_SUCCESS) + return EC_ERROR_UNKNOWN; + + /* Clear previous error status */ + STM32_FLASH_CCR(bank) = FLASH_CCR_ERR_MASK; + + /* select write parallelism */ + STM32_FLASH_CR(bank) = (STM32_FLASH_CR(bank) & ~FLASH_CR_PSIZE_MASK) + | DEFAULT_PSIZE; + + /* set PG bit */ + STM32_FLASH_CR(bank) |= FLASH_CR_PG; + + for (; size > 0; size -= CONFIG_FLASH_WRITE_SIZE) { + /* + * Reload the watchdog timer to avoid watchdog reset when doing + * long writing. + */ + watchdog_reload(); + + /* write a 256-bit flash word */ + if (unaligned) { + for (i = 0; i < CONFIG_FLASH_WRITE_SIZE / 4; i++, + data += 4) + *address++ = (uint32_t)data[0] | (data[1] << 8) + | (data[2] << 16) | (data[3] << 24); + } else { + for (i = 0; i < CONFIG_FLASH_WRITE_SIZE / 4; i++) + *address++ = *data32++; + } + + /* Wait for writes to complete */ + for (i = 0; (STM32_FLASH_SR(bank) & + (FLASH_SR_WBNE | FLASH_SR_QW)) && (i < timeout); i++) + ; + + if (STM32_FLASH_SR(bank) & (FLASH_SR_WBNE | FLASH_SR_QW)) { + res = EC_ERROR_TIMEOUT; + goto exit_wr; + } + + if (STM32_FLASH_SR(bank) & FLASH_CCR_ERR_MASK) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + } + +exit_wr: + /* Disable PG bit */ + STM32_FLASH_CR(bank) &= ~FLASH_CR_PG; + + lock(bank); + + return res; +} + +int flash_physical_erase(int offset, int size) +{ + int res = EC_SUCCESS; + int bank = offset / HWBANK_SIZE; + int last = (offset + size) / CONFIG_FLASH_ERASE_SIZE; + int sect; + + if (access_disabled) + return EC_ERROR_ACCESS_DENIED; + + /* work on a single hardware bank at a time */ + if ((offset + size) / HWBANK_SIZE != bank) + return EC_ERROR_INVAL; + + if (unlock(bank) != EC_SUCCESS) + return EC_ERROR_UNKNOWN; + + /* Clear previous error status */ + STM32_FLASH_CCR(bank) = FLASH_CCR_ERR_MASK; + + /* select erase parallelism */ + STM32_FLASH_CR(bank) = (STM32_FLASH_CR(bank) & ~FLASH_CR_PSIZE_MASK) + | DEFAULT_PSIZE; + + for (sect = offset / CONFIG_FLASH_ERASE_SIZE; sect < last; sect++) { + timestamp_t deadline; + + /* select page to erase and PER bit */ + STM32_FLASH_CR(bank) = (STM32_FLASH_CR(bank) + & ~FLASH_CR_SNB_MASK) + | FLASH_CR_SER | FLASH_CR_SNB(sect); + + /* set STRT bit : start erase */ + STM32_FLASH_CR(bank) |= FLASH_CR_STRT; + + /* + * Reload the watchdog timer to avoid watchdog reset during a + * long erase operation. + */ + watchdog_reload(); + + deadline.val = get_time().val + FLASH_ERASE_TIMEOUT_US; + /* Wait for erase to complete */ + while ((STM32_FLASH_SR(bank) & FLASH_SR_BUSY) && + (get_time().val < deadline.val)) { + usleep(5000); + } + if (STM32_FLASH_SR(bank) & FLASH_SR_BUSY) { + res = EC_ERROR_TIMEOUT; + goto exit_er; + } + + /* + * Check for error conditions - erase failed, voltage error, + * protection error + */ + if (STM32_FLASH_SR(bank) & FLASH_CCR_ERR_MASK) { + res = EC_ERROR_UNKNOWN; + goto exit_er; + } + } + +exit_er: + /* reset SER bit */ + STM32_FLASH_CR(bank) &= ~(FLASH_CR_SER | FLASH_CR_SNB_MASK); + + lock(bank); + + return res; +} + +int flash_physical_get_protect(int block) +{ + int bank = block / BLOCKS_PER_HWBANK; + int index = block % BLOCKS_PER_HWBANK; + + return !(STM32_FLASH_WPSN_CUR(bank) & (1 << index)); +} + +/* + * Note: This does not need to update _NOW flags, as flash_get_protect + * in common code already does so. + */ +uint32_t flash_physical_get_protect_flags(void) +{ + uint32_t flags = 0; + + if (access_disabled) + flags |= EC_FLASH_PROTECT_ALL_NOW; + + if (is_wp_enabled()) + flags |= EC_FLASH_PROTECT_RO_AT_BOOT; + + /* Check if blocks were stuck locked at pre-init */ + if (stuck_locked) + flags |= EC_FLASH_PROTECT_ERROR_STUCK; + + return flags; +} + +#define WP_RANGE(start, count) (((1 << (count)) - 1) << (start)) +#define RO_WP_RANGE WP_RANGE(WP_BANK_OFFSET, WP_BANK_COUNT) + +int flash_physical_protect_now(int all) +{ + protect_blocks(RO_WP_RANGE); + + /* + * Lock the option bytes or the full access 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 + * permanently locked until reset, a correct keyring write + * will not unlock it. + */ + ignore_bus_fault(1); + + if (all) { + /* cannot do any write/erase access until next reboot */ + STM32_FLASH_KEYR(0) = 0xffffffff; + STM32_FLASH_KEYR(1) = 0xffffffff; + access_disabled = 1; + } + /* cannot modify the WP bits in the option bytes until reboot */ + STM32_FLASH_OPTKEYR(0) = 0xffffffff; + option_disabled = 1; + ignore_bus_fault(0); + + return EC_SUCCESS; +} + +int flash_physical_protect_at_boot(uint32_t new_flags) +{ + int new_wp_enable = !!(new_flags & EC_FLASH_PROTECT_RO_AT_BOOT); + + if (is_wp_enabled() != new_wp_enable) + return set_wp(new_wp_enable); + + return EC_SUCCESS; +} + +uint32_t flash_physical_get_valid_flags(void) +{ + return EC_FLASH_PROTECT_RO_AT_BOOT | + EC_FLASH_PROTECT_RO_NOW | + EC_FLASH_PROTECT_ALL_NOW; +} + +uint32_t flash_physical_get_writable_flags(uint32_t cur_flags) +{ + uint32_t ret = 0; + + /* If RO protection isn't enabled, its at-boot state can be changed. */ + if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW)) + ret |= EC_FLASH_PROTECT_RO_AT_BOOT; + + /* + * If entire flash isn't protected at this boot, it can be enabled if + * the WP GPIO is asserted. + */ + if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) && + (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) + ret |= EC_FLASH_PROTECT_ALL_NOW; + + return ret; +} + +int flash_pre_init(void) +{ + uint32_t reset_flags = system_get_reset_flags(); + uint32_t prot_flags = flash_get_protect(); + uint32_t unwanted_prot_flags = EC_FLASH_PROTECT_ALL_NOW | + EC_FLASH_PROTECT_ERROR_INCONSISTENT; + + /* + * 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) + return EC_SUCCESS; + + if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { + /* + * Write protect is asserted. If we want RO flash protected, + * protect it now. + */ + if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && + !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { + int rv = flash_set_protect(EC_FLASH_PROTECT_RO_NOW, + EC_FLASH_PROTECT_RO_NOW); + if (rv) + return rv; + + /* Re-read flags */ + prot_flags = flash_get_protect(); + } + } else { + /* Don't want RO flash protected */ + unwanted_prot_flags |= EC_FLASH_PROTECT_RO_NOW; + } + + /* If there are no unwanted flags, done */ + if (!(prot_flags & unwanted_prot_flags)) + return EC_SUCCESS; + + /* + * If the last reboot was a power-on reset, it should have cleared + * write-protect. If it didn't, then the flash write protect registers + * have been permanently committed and we can't fix that. + */ + if (reset_flags & RESET_FLAG_POWER_ON) { + stuck_locked = 1; + return EC_ERROR_ACCESS_DENIED; + } + + /* Otherwise, do a hard boot to clear the flash protection registers */ + system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); + + /* That doesn't return, so if we're still here that's an error */ + return EC_ERROR_UNKNOWN; +} diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 76b89e9f23..24fe527658 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -1897,7 +1897,10 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_OPT_LOCK_MASK(_block) ((0xFF << ((_block) % 4) * 8)) #elif defined(CHIP_FAMILY_STM32H7) -#define STM32_FLASH_ACR REG32(STM32_FLASH_REGS_BASE + 0x00) +#define STM32_FLASH_REG(bank, offset) REG32(((bank) ? 0x100 : 0) + \ + STM32_FLASH_REGS_BASE + (offset)) + +#define STM32_FLASH_ACR(bank) STM32_FLASH_REG(bank, 0x00) #define STM32_FLASH_ACR_LATENCY_SHIFT (0) #define STM32_FLASH_ACR_LATENCY_MASK (7 << STM32_FLASH_ACR_LATENCY_SHIFT) #define STM32_FLASH_ACR_WRHIGHFREQ_85MHZ (0 << 4) @@ -1905,6 +1908,71 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_FLASH_ACR_WRHIGHFREQ_285MHZ (2 << 4) #define STM32_FLASH_ACR_WRHIGHFREQ_385MHZ (3 << 4) +#define STM32_FLASH_KEYR(bank) STM32_FLASH_REG(bank, 0x04) +#define FLASH_KEYR_KEY1 0x45670123 +#define FLASH_KEYR_KEY2 0xCDEF89AB +#define STM32_FLASH_OPTKEYR(bank) STM32_FLASH_REG(bank, 0x08) +#define FLASH_OPTKEYR_KEY1 0x08192A3B +#define FLASH_OPTKEYR_KEY2 0x4C5D6E7F +#define STM32_FLASH_CR(bank) STM32_FLASH_REG(bank, 0x0C) +#define FLASH_CR_LOCK (1 << 0) +#define FLASH_CR_PG (1 << 1) +#define FLASH_CR_SER (1 << 2) +#define FLASH_CR_BER (1 << 3) +#define FLASH_CR_PSIZE_BYTE (0 << 4) +#define FLASH_CR_PSIZE_HWORD (1 << 4) +#define FLASH_CR_PSIZE_WORD (2 << 4) +#define FLASH_CR_PSIZE_DWORD (3 << 4) +#define FLASH_CR_PSIZE_MASK (3 << 4) +#define FLASH_CR_FW (1 << 6) +#define FLASH_CR_STRT (1 << 7) +#define FLASH_CR_SNB(sec) (((sec) & 0x7) << 8) +#define FLASH_CR_SNB_MASK FLASH_CR_SNB(0x7) +#define STM32_FLASH_SR(bank) STM32_FLASH_REG(bank, 0x10) +#define FLASH_SR_BUSY (1 << 0) +#define FLASH_SR_WBNE (1 << 1) +#define FLASH_SR_QW (1 << 2) +#define FLASH_SR_CRC_BUSY (1 << 3) +#define FLASH_SR_EOP (1 << 16) +#define FLASH_SR_WRPERR (1 << 17) +#define FLASH_SR_PGSERR (1 << 18) +#define FLASH_SR_STRBERR (1 << 19) +#define FLASH_SR_INCERR (1 << 21) +#define FLASH_SR_OPERR (1 << 22) +#define FLASH_SR_RDPERR (1 << 23) +#define FLASH_SR_RDSERR (1 << 24) +#define FLASH_SR_SNECCERR (1 << 25) +#define FLASH_SR_DBECCERR (1 << 26) +#define FLASH_SR_CRCEND (1 << 27) +#define STM32_FLASH_CCR(bank) STM32_FLASH_REG(bank, 0x14) +#define FLASH_CCR_ERR_MASK (FLASH_SR_WRPERR | FLASH_SR_PGSERR \ + | FLASH_SR_STRBERR | FLASH_SR_INCERR \ + | FLASH_SR_OPERR | FLASH_SR_RDPERR \ + | FLASH_SR_RDSERR | FLASH_SR_SNECCERR \ + | FLASH_SR_DBECCERR) +#define STM32_FLASH_OPTCR(bank) STM32_FLASH_REG(bank, 0x18) +#define FLASH_OPTCR_OPTLOCK (1 << 0) +#define FLASH_OPTCR_OPTSTART (1 << 1) +#define STM32_FLASH_OPTSR_CUR(bank) STM32_FLASH_REG(bank, 0x1C) +#define STM32_FLASH_OPTSR_PRG(bank) STM32_FLASH_REG(bank, 0x20) +#define FLASH_OPTSR_BUSY (1 << 0) /* only in OPTSR_CUR */ +#define FLASH_OPTSR_RSS1 (1 << 26) +#define FLASH_OPTSR_RSS2 (1 << 27) +#define STM32_FLASH_OPTCCR(bank) STM32_FLASH_REG(bank, 0x24) +#define STM32_FLASH_PRAR_CUR(bank) STM32_FLASH_REG(bank, 0x28) +#define STM32_FLASH_PRAR_PRG(bank) STM32_FLASH_REG(bank, 0x2C) +#define STM32_FLASH_SCAR_CUR(bank) STM32_FLASH_REG(bank, 0x30) +#define STM32_FLASH_SCAR_PRG(bank) STM32_FLASH_REG(bank, 0x34) +#define STM32_FLASH_WPSN_CUR(bank) STM32_FLASH_REG(bank, 0x38) +#define STM32_FLASH_WPSN_PRG(bank) STM32_FLASH_REG(bank, 0x3C) +#define STM32_FLASH_BOOT_CUR(bank) STM32_FLASH_REG(bank, 0x40) +#define STM32_FLASH_BOOT_PRG(bank) STM32_FLASH_REG(bank, 0x44) +#define STM32_FLASH_CRC_CR(bank) STM32_FLASH_REG(bank, 0x50) +#define STM32_FLASH_CRC_SADDR(bank) STM32_FLASH_REG(bank, 0x54) +#define STM32_FLASH_CRC_EADDR(bank) STM32_FLASH_REG(bank, 0x58) +#define STM32_FLASH_CRC_DATA(bank) STM32_FLASH_REG(bank, 0x5C) +#define STM32_FLASH_ECC_FA(bank) STM32_FLASH_REG(bank, 0x60) + #else #error Unsupported chip variant #endif diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 24174cfb2d..703586c135 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -425,5 +425,10 @@ void bus_fault_handler(void) void ignore_bus_fault(int ignored) { + /* + * Flash code might call this before cpu_init(), + * ensure that the bus faults really go through our handler. + */ + CPU_NVIC_SHCSR |= CPU_NVIC_SHCSR_BUSFAULTENA; bus_fault_ignored = ignored; } -- cgit v1.2.1