summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-05-20 18:17:34 -0700
committerVincent Palatin <vpalatin@chromium.org>2012-05-21 18:48:27 +0000
commit6b2a23bf8383ceed81a34a9fd5f945f90e75f990 (patch)
tree0cfbfbb404bfc012c4e5d43cf4eadb885db8436b
parentb5ce7f5a203937c652dd543bcd4d9d76944ecd6b (diff)
downloadchrome-ec-6b2a23bf8383ceed81a34a9fd5f945f90e75f990.tar.gz
stm32: add flash driver for stm32f100 SoC
Implementation of the flash driver for the stm32f100 chip used on Snow board. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BUG=chrome-os-partner:8865 TEST=On Snow board, use "flashwrite/flasherase" commands from EC console and verify result with "rw" command. Change-Id: Ie8b8be3d549ff9ec8c3036d5f4a97480daa5e03e
-rw-r--r--board/snow/board.h3
-rw-r--r--chip/stm32/flash-stm32f100.c259
2 files changed, 262 insertions, 0 deletions
diff --git a/board/snow/board.h b/board/snow/board.h
index 67156dc0ec..9f788411d9 100644
--- a/board/snow/board.h
+++ b/board/snow/board.h
@@ -14,6 +14,9 @@
/* Use USART1 as console serial port */
#define CONFIG_CONSOLE_UART 1
+/* support programming on-chip flash */
+#define CONFIG_FLASH
+
/* use I2C for host communication */
#define CONFIG_I2C
diff --git a/chip/stm32/flash-stm32f100.c b/chip/stm32/flash-stm32f100.c
new file mode 100644
index 0000000000..e9f888a581
--- /dev/null
+++ b/chip/stm32/flash-stm32f100.c
@@ -0,0 +1,259 @@
+/* Copyright (c) 2012 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 "console.h"
+#include "flash.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "watchdog.h"
+
+#define FLASH_WRITE_BYTES 2
+#define FLASH_ERASE_BYTES 1024
+#define FLASH_PROTECT_BYTES 4096
+
+#define US_PER_SECOND 1000000
+
+/* the 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 / US_PER_SECOND) / CYCLE_PER_FLASH_LOOP)
+
+/* Flash unlocking keys */
+#define KEY1 0x45670123
+#define KEY2 0xCDEF89AB
+
+/* Lock bits*/
+#define CR_LOCK (1<<7)
+#define PRG_LOCK 0
+#define OPT_LOCK (1<<9)
+
+int flash_get_write_block_size(void)
+{
+ return FLASH_WRITE_BYTES;
+}
+
+
+int flash_get_erase_block_size(void)
+{
+ return FLASH_ERASE_BYTES;
+}
+
+
+int flash_get_protect_block_size(void)
+{
+ BUILD_ASSERT(FLASH_PROTECT_BYTES == CONFIG_FLASH_BANK_SIZE);
+ return FLASH_PROTECT_BYTES;
+}
+
+
+int flash_physical_size(void)
+{
+ return CONFIG_FLASH_SIZE;
+}
+
+
+int flash_physical_read(int offset, int size, char *data)
+{
+ /* Just read the flash from its memory window. */
+ /* TODO: (crosbug.com/p/7473) is this affected by data cache? */
+ memcpy(data, (char *)offset, size);
+ return EC_SUCCESS;
+}
+
+static int unlock(int locks)
+{
+ /* 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;
+ }
+
+ return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ?
+ EC_ERROR_UNKNOWN : EC_SUCCESS;
+}
+
+static void lock(void)
+{
+ STM32_FLASH_CR = CR_LOCK;
+}
+
+static uint8_t read_optb(int byte)
+{
+ return *(uint8_t *)(STM32_OPTB_BASE + byte);
+
+}
+
+static void write_optb(int byte, uint8_t value)
+{
+ volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte);
+
+ if (unlock(OPT_LOCK) != EC_SUCCESS)
+ return;
+
+ /* set OPTPG bit */
+ STM32_FLASH_CR |= (1<<4);
+
+ /*TODO: how do we manage erasing (aka OPTER) ? */
+
+ *hword = value ;
+
+ /* reset OPTPG bit */
+ STM32_FLASH_CR |= (1<<4);
+
+ lock();
+}
+
+int flash_physical_write(int offset, int size, const char *data)
+{
+ /* this is pretty nasty, we need to enforce alignment instead of this
+ * wild cast : TODO crosbug.com/p/9526
+ */
+ uint16_t *data16 = (uint16_t *)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 |= (1<<0);
+
+
+ for ( ; size > 0; size -= FLASH_WRITE_BYTES) {
+#ifdef CONFIG_TASK_WATCHDOG
+ /* Reload the watchdog timer to avoid watchdog reset when doing
+ * long writing with interrupt disabled.
+ */
+ watchdog_reload();
+#endif
+ /* wait to be ready */
+ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP) ;
+ i++)
+ ;
+
+ /* write the half word */
+ *address++ = *data16++;
+
+ /* 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 &= ~(1<<0);
+
+ lock();
+
+ return res;
+}
+
+
+int flash_physical_erase(int offset, int size)
+{
+ uint32_t address;
+ 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 |= (1<<1);
+
+ for (address = CONFIG_FLASH_BASE + offset ;
+ size > 0; size -= FLASH_ERASE_BYTES,
+ address += FLASH_ERASE_BYTES) {
+ timestamp_t deadline;
+
+ /* select page to erase */
+ STM32_FLASH_AR = address;
+
+ /* set STRT bit : start erase */
+ STM32_FLASH_CR |= (1<<6);
+#ifdef CONFIG_TASK_WATCHDOG
+ /* Reload the watchdog timer in case the erase takes long time
+ * so that erasing many flash pages
+ */
+ watchdog_reload();
+#endif
+
+ 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 &= ~(1<<1);
+
+ lock();
+
+ return res;
+}
+
+
+int flash_physical_get_protect(int block)
+{
+ uint8_t val = read_optb(STM32_OPTB_WRP_OFF(block/8));
+ return val & (1 << (block % 8));
+}
+
+
+void flash_physical_set_protect(int block)
+{
+ int byte_off = STM32_OPTB_WRP_OFF(block/8);
+ uint8_t val = read_optb(byte_off) | (1 << (block % 8));
+ write_optb(byte_off, val);
+}