mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 16:41:55 +00:00
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
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
259
chip/stm32/flash-stm32f100.c
Normal file
259
chip/stm32/flash-stm32f100.c
Normal file
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user