mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-12 19:04:59 +00:00
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 <vpalatin@chromium.org> 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 <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
4ee04e1c4a
commit
730491df20
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
468
chip/stm32/flash-stm32h7.c
Normal file
468
chip/stm32/flash-stm32h7.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user