diff options
author | Louis Yung-Chieh Lo <yjlou@chromium.org> | 2012-07-13 12:50:27 +0800 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-07-18 00:56:45 -0700 |
commit | 9c289eda9f4fc9d14ea334cf57bc94f789c890e9 (patch) | |
tree | 40c7453e755cf2c7637d17a326c09e9f26145a2e | |
parent | 73b042f3dce25f471003a459b72ba727b0d90181 (diff) | |
download | chrome-ec-9c289eda9f4fc9d14ea334cf57bc94f789c890e9.tar.gz |
Enable Lucas EC WP again.
Uncomment back the old code and fix the bug of WRP bit definition and
also write_opt().
Note that to make this functional, wp_pin_asserted() always returns true.
Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
Change-Id: Ic09d3346ca68a2700697ff863f0fa08525129b11
BUG=chrome-os-partner:9849
TEST=run on lucas.
> flashwp set 0 0x1f000
> flashwp lock
> flashinfo # ensure the setting is right.
stm32mon -r to read the firmware.
stm32mon -w to write a different image.
stm32mon -r to read again and compare the firmware is non-changed.
> flashwp unlock
Command returned error 1
stm32mon -u to unlock write protection.
Reviewed-on: https://gerrit.chromium.org/gerrit/27503
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Commit-Ready: Yung-Chieh Lo <yjlou%chromium.org@gtempaccount.com>
Tested-by: Yung-Chieh Lo <yjlou%chromium.org@gtempaccount.com>
-rw-r--r-- | chip/stm32/flash-stm32f100.c | 104 | ||||
-rw-r--r-- | common/flash_common.c | 17 |
2 files changed, 95 insertions, 26 deletions
diff --git a/chip/stm32/flash-stm32f100.c b/chip/stm32/flash-stm32f100.c index 07a0ac2416..46dc8336be 100644 --- a/chip/stm32/flash-stm32f100.c +++ b/chip/stm32/flash-stm32f100.c @@ -33,11 +33,19 @@ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB -/* Lock bits*/ +/* 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 void write_optb(int byte, uint8_t value); + + int flash_get_write_block_size(void) { return FLASH_WRITE_BYTES; @@ -72,6 +80,15 @@ int flash_physical_read(int offset, int size, char *data) } +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) { /* unlock CR if needed */ @@ -94,29 +111,90 @@ 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 void erase_optb(void) +{ + wait_busy(); + + if (unlock(OPT_LOCK) != EC_SUCCESS) + return; + + /* Must be set in 2 separate lines. */ + STM32_FLASH_CR |= OPTER; + STM32_FLASH_CR |= STRT; + + wait_busy(); + lock(); +} + +/* + * 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 void preserve_optb(int byte) +{ + int i; + uint8_t optb[8]; + + /* The byte has been reset, no need to run preserve. */ + if (*(uint8_t *)(STM32_OPTB_BASE + byte) == 0xff) + return; + + for (i = 0; i < ARRAY_SIZE(optb); ++i) + optb[i] = read_optb(i * 2); + + optb[byte / 2] = 0xff; + + erase_optb(); + for (i = 0; i < ARRAY_SIZE(optb); ++i) + write_optb(i * 2, optb[i]); } static void write_optb(int byte, uint8_t value) { volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); + wait_busy(); + + /* The target byte is the value we want to write. */ + if (*(uint8_t *)hword == value) + return; + + /* Try to erase that byte back to 0xff. */ + preserve_optb(byte); + if (unlock(OPT_LOCK) != EC_SUCCESS) return; /* set OPTPG bit */ - STM32_FLASH_CR |= (1<<4); - - /*TODO: how do we manage erasing (aka OPTER) ? */ + STM32_FLASH_CR |= OPTPG; *hword = value ; /* reset OPTPG bit */ - STM32_FLASH_CR |= (1<<4); + STM32_FLASH_CR &= ~OPTPG; + wait_busy(); lock(); } @@ -135,7 +213,7 @@ int flash_physical_write(int offset, int size, const char *data) STM32_FLASH_SR = 0x34; /* set PG bit */ - STM32_FLASH_CR |= (1<<0); + STM32_FLASH_CR |= PG; for ( ; size > 0; size -= sizeof(uint16_t)) { @@ -174,7 +252,7 @@ int flash_physical_write(int offset, int size, const char *data) exit_wr: /* Disable PG bit */ - STM32_FLASH_CR &= ~(1<<0); + STM32_FLASH_CR &= ~PG; lock(); @@ -194,7 +272,7 @@ int flash_physical_erase(int offset, int size) STM32_FLASH_SR = 0x34; /* set PER bit */ - STM32_FLASH_CR |= (1<<1); + STM32_FLASH_CR |= PER; for (address = CONFIG_FLASH_BASE + offset ; size > 0; size -= FLASH_ERASE_BYTES, @@ -205,7 +283,7 @@ int flash_physical_erase(int offset, int size) STM32_FLASH_AR = address; /* set STRT bit : start erase */ - STM32_FLASH_CR |= (1<<6); + STM32_FLASH_CR |= STRT; #ifdef CONFIG_TASK_WATCHDOG /* Reload the watchdog timer in case the erase takes long time * so that erasing many flash pages @@ -234,7 +312,7 @@ int flash_physical_erase(int offset, int size) exit_er: /* reset PER bit */ - STM32_FLASH_CR &= ~(1<<1); + STM32_FLASH_CR &= ~PER; lock(); @@ -245,17 +323,15 @@ exit_er: int flash_physical_get_protect(int block) { uint8_t val = read_optb(STM32_OPTB_WRP_OFF(block/8)); - return val & (1 << (block % 8)); + return !(val & (1 << (block % 8))); } void flash_physical_set_protect(int block) { - if (0) { /* TODO: crosbug.com/p/9849 verify WP */ int byte_off = STM32_OPTB_WRP_OFF(block/8); - uint8_t val = read_optb(byte_off) | (1 << (block % 8)); + uint8_t val = read_optb(byte_off) & ~(1 << (block % 8)); write_optb(byte_off, val); - } } int flash_physical_pre_init(void) diff --git a/common/flash_common.c b/common/flash_common.c index 184f5a79bb..e7467954f4 100644 --- a/common/flash_common.c +++ b/common/flash_common.c @@ -31,7 +31,11 @@ static int wp_pin_asserted(void) { #ifdef CHIP_stm32 /* TODO (vpalatin) : write protect scheme for stm32 */ - return 0; /* always disable write protect */ + return 1; /* Always enable write protect until we have WP pin. + * For developer to unlock WP, please use stm32mon -u and + * immediately re-program the pstate sector (so that + * apply_pstate() has no chance to run). + */ #else return gpio_get_level(GPIO_WRITE_PROTECT); #endif @@ -41,7 +45,6 @@ static int wp_pin_asserted(void) /* Read persistent state into pstate. */ static int read_pstate(void) { -#ifndef CHIP_stm32 int i; int rv = flash_physical_read(usable_flash_size, sizeof(pstate), (char *)&pstate); @@ -58,7 +61,6 @@ static int read_pstate(void) pstate.lock &= FLASH_PROTECT_LOCK_SET; for (i = 0; i < MAX_BANKS; i++) pstate.blocks[i] &= FLASH_PROTECT_PERSISTENT; -#endif /* CHIP_stm32 */ return EC_SUCCESS; } @@ -66,7 +68,6 @@ static int read_pstate(void) /* Write persistent state from pstate, erasing if necessary. */ static int write_pstate(void) { -#ifndef CHIP_stm32 int rv; /* Erase top protection block. Assumes pstate size is less than @@ -86,9 +87,6 @@ static int write_pstate(void) /* Rewrite the data */ return flash_physical_write(usable_flash_size, sizeof(pstate), (const char *)&pstate); -#else - return EC_SUCCESS; -#endif /* CHIP_stm32 */ } @@ -354,17 +352,12 @@ int flash_pre_init(void) */ flash_physical_pre_init(); -#ifdef CHIP_stm32 - usable_flash_size = flash_physical_size(); -#else /* * Calculate usable flash size. Reserve one protection block * at the top to hold the "pretend SPI" write protect data. */ usable_flash_size = flash_physical_size() - flash_get_protect_block_size(); -#endif - /* Apply write protect to blocks if needed */ return apply_pstate(); |