summaryrefslogtreecommitdiff
path: root/chip/stm32/flash-f.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /chip/stm32/flash-f.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14528.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'chip/stm32/flash-f.c')
-rw-r--r--chip/stm32/flash-f.c833
1 files changed, 0 insertions, 833 deletions
diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c
deleted file mode 100644
index 9e35a2c689..0000000000
--- a/chip/stm32/flash-f.c
+++ /dev/null
@@ -1,833 +0,0 @@
-/* Copyright 2014 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.
- */
-
-/* Common flash memory module for STM32F and STM32F0 */
-
-#include <stdbool.h>
-#include "battery.h"
-#include "console.h"
-#include "clock.h"
-#include "flash.h"
-#include "flash-f.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"
-
-#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
-
-/*
- * Approximate number of CPU cycles per iteration of the loop when polling
- * the flash status
- */
-#define CYCLE_PER_FLASH_LOOP 10
-
-/*
- * While flash write / erase is in progress, the stm32 CPU core is mostly
- * non-functional, due to the inability to fetch instructions from flash.
- * This may greatly increase interrupt latency.
- */
-
-/* Flash page programming timeout. This is 2x the datasheet max. */
-#define FLASH_WRITE_TIMEOUT_US 16000
-/* 20ms < tERASE < 40ms on F0/F3, for 1K / 2K sector size. */
-#define FLASH_ERASE_TIMEOUT_US 40000
-
-#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE)
-#if !defined(CHIP_FAMILY_STM32F4)
-#error "CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE should work with all STM32F "
-"series chips, but has not been tested"
-#endif /* !CHIP_FAMILY_STM32F4 */
-#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */
-
-/* Forward declarations */
-#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE)
-static enum flash_rdp_level flash_physical_get_rdp_level(void);
-static int flash_physical_set_rdp_level(enum flash_rdp_level level);
-#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */
-
-static inline int calculate_flash_timeout(void)
-{
- return (FLASH_WRITE_TIMEOUT_US *
- (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP);
-}
-
-static int wait_busy(void)
-{
- int timeout = calculate_flash_timeout();
- while ((STM32_FLASH_SR & FLASH_SR_BUSY) && timeout-- > 0)
- udelay(CYCLE_PER_FLASH_LOOP);
- return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
-}
-
-
-void unlock_flash_control_register(void)
-{
- STM32_FLASH_KEYR = FLASH_KEYR_KEY1;
- STM32_FLASH_KEYR = FLASH_KEYR_KEY2;
-}
-
-void unlock_flash_option_bytes(void)
-{
- STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
- STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
-}
-
-void disable_flash_option_bytes(void)
-{
- ignore_bus_fault(1);
- /*
- * Writing anything other than the pre-defined keys to the option key
- * register results in a bus fault and the register being locked until
- * reboot (even with a further correct key write).
- */
- STM32_FLASH_OPTKEYR = 0xffffffff;
- ignore_bus_fault(0);
-}
-
-void disable_flash_control_register(void)
-{
- ignore_bus_fault(1);
- /*
- * Writing anything other than the pre-defined keys to the key
- * register results in a bus fault and the register being locked until
- * reboot (even with a further correct key write).
- */
- STM32_FLASH_KEYR = 0xffffffff;
- ignore_bus_fault(0);
-}
-
-void lock_flash_control_register(void)
-{
-#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3)
- /* FLASH_CR_OPTWRE was set by writing the keys in unlock(). */
- STM32_FLASH_CR &= ~FLASH_CR_OPTWRE;
-#endif
- STM32_FLASH_CR |= FLASH_CR_LOCK;
-}
-
-void lock_flash_option_bytes(void)
-{
-#if !(defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3))
- STM32_FLASH_OPTCR |= FLASH_OPTLOCK;
-#endif
-}
-
-bool flash_option_bytes_locked(void)
-{
- return !!STM32_FLASH_OPT_LOCKED;
-}
-
-bool flash_control_register_locked(void)
-{
- return !!(STM32_FLASH_CR & FLASH_CR_LOCK);
-}
-
-/*
- * We at least unlock the control register lock.
- * We may also unlock other locks.
- */
-enum extra_lock_type {
- NO_EXTRA_LOCK = 0,
- OPT_LOCK = 1,
-};
-
-static int unlock(int locks)
-{
- /*
- * 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);
-
- /* Always unlock CR if needed */
- if (flash_control_register_locked())
- unlock_flash_control_register();
-
- /* unlock option memory if required */
- if ((locks & OPT_LOCK) && flash_option_bytes_locked())
- unlock_flash_option_bytes();
-
- /* Re-enable bus fault handler */
- ignore_bus_fault(0);
-
- if ((locks & OPT_LOCK) && flash_option_bytes_locked())
- return EC_ERROR_UNKNOWN;
- if (STM32_FLASH_CR & FLASH_CR_LOCK)
- return EC_ERROR_UNKNOWN;
- return EC_SUCCESS;
-}
-
-static void lock(void)
-{
- lock_flash_control_register();
-}
-
-#ifdef CHIP_FAMILY_STM32F4
-static int write_optb(uint32_t mask, uint32_t value)
-{
- int rv;
-
- rv = wait_busy();
- if (rv)
- return rv;
-
- /* The target byte is the value we want to write. */
- if ((STM32_FLASH_OPTCR & mask) == value)
- return EC_SUCCESS;
-
- rv = unlock(OPT_LOCK);
- if (rv)
- return rv;
-
- STM32_FLASH_OPTCR = (STM32_FLASH_OPTCR & ~mask) | value;
- STM32_FLASH_OPTCR |= FLASH_OPTSTRT;
-
- rv = wait_busy();
- if (rv)
- return rv;
- lock();
-
- return EC_SUCCESS;
-}
-#else
-static int write_optb(int byte, uint8_t value);
-/*
- * Option byte organization
- *
- * [31:24] [23:16] [15:8] [7:0]
- *
- * 0x1FFF_F800 nUSER USER nRDP RDP
- *
- * 0x1FFF_F804 nData1 Data1 nData0 Data0
- *
- * 0x1FFF_F808 nWRP1 WRP1 nWRP0 WRP0
- *
- * 0x1FFF_F80C nWRP3 WRP2 nWRP2 WRP2
- *
- * Note that the variable with n prefix means the complement.
- */
-static uint8_t read_optb(int byte)
-{
- return *(uint8_t *)(STM32_OPTB_BASE + byte);
-}
-
-static int erase_optb(void)
-{
- int rv;
-
- rv = wait_busy();
- if (rv)
- return rv;
-
- rv = unlock(OPT_LOCK);
- if (rv)
- return rv;
-
- /* Must be set in 2 separate lines. */
- STM32_FLASH_CR |= FLASH_CR_OPTER;
- STM32_FLASH_CR |= FLASH_CR_STRT;
-
- rv = wait_busy();
-
- STM32_FLASH_CR &= ~FLASH_CR_OPTER;
-
- if (rv)
- return rv;
- lock();
-
- return EC_SUCCESS;
-}
-
-static int write_optb(int byte, uint8_t value);
-/*
- * Since the option byte erase is WHOLE erase, this function is to keep
- * rest of bytes, but make this byte 0xff.
- * Note that this could make a recursive call to write_optb().
- */
-static int preserve_optb(int byte)
-{
- int i, rv;
- uint8_t optb[8];
-
- /* The byte has been reset, no need to run preserve. */
- if (*(uint16_t *)(STM32_OPTB_BASE + byte) == 0xffff)
- return EC_SUCCESS;
-
- for (i = 0; i < ARRAY_SIZE(optb); ++i)
- optb[i] = read_optb(i * 2);
-
- optb[byte / 2] = 0xff;
-
- rv = erase_optb();
- if (rv)
- return rv;
- for (i = 0; i < ARRAY_SIZE(optb); ++i) {
- rv = write_optb(i * 2, optb[i]);
- if (rv)
- return rv;
- }
-
- return EC_SUCCESS;
-}
-
-static int write_optb(int byte, uint8_t value)
-{
- volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte);
- int rv;
-
- rv = wait_busy();
- if (rv)
- return rv;
-
- /* The target byte is the value we want to write. */
- if (*(uint8_t *)hword == value)
- return EC_SUCCESS;
-
- /* Try to erase that byte back to 0xff. */
- rv = preserve_optb(byte);
- if (rv)
- return rv;
-
- /* The value is 0xff after erase. No need to write 0xff again. */
- if (value == 0xff)
- return EC_SUCCESS;
-
- rv = unlock(OPT_LOCK);
- if (rv)
- return rv;
-
- /* set OPTPG bit */
- STM32_FLASH_CR |= FLASH_CR_OPTPG;
-
- *hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value;
-
- /* reset OPTPG bit */
- STM32_FLASH_CR &= ~FLASH_CR_OPTPG;
-
- rv = wait_busy();
- if (rv)
- return rv;
- lock();
-
- return EC_SUCCESS;
-}
-#endif
-
-#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE)
-/**
- * @return true if RDP (read protection) Level 1 or 2 enabled, false otherwise
- */
-bool is_flash_rdp_enabled(void)
-{
- enum flash_rdp_level level = flash_physical_get_rdp_level();
-
- if (level == FLASH_RDP_LEVEL_INVALID) {
- CPRINTS("ERROR: unable to read RDP level");
- return false;
- }
-
- return level != FLASH_RDP_LEVEL_0;
-}
-#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */
-
-/*****************************************************************************/
-/* Physical layer APIs */
-
-int crec_flash_physical_write(int offset, int size, const char *data)
-{
-#if CONFIG_FLASH_WRITE_SIZE == 1
- uint8_t *address = (uint8_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
- uint8_t quantum = 0;
-#elif CONFIG_FLASH_WRITE_SIZE == 2
- uint16_t *address = (uint16_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
- uint16_t quantum = 0;
-#elif CONFIG_FLASH_WRITE_SIZE == 4
- uint32_t *address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
- uint32_t quantum = 0;
-#else
-#error "CONFIG_FLASH_WRITE_SIZE not supported."
-#endif
- int res = EC_SUCCESS;
- int timeout = calculate_flash_timeout();
-
- if (unlock(NO_EXTRA_LOCK) != EC_SUCCESS) {
- res = EC_ERROR_UNKNOWN;
- goto exit_wr;
- }
-
- /* Clear previous error status */
- STM32_FLASH_SR = FLASH_SR_ALL_ERR | FLASH_SR_EOP;
-
- /* set PG bit */
- STM32_FLASH_CR |= FLASH_CR_PG;
-
- for (; size > 0; size -= CONFIG_FLASH_WRITE_SIZE) {
- int i;
-
- for (i = CONFIG_FLASH_WRITE_SIZE - 1, quantum = 0; i >= 0; i--)
- quantum = (quantum << 8) + data[i];
- data += CONFIG_FLASH_WRITE_SIZE;
- /*
- * Reload the watchdog timer to avoid watchdog reset when doing
- * long writing with interrupt disabled.
- */
- watchdog_reload();
-
- /* wait to be ready */
- for (i = 0;
- (STM32_FLASH_SR & FLASH_SR_BUSY) &&
- (i < timeout);
- i++)
- ;
-
- /* write the data */
- *address++ = quantum;
-
- /* Wait for writes to complete */
- for (i = 0;
- (STM32_FLASH_SR & FLASH_SR_BUSY) &&
- (i < timeout);
- i++)
- ;
-
- 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_ALL_ERR) {
- res = EC_ERROR_UNKNOWN;
- goto exit_wr;
- }
- }
-
-exit_wr:
- /* Disable PG bit */
- STM32_FLASH_CR &= ~FLASH_CR_PG;
-
- lock();
-
- return res;
-}
-
-int crec_flash_physical_erase(int offset, int size)
-{
- int res = EC_SUCCESS;
- int sector_size;
- int timeout_us;
-#ifdef CHIP_FAMILY_STM32F4
- int sector = crec_flash_bank_index(offset);
- /* we take advantage of sector_size == erase_size */
- if ((sector < 0) || (crec_flash_bank_index(offset + size) < 0))
- return EC_ERROR_INVAL; /* Invalid range */
-#endif
-
- if (unlock(NO_EXTRA_LOCK) != EC_SUCCESS)
- return EC_ERROR_UNKNOWN;
-
- /* Clear previous error status */
- STM32_FLASH_SR = FLASH_SR_ALL_ERR | FLASH_SR_EOP;
-
- /* set SER/PER bit */
- STM32_FLASH_CR |= FLASH_CR_PER;
-
- while (size > 0) {
- timestamp_t deadline;
-#ifdef CHIP_FAMILY_STM32F4
- sector_size = crec_flash_bank_size(sector);
- /* Timeout: from spec, proportional to the size
- * inversely proportional to the write size.
- */
- timeout_us = sector_size * 4 / CONFIG_FLASH_WRITE_SIZE;
-#else
- sector_size = CONFIG_FLASH_ERASE_SIZE;
- timeout_us = FLASH_ERASE_TIMEOUT_US;
-#endif
- /* Do nothing if already erased */
- if (crec_flash_is_erased(offset, sector_size))
- goto next_sector;
-#ifdef CHIP_FAMILY_STM32F4
- /* select page to erase */
- STM32_FLASH_CR = (STM32_FLASH_CR & ~STM32_FLASH_CR_SNB_MASK) |
- (sector << STM32_FLASH_CR_SNB_OFFSET);
-#else
- /* select page to erase */
- STM32_FLASH_AR = CONFIG_PROGRAM_MEMORY_BASE + offset;
-#endif
- /* set STRT bit : start erase */
- STM32_FLASH_CR |= FLASH_CR_STRT;
-
- deadline.val = get_time().val + timeout_us;
- /* Wait for erase to complete */
- watchdog_reload();
- while ((STM32_FLASH_SR & FLASH_SR_BUSY) &&
- (get_time().val < deadline.val)) {
- usleep(timeout_us/100);
- }
- if (STM32_FLASH_SR & FLASH_SR_BUSY) {
- res = EC_ERROR_TIMEOUT;
- goto exit_er;
- }
-
- /*
- * Check for error conditions - erase failed, voltage error,
- * protection error
- */
- if (STM32_FLASH_SR & FLASH_SR_ALL_ERR) {
- res = EC_ERROR_UNKNOWN;
- goto exit_er;
- }
-next_sector:
- size -= sector_size;
- offset += sector_size;
-#ifdef CHIP_FAMILY_STM32F4
- sector++;
-#endif
- }
-
-exit_er:
- /* reset SER/PER bit */
- STM32_FLASH_CR &= ~FLASH_CR_PER;
-
- lock();
-
- return res;
-}
-
-#ifdef CHIP_FAMILY_STM32F4
-static int flash_physical_get_protect_at_boot(int block)
-{
- /* 0: Write protection active on sector i. */
- return !(STM32_OPTB_WP & STM32_OPTB_nWRP(block));
-}
-
-static int flash_physical_protect_at_boot_update_rdp_pstate(uint32_t new_flags)
-{
-#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE)
- int rv = EC_SUCCESS;
-
- bool rdp_enable = (new_flags & EC_FLASH_PROTECT_RO_AT_BOOT) != 0;
-
- /*
- * This is intentionally a one-way latch. Once we have enabled RDP
- * Level 1, we will only allow going back to Level 0 using the
- * bootloader (e.g., "stm32mon -U") since transitioning from Level 1 to
- * Level 0 triggers a mass erase.
- */
- if (rdp_enable)
- rv = flash_physical_set_rdp_level(FLASH_RDP_LEVEL_1);
-
- return rv;
-#else
- return EC_SUCCESS;
-#endif
-}
-
-int crec_flash_physical_protect_at_boot(uint32_t new_flags)
-{
- int block;
- int original_val, val;
-
- original_val = val = STM32_OPTB_WP & STM32_OPTB_nWRP_ALL;
-
- for (block = WP_BANK_OFFSET;
- block < WP_BANK_OFFSET + PHYSICAL_BANKS;
- block++) {
- int protect = new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT;
-
- if (block >= WP_BANK_OFFSET &&
- block < WP_BANK_OFFSET + WP_BANK_COUNT)
- protect |= new_flags & EC_FLASH_PROTECT_RO_AT_BOOT;
-#ifdef CONFIG_FLASH_PROTECT_RW
- else
- protect |= new_flags & EC_FLASH_PROTECT_RW_AT_BOOT;
-#endif
-
- if (protect)
- val &= ~BIT(block);
- else
- val |= 1 << block;
- }
- if (original_val != val) {
- int rv = write_optb(STM32_FLASH_nWRP_ALL,
- val << STM32_FLASH_nWRP_OFFSET);
- if (rv != EC_SUCCESS)
- return rv;
- }
-
- return flash_physical_protect_at_boot_update_rdp_pstate(new_flags);
-}
-
-static void unprotect_all_blocks(void)
-{
- write_optb(STM32_FLASH_nWRP_ALL, STM32_FLASH_nWRP_ALL);
-}
-
-#else /* CHIP_FAMILY_STM32F4 */
-static int flash_physical_get_protect_at_boot(int block)
-{
- uint8_t val = read_optb(STM32_OPTB_WRP_OFF(block/8));
- return (!(val & (1 << (block % 8)))) ? 1 : 0;
-}
-
-int crec_flash_physical_protect_at_boot(uint32_t new_flags)
-{
- int block;
- int i;
- int original_val[4], val[4];
-
- for (i = 0; i < 4; ++i)
- original_val[i] = val[i] = read_optb(i * 2 + 8);
-
- for (block = WP_BANK_OFFSET;
- block < WP_BANK_OFFSET + PHYSICAL_BANKS;
- block++) {
- int protect = new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT;
- int byte_off = STM32_OPTB_WRP_OFF(block/8) / 2 - 4;
-
- if (block >= WP_BANK_OFFSET &&
- block < WP_BANK_OFFSET + WP_BANK_COUNT)
- protect |= new_flags & EC_FLASH_PROTECT_RO_AT_BOOT;
-#ifdef CONFIG_ROLLBACK
- else if (block >= ROLLBACK_BANK_OFFSET &&
- block < ROLLBACK_BANK_OFFSET + ROLLBACK_BANK_COUNT)
- protect |= new_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
-#endif
-#ifdef CONFIG_FLASH_PROTECT_RW
- else
- protect |= new_flags & EC_FLASH_PROTECT_RW_AT_BOOT;
-#endif
-
- if (protect)
- val[byte_off] = val[byte_off] & (~(1 << (block % 8)));
- else
- val[byte_off] = val[byte_off] | (1 << (block % 8));
- }
-
- for (i = 0; i < 4; ++i)
- if (original_val[i] != val[i])
- write_optb(i * 2 + 8, val[i]);
-
-#ifdef CONFIG_FLASH_READOUT_PROTECTION
- /*
- * Set a permanent protection by increasing RDP to level 1,
- * trying to unprotected the flash will trigger a full erase.
- */
- write_optb(0, 0x11);
-#endif
-
- return EC_SUCCESS;
-}
-
-static void unprotect_all_blocks(void)
-{
- int i;
-
- for (i = 4; i < 8; ++i)
- write_optb(i * 2, 0xff);
-}
-#endif
-
-/**
- * Check if write protect register state is inconsistent with RO_AT_BOOT and
- * ALL_AT_BOOT state.
- *
- * @return zero if consistent, non-zero if inconsistent.
- */
-static int registers_need_reset(void)
-{
- uint32_t flags = crec_flash_get_protect();
- int i;
- int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0;
- int ro_wp_region_start = WP_BANK_OFFSET;
- int ro_wp_region_end = WP_BANK_OFFSET + WP_BANK_COUNT;
-
- for (i = ro_wp_region_start; i < ro_wp_region_end; i++)
- if (flash_physical_get_protect_at_boot(i) != ro_at_boot)
- return 1;
- return 0;
-}
-
-#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE)
-/**
- * Set Flash RDP (read protection) level.
- *
- * @note Does not take effect until reset.
- *
- * @param level new RDP (read protection) level to set
- * @return EC_SUCCESS on success, other on failure
- */
-int flash_physical_set_rdp_level(enum flash_rdp_level level)
-{
- uint32_t reg_level;
-
- switch (level) {
- case FLASH_RDP_LEVEL_0:
- /*
- * Asserting by default since we don't want to inadvertently
- * go from Level 1 to Level 0, which triggers a mass erase.
- * Remove assert if you want to use it.
- */
- ASSERT(false);
- reg_level = FLASH_OPTCR_RDP_LEVEL_0;
- break;
- case FLASH_RDP_LEVEL_1:
- reg_level = FLASH_OPTCR_RDP_LEVEL_1;
- break;
- case FLASH_RDP_LEVEL_2:
- /*
- * Asserting by default since it's permanent (there is no
- * way to reverse). Remove assert if you want to use it.
- */
- ASSERT(false);
- reg_level = FLASH_OPTCR_RDP_LEVEL_2;
- break;
- default:
- return EC_ERROR_INVAL;
- }
-
- return write_optb(FLASH_OPTCR_RDP_MASK, reg_level);
-}
-
-/**
- * @return On success, current flash read protection level.
- * On failure, FLASH_RDP_LEVEL_INVALID
- */
-enum flash_rdp_level flash_physical_get_rdp_level(void)
-{
- uint32_t level = (STM32_FLASH_OPTCR & FLASH_OPTCR_RDP_MASK);
-
- switch (level) {
- case FLASH_OPTCR_RDP_LEVEL_0:
- return FLASH_RDP_LEVEL_0;
- case FLASH_OPTCR_RDP_LEVEL_1:
- return FLASH_RDP_LEVEL_1;
- case FLASH_OPTCR_RDP_LEVEL_2:
- return FLASH_RDP_LEVEL_2;
- default:
- return FLASH_RDP_LEVEL_INVALID;
- }
-}
-#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */
-
-/*****************************************************************************/
-/* High-level APIs */
-
-int crec_flash_pre_init(void)
-{
- uint32_t reset_flags = system_get_reset_flags();
- uint32_t prot_flags = crec_flash_get_protect();
- int need_reset = 0;
-
-
-#ifdef CHIP_FAMILY_STM32F4
- unlock(NO_EXTRA_LOCK);
- /* Set the proper write size */
- STM32_FLASH_CR = (STM32_FLASH_CR & ~STM32_FLASH_CR_PSIZE_MASK) |
- (31 - __builtin_clz(CONFIG_FLASH_WRITE_SIZE)) <<
- STM32_FLASH_CR_PSIZE_OFFSET;
- lock();
-#endif
- if (crec_flash_physical_restore_state())
- return EC_SUCCESS;
-
- /*
- * If we have already jumped between images, an earlier image could
- * have applied write protection. Nothing additional needs to be done.
- */
- if (reset_flags & EC_RESET_FLAG_SYSJUMP)
- return EC_SUCCESS;
-
- if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
- if (prot_flags & EC_FLASH_PROTECT_RO_NOW) {
- /* Enable physical protection for RO (0 means RO). */
- crec_flash_physical_protect_now(0);
- }
-
- if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) &&
- !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) {
- /*
- * Pstate wants RO protected at boot, but the write
- * protect register wasn't set to protect it. Force an
- * update to the write protect register and reboot so
- * it takes effect.
- */
- crec_flash_physical_protect_at_boot(
- EC_FLASH_PROTECT_RO_AT_BOOT);
- need_reset = 1;
- }
-
- if (registers_need_reset()) {
- /*
- * Write protect register was in an inconsistent state.
- * Set it back to a good state and reboot.
- *
- * TODO(crosbug.com/p/23798): this seems really similar
- * to the check above. One of them should be able to
- * go away.
- */
- crec_flash_protect_at_boot(
- prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT);
- need_reset = 1;
- }
- } else {
- if (prot_flags & EC_FLASH_PROTECT_RO_NOW) {
- /*
- * Write protect pin unasserted but some section is
- * protected. Drop it and reboot.
- */
- unprotect_all_blocks();
- need_reset = 1;
- }
- }
-
- if ((crec_flash_physical_get_valid_flags() &
- EC_FLASH_PROTECT_ALL_AT_BOOT) &&
- (!!(prot_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) !=
- !!(prot_flags & EC_FLASH_PROTECT_ALL_NOW))) {
- /*
- * ALL_AT_BOOT and ALL_NOW should be both set or both unset
- * at boot. If they are not, it must be that the chip requires
- * OBL_LAUNCH to be set to reload option bytes. Let's reset
- * the system with OBL_LAUNCH set.
- * This assumes OBL_LAUNCH is used for hard reset in
- * chip/stm32/system.c.
- */
- need_reset = 1;
- }
-
-#ifdef CONFIG_FLASH_PROTECT_RW
- if ((crec_flash_physical_get_valid_flags() &
- EC_FLASH_PROTECT_RW_AT_BOOT) &&
- (!!(prot_flags & EC_FLASH_PROTECT_RW_AT_BOOT) !=
- !!(prot_flags & EC_FLASH_PROTECT_RW_NOW))) {
- /* RW_AT_BOOT and RW_NOW do not match. */
- need_reset = 1;
- }
-#endif
-
-#ifdef CONFIG_ROLLBACK
- if ((crec_flash_physical_get_valid_flags() &
- EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) &&
- (!!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) !=
- !!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_NOW))) {
- /* ROLLBACK_AT_BOOT and ROLLBACK_NOW do not match. */
- need_reset = 1;
- }
-#endif
-
- if (need_reset)
- system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
-
- return EC_SUCCESS;
-}