Factor out common flash code for STM32F and STM32F0

This is a preparatory work for the following change for write protection
support on STM32F0.

BUG=chrome-os-partner:32745
TEST=make buildall
BRANCH=samus

Change-Id: Ic4deea06e26c4a6ac024a5388e1a5783b40e9876
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/222660
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Vic Yang
2014-10-09 14:04:32 -07:00
committed by chrome-internal-fetch
parent b8f73a451d
commit 4a9cabc3f9
7 changed files with 486 additions and 431 deletions

View File

@@ -92,14 +92,17 @@ _rw_size_str:=$(shell echo "CONFIG_FW_RW_SIZE" | $(CPP) $(CPPFLAGS) -P \
-Ichip/$(CHIP) -Iboard/$(BOARD) -imacros include/config.h)
_rw_size:=$(shell echo "$$(($(_rw_size_str)))")
$(eval BOARD_$(UC_BOARD)=y)
$(eval CHIP_$(UC_CHIP)=y)
$(eval CHIP_VARIANT_$(UC_CHIP_VARIANT)=y)
$(eval CHIP_FAMILY_$(UC_CHIP_FAMILY)=y)
# Get build configuration from sub-directories
# Note that this re-includes the board and chip makefiles
include board/$(BOARD)/build.mk
include chip/$(CHIP)/build.mk
include core/$(CORE)/build.mk
$(eval BOARD_$(UC_BOARD)=y)
include common/build.mk
include driver/build.mk
include power/build.mk

View File

@@ -35,6 +35,9 @@ chip-$(HAS_TASK_CONSOLE)+=uart.o
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
chip-$(HAS_TASK_POWERLED)+=power_led.o
chip-$(CONFIG_FLASH)+=flash-$(CHIP_FAMILY).o
chip-$(CHIP_FAMILY_STM32F)+=flash-f.o
chip-$(CHIP_FAMILY_STM32F0)+=flash-f.o
chip-$(CHIP_FAMILY_STM32F3)+=flash-f.o
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_USB)+=usb.o usb_endpoints.o

448
chip/stm32/flash-f.c Normal file
View File

@@ -0,0 +1,448 @@
/* 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 "battery.h"
#include "console.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 10
/* Flash page programming timeout. This is 2x the datasheet max. */
#define FLASH_TIMEOUT_US 16000
#define FLASH_TIMEOUT_LOOP \
(FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP)
/* Flash unlocking keys */
#define KEY1 0x45670123
#define KEY2 0xCDEF89AB
/* Lock bits for FLASH_CR register */
#define PG (1<<0)
#define PER (1<<1)
#define OPTPG (1<<4)
#define OPTER (1<<5)
#define STRT (1<<6)
#define CR_LOCK (1<<7)
#define PRG_LOCK 0
#define OPT_LOCK (1<<9)
static int write_optb(int byte, uint8_t value);
static int wait_busy(void)
{
int timeout = FLASH_TIMEOUT_LOOP;
while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0)
udelay(CYCLE_PER_FLASH_LOOP);
return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
}
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);
/* unlock CR if needed */
if (STM32_FLASH_CR & CR_LOCK) {
STM32_FLASH_KEYR = KEY1;
STM32_FLASH_KEYR = KEY2;
}
/* unlock option memory if required */
if ((locks & OPT_LOCK) && !(STM32_FLASH_CR & OPT_LOCK)) {
STM32_FLASH_OPTKEYR = KEY1;
STM32_FLASH_OPTKEYR = KEY2;
}
/* Re-enable bus fault handler */
ignore_bus_fault(0);
return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ?
EC_ERROR_UNKNOWN : EC_SUCCESS;
}
static void lock(void)
{
STM32_FLASH_CR = CR_LOCK;
}
/*
* 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 |= OPTER;
STM32_FLASH_CR |= STRT;
rv = wait_busy();
if (rv)
return rv;
lock();
return EC_SUCCESS;
}
/*
* 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 |= OPTPG;
*hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value;
/* reset OPTPG bit */
STM32_FLASH_CR &= ~OPTPG;
rv = wait_busy();
if (rv)
return rv;
lock();
return EC_SUCCESS;
}
/*****************************************************************************/
/* Physical layer APIs */
int flash_physical_write(int offset, int size, const char *data)
{
uint16_t *address = (uint16_t *)(CONFIG_FLASH_BASE + offset);
int res = EC_SUCCESS;
int i;
if (unlock(PRG_LOCK) != EC_SUCCESS) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
/* Clear previous error status */
STM32_FLASH_SR = 0x34;
/* set PG bit */
STM32_FLASH_CR |= PG;
for (; size > 0; size -= sizeof(uint16_t)) {
/*
* 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 & 1) && (i < FLASH_TIMEOUT_LOOP);
i++)
;
/* write the half word */
*address++ = data[0] + (data[1] << 8);
data += 2;
/* Wait for writes to complete */
for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP);
i++)
;
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
}
/* Check for error conditions - erase failed, voltage error,
* protection error */
if (STM32_FLASH_SR & 0x14) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
}
exit_wr:
/* Disable PG bit */
STM32_FLASH_CR &= ~PG;
lock();
return res;
}
int flash_physical_erase(int offset, int size)
{
int res = EC_SUCCESS;
if (unlock(PRG_LOCK) != EC_SUCCESS)
return EC_ERROR_UNKNOWN;
/* Clear previous error status */
STM32_FLASH_SR = 0x34;
/* set PER bit */
STM32_FLASH_CR |= PER;
for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
offset += CONFIG_FLASH_ERASE_SIZE) {
timestamp_t deadline;
/* Do nothing if already erased */
if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE))
continue;
/* select page to erase */
STM32_FLASH_AR = CONFIG_FLASH_BASE + offset;
/* set STRT bit : start erase */
STM32_FLASH_CR |= STRT;
/*
* Reload the watchdog timer to avoid watchdog reset during a
* long erase operation.
*/
watchdog_reload();
deadline.val = get_time().val + FLASH_TIMEOUT_US;
/* Wait for erase to complete */
while ((STM32_FLASH_SR & 1) &&
(get_time().val < deadline.val)) {
usleep(300);
}
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_er;
}
/*
* Check for error conditions - erase failed, voltage error,
* protection error
*/
if (STM32_FLASH_SR & 0x14) {
res = EC_ERROR_UNKNOWN;
goto exit_er;
}
}
exit_er:
/* reset PER bit */
STM32_FLASH_CR &= ~PER;
lock();
return res;
}
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 flash_physical_protect_at_boot(enum flash_wp_range range)
{
int block;
int i;
int original_val[4], val[4];
enum flash_wp_range cur_range;
for (i = 0; i < 4; ++i)
original_val[i] = val[i] = read_optb(i * 2 + 8);
for (block = RO_BANK_OFFSET;
block < RO_BANK_OFFSET + PHYSICAL_BANKS;
block++) {
int byte_off = STM32_OPTB_WRP_OFF(block/8) / 2 - 4;
if (block >= RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT)
cur_range = FLASH_WP_ALL;
else
cur_range = FLASH_WP_RO;
if (cur_range <= range)
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]);
return EC_SUCCESS;
}
/**
* 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 = flash_get_protect();
int i;
int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0;
int ro_wp_region_start = RO_BANK_OFFSET;
int ro_wp_region_end =
RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_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;
}
static void unprotect_all_blocks(void)
{
int i;
for (i = 4; i < 8; ++i)
write_optb(i * 2, 0xff);
}
/*****************************************************************************/
/* High-level APIs */
int flash_pre_init(void)
{
uint32_t prot_flags = flash_get_protect();
int need_reset = 0;
if (flash_physical_restore_state())
return EC_SUCCESS;
if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
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.
*/
flash_physical_protect_at_boot(FLASH_WP_RO);
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.
*/
flash_protect_ro_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 (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
return EC_SUCCESS;
}

View File

@@ -1,46 +1,16 @@
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
/* 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.
*/
/* Flash memory module for Chrome EC */
#include "battery.h"
#include "console.h"
#include "common.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 10
/* Flash page programming timeout. This is 2x the datasheet max. */
#define FLASH_TIMEOUT_US 16000
#define FLASH_TIMEOUT_LOOP \
(FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP)
/* Flash unlocking keys */
#define KEY1 0x45670123
#define KEY2 0xCDEF89AB
/* Lock bits for FLASH_CR register */
#define PG (1<<0)
#define PER (1<<1)
#define OPTPG (1<<4)
#define OPTER (1<<5)
#define STRT (1<<6)
#define CR_LOCK (1<<7)
#define PRG_LOCK 0
#define OPT_LOCK (1<<9)
#include "panic.h"
/* Flag indicating whether we have locked down entire flash */
static int entire_flash_locked;
@@ -57,301 +27,14 @@ struct flash_wp_state {
int entire_flash_locked;
};
static int write_optb(int byte, uint8_t value);
static int wait_busy(void)
{
int timeout = FLASH_TIMEOUT_LOOP;
while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0)
udelay(CYCLE_PER_FLASH_LOOP);
return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
}
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);
/* unlock CR if needed */
if (STM32_FLASH_CR & CR_LOCK) {
STM32_FLASH_KEYR = KEY1;
STM32_FLASH_KEYR = KEY2;
}
/* unlock option memory if required */
if ((locks & OPT_LOCK) && !(STM32_FLASH_CR & OPT_LOCK)) {
STM32_FLASH_OPTKEYR = KEY1;
STM32_FLASH_OPTKEYR = KEY2;
}
/* Re-enable bus fault handler */
ignore_bus_fault(0);
return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ?
EC_ERROR_UNKNOWN : EC_SUCCESS;
}
static void lock(void)
{
STM32_FLASH_CR = CR_LOCK;
}
/*
* 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 |= OPTER;
STM32_FLASH_CR |= STRT;
rv = wait_busy();
if (rv)
return rv;
lock();
return EC_SUCCESS;
}
/*
* 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 |= OPTPG;
*hword = value;
/* reset OPTPG bit */
STM32_FLASH_CR &= ~OPTPG;
rv = wait_busy();
if (rv)
return rv;
lock();
return EC_SUCCESS;
}
/*****************************************************************************/
/* Physical layer APIs */
int flash_physical_write(int offset, int size, const char *data)
{
uint16_t *address = (uint16_t *)(CONFIG_FLASH_BASE + offset);
int res = EC_SUCCESS;
int i;
if (unlock(PRG_LOCK) != EC_SUCCESS) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
/* Clear previous error status */
STM32_FLASH_SR = 0x34;
/* set PG bit */
STM32_FLASH_CR |= PG;
for (; size > 0; size -= sizeof(uint16_t)) {
/*
* 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 & 1) && (i < FLASH_TIMEOUT_LOOP);
i++)
;
/* write the half word */
*address++ = data[0] + (data[1] << 8);
data += 2;
/* Wait for writes to complete */
for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP);
i++)
;
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
}
/* Check for error conditions - erase failed, voltage error,
* protection error */
if (STM32_FLASH_SR & 0x14) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
}
exit_wr:
/* Disable PG bit */
STM32_FLASH_CR &= ~PG;
lock();
return res;
}
int flash_physical_erase(int offset, int size)
{
int res = EC_SUCCESS;
if (unlock(PRG_LOCK) != EC_SUCCESS)
return EC_ERROR_UNKNOWN;
/* Clear previous error status */
STM32_FLASH_SR = 0x34;
/* set PER bit */
STM32_FLASH_CR |= PER;
for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
offset += CONFIG_FLASH_ERASE_SIZE) {
timestamp_t deadline;
/* Do nothing if already erased */
if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE))
continue;
/* select page to erase */
STM32_FLASH_AR = CONFIG_FLASH_BASE + offset;
/* set STRT bit : start erase */
STM32_FLASH_CR |= STRT;
/*
* Reload the watchdog timer to avoid watchdog reset during a
* long erase operation.
*/
watchdog_reload();
deadline.val = get_time().val + FLASH_TIMEOUT_US;
/* Wait for erase to complete */
while ((STM32_FLASH_SR & 1) &&
(get_time().val < deadline.val)) {
usleep(300);
}
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_er;
}
/*
* Check for error conditions - erase failed, voltage error,
* protection error
*/
if (STM32_FLASH_SR & 0x14) {
res = EC_ERROR_UNKNOWN;
goto exit_er;
}
}
exit_er:
/* reset PER bit */
STM32_FLASH_CR &= ~PER;
lock();
return res;
}
int flash_physical_get_protect(int block)
{
return entire_flash_locked || !(STM32_FLASH_WRPR & (1 << block));
}
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;
}
uint32_t flash_physical_get_protect_flags(void)
{
uint32_t flags = 0;
@@ -363,32 +46,6 @@ uint32_t flash_physical_get_protect_flags(void)
return flags;
}
int flash_physical_protect_ro_at_boot(int enable)
{
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 = RO_BANK_OFFSET;
block < RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT;
block++) {
int byte_off = STM32_OPTB_WRP_OFF(block/8) / 2 - 4;
if (enable)
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]);
return EC_SUCCESS;
}
int flash_physical_protect_now(int all)
{
if (all) {
@@ -410,44 +67,11 @@ int flash_physical_protect_now(int all)
}
}
/**
* 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 = flash_get_protect();
int i;
int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0;
int ro_wp_region_start = RO_BANK_OFFSET;
int ro_wp_region_end =
RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_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;
}
static void unprotect_all_blocks(void)
{
int i;
for (i = 4; i < 8; ++i)
write_optb(i * 2, 0xff);
}
/*****************************************************************************/
/* High-level APIs */
int flash_pre_init(void)
int flash_physical_restore_state(void)
{
uint32_t reset_flags = system_get_reset_flags();
uint32_t prot_flags = flash_get_protect();
int need_reset = 0;
const struct flash_wp_state *prev;
int version, size;
const struct flash_wp_state *prev;
/*
* If we have already jumped between images, an earlier image could
@@ -459,50 +83,10 @@ int flash_pre_init(void)
if (prev && version == FLASH_HOOK_VERSION &&
size == sizeof(*prev))
entire_flash_locked = prev->entire_flash_locked;
return EC_SUCCESS;
return 1;
}
if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
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.
*/
flash_physical_protect_ro_at_boot(1);
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.
*/
flash_protect_ro_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 (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
return EC_SUCCESS;
return 0;
}
/*****************************************************************************/

View File

@@ -316,18 +316,21 @@ int flash_physical_get_protect(int block)
return STM32_FLASH_WRPR & (1 << block);
}
int flash_physical_protect_ro_at_boot(int enable)
int flash_physical_protect_at_boot(enum flash_wp_range range)
{
uint32_t prot;
uint32_t mask = ((1 << (RO_BANK_COUNT + PSTATE_BANK_COUNT)) - 1)
<< RO_BANK_OFFSET;
int rv;
if (range == FLASH_WP_ALL)
return EC_ERROR_UNIMPLEMENTED;
/* Read the current protection status */
prot = read_optb_wrp();
/* Set/clear bits */
if (enable)
if (range == FLASH_WP_RO)
prot |= mask;
else
prot &= ~mask;

View File

@@ -188,7 +188,7 @@ int flash_protect_ro_at_boot(int enable)
* This assumes PSTATE immediately follows RO, which it does on
* all STM32 platforms (which are the only ones with this config).
*/
flash_physical_protect_ro_at_boot(new_flags);
flash_physical_protect_at_boot(new_flags ? FLASH_WP_RO : FLASH_WP_NONE);
#endif
return EC_SUCCESS;

View File

@@ -28,6 +28,13 @@
#define PSTATE_BANK (PSTATE_OFFSET / CONFIG_FLASH_BANK_SIZE)
#define PSTATE_BANK_COUNT (PSTATE_SIZE / CONFIG_FLASH_BANK_SIZE)
/* Range of write protection */
enum flash_wp_range {
FLASH_WP_NONE = 0,
FLASH_WP_RO,
FLASH_WP_ALL,
};
/*****************************************************************************/
/* Low-level methods, for use by flash_common. */
@@ -70,12 +77,12 @@ int flash_physical_get_protect(int bank);
uint32_t flash_physical_get_protect_flags(void);
/**
* Enable/disable protecting RO firmware and pstate at boot.
* Enable/disable protecting firmware/pstate at boot.
*
* @param enable Enable (non-zero) or disable (zero) protection
* @param range The range to protect
* @return non-zero if error.
*/
int flash_physical_protect_ro_at_boot(int enable);
int flash_physical_protect_at_boot(enum flash_wp_range range);
/**
* Protect flash now.
@@ -96,6 +103,13 @@ int flash_physical_protect_now(int all);
*/
int flash_physical_force_reload(void);
/**
* Restore flash physical layer state after sysjump.
*
* @return non-zero if restored.
*/
int flash_physical_restore_state(void);
/*****************************************************************************/
/* Low-level common code for use by flash modules. */