summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2012-07-13 12:50:27 +0800
committerGerrit <chrome-bot@google.com>2012-07-18 00:56:45 -0700
commit9c289eda9f4fc9d14ea334cf57bc94f789c890e9 (patch)
tree40c7453e755cf2c7637d17a326c09e9f26145a2e
parent73b042f3dce25f471003a459b72ba727b0d90181 (diff)
downloadchrome-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.c104
-rw-r--r--common/flash_common.c17
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();