From 6b2a23bf8383ceed81a34a9fd5f945f90e75f990 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Sun, 20 May 2012 18:17:34 -0700 Subject: 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 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 --- board/snow/board.h | 3 + chip/stm32/flash-stm32f100.c | 259 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 chip/stm32/flash-stm32f100.c 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); +} -- cgit v1.2.1