zephyr/drivers/flash/flash_stm32f4x.c
Erwan Gouriou 0e4dc5f33a drivers/flash: stm32f4: Return error on Dual Bank configuration
Some stm32f4 1MB SoCs support optional Dual Bank configuration.
This is not yet supported by stm32f4 driver, so report an
error when configuration is detected

Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
2019-11-05 16:37:25 -06:00

235 lines
5.9 KiB
C

/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <drivers/flash.h>
#include <init.h>
#include <soc.h>
#include "flash_stm32.h"
#define STM32F4X_SECTOR_MASK ((u32_t) 0xFFFFFF07)
bool flash_stm32_valid_range(struct device *dev, off_t offset, u32_t len,
bool write)
{
ARG_UNUSED(write);
#if (FLASH_SECTOR_TOTAL == 12) && defined(FLASH_OPTCR_DB1M)
struct stm32f4x_flash *regs = FLASH_STM32_REGS(dev);
/*
* RM0090, table 7.1: STM32F42xxx, STM32F43xxx
*/
if (regs->optcr & FLASH_OPTCR_DB1M) {
/* Device configured in Dual Bank, but not supported for now */
return false;
}
#endif
return flash_stm32_range_exists(dev, offset, len);
}
static int write_byte(struct device *dev, off_t offset, u8_t val)
{
struct stm32f4x_flash *regs = FLASH_STM32_REGS(dev);
u32_t tmp;
int rc;
/* if the control register is locked, do not fail silently */
if (regs->cr & FLASH_CR_LOCK) {
return -EIO;
}
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
regs->cr &= ~CR_PSIZE_MASK;
regs->cr |= FLASH_PSIZE_BYTE;
regs->cr |= FLASH_CR_PG;
/* flush the register write */
tmp = regs->cr;
*((u8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val;
rc = flash_stm32_wait_flash_idle(dev);
regs->cr &= (~FLASH_CR_PG);
return rc;
}
static int erase_sector(struct device *dev, u32_t sector)
{
struct stm32f4x_flash *regs = FLASH_STM32_REGS(dev);
u32_t tmp;
int rc;
/* if the control register is locked, do not fail silently */
if (regs->cr & FLASH_CR_LOCK) {
return -EIO;
}
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
#if FLASH_SECTOR_TOTAL == 24
/*
* RM0090, §3.9.8: STM32F42xxx, STM32F43xxx
* RM0386, §3.7.5: STM32F469xx, STM32F479xx
*/
if (sector >= 12) {
/* From sector 12, SNB is offset by 0b10000 */
sector += 4U;
}
#endif
regs->cr &= STM32F4X_SECTOR_MASK;
regs->cr |= FLASH_CR_SER | (sector << 3);
regs->cr |= FLASH_CR_STRT;
/* flush the register write */
tmp = regs->cr;
rc = flash_stm32_wait_flash_idle(dev);
regs->cr &= ~(FLASH_CR_SER | FLASH_CR_SNB);
return rc;
}
int flash_stm32_block_erase_loop(struct device *dev, unsigned int offset,
unsigned int len)
{
struct flash_pages_info info;
u32_t start_sector, end_sector;
u32_t i;
int rc = 0;
rc = flash_get_page_info_by_offs(dev, offset, &info);
if (rc) {
return rc;
}
start_sector = info.index;
rc = flash_get_page_info_by_offs(dev, offset + len - 1, &info);
if (rc) {
return rc;
}
end_sector = info.index;
for (i = start_sector; i <= end_sector; i++) {
rc = erase_sector(dev, i);
if (rc < 0) {
break;
}
}
return rc;
}
int flash_stm32_write_range(struct device *dev, unsigned int offset,
const void *data, unsigned int len)
{
int i, rc = 0;
for (i = 0; i < len; i++, offset++) {
rc = write_byte(dev, offset, ((const u8_t *) data)[i]);
if (rc < 0) {
return rc;
}
}
return rc;
}
/*
* Different SoC flash layouts are specified in across various
* reference manuals, but the flash layout for a given number of
* sectors is consistent across these manuals, with one "gotcha". The
* number of sectors is given by the HAL as FLASH_SECTOR_TOTAL.
*
* The only "gotcha" is that when there are 24 sectors, they are split
* across 2 "banks" of 12 sectors each, with another set of small
* sectors (16 KB) in the second bank occurring after the large ones
* (128 KB) in the first. We could consider supporting this as two
* devices to make the layout cleaner, but this will do for now.
*/
#ifndef FLASH_SECTOR_TOTAL
#error "Unknown flash layout"
#else /* defined(FLASH_SECTOR_TOTAL) */
#if FLASH_SECTOR_TOTAL == 5
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/* RM0401, table 5: STM32F410Tx, STM32F410Cx, STM32F410Rx */
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
};
#elif FLASH_SECTOR_TOTAL == 6
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/* RM0368, table 5: STM32F401xC */
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 1, .pages_size = KB(128)},
};
#elif FLASH_SECTOR_TOTAL == 8
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/*
* RM0368, table 5: STM32F401xE
* RM0383, table 4: STM32F411xE
* RM0390, table 4: STM32F446xx
*/
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 3, .pages_size = KB(128)},
};
#elif FLASH_SECTOR_TOTAL == 12
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/*
* RM0090, table 5: STM32F405xx, STM32F415xx, STM32F407xx, STM32F417xx
* RM0402, table 5: STM32F412Zx, STM32F412Vx, STM32F412Rx, STM32F412Cx
*/
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 7, .pages_size = KB(128)},
};
#elif FLASH_SECTOR_TOTAL == 16
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/* RM0430, table 5.: STM32F413xx, STM32F423xx */
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 11, .pages_size = KB(128)},
};
#elif FLASH_SECTOR_TOTAL == 24
static const struct flash_pages_layout stm32f4_flash_layout[] = {
/*
* RM0090, table 6: STM32F427xx, STM32F437xx, STM32F429xx, STM32F439xx
* RM0386, table 4: STM32F469xx, STM32F479xx
*/
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 7, .pages_size = KB(128)},
{.pages_count = 4, .pages_size = KB(16)},
{.pages_count = 1, .pages_size = KB(64)},
{.pages_count = 7, .pages_size = KB(128)},
};
#else
#error "Unknown flash layout"
#endif /* FLASH_SECTOR_TOTAL == 5 */
#endif/* !defined(FLASH_SECTOR_TOTAL) */
void flash_stm32_page_layout(struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
ARG_UNUSED(dev);
*layout = stm32f4_flash_layout;
*layout_size = ARRAY_SIZE(stm32f4_flash_layout);
}