drivers/flash: Move STM32F3 to generic STM32 series driver

A common driver is shared between stm32 chips, which was not the case
for stm32f3 series. As a consequence stm32f3 was not maintained
equally and was missing features such as flash layout or dts based
configuration.
Besides, drivers had some flows such as wrong bus clock and
missing HSI clock activation which lead to issues on boards not
using HSI as main clock.
As a consequence this commit moves stm32f3 series flash driver to
common stm32 flash drivers.

Fixes #4197

Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
This commit is contained in:
Erwan Gouriou 2019-02-14 15:38:52 +01:00 committed by Kumar Gala
commit 82403f68e2
8 changed files with 162 additions and 395 deletions

View file

@ -20,8 +20,10 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32
endif()
if(CONFIG_SOC_SERIES_STM32F3X)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32 flash_stm32f3x.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32 flash_stm32f3x_priv.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32
flash_stm32.c
flash_stm32f3x.c
)
endif()
if(CONFIG_SOC_SERIES_STM32F4X)

View file

@ -14,10 +14,12 @@ menuconfig SOC_FLASH_STM32
select FLASH_HAS_DRIVER_ENABLED
default y
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F0X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F3X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F4X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F7X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32L4X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F0X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F3X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F4X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F7X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32L4X

View file

@ -17,6 +17,9 @@
/* STM32F0: maximum erase time of 40ms for a 2K sector */
#if defined(CONFIG_SOC_SERIES_STM32F0X)
#define STM32_FLASH_TIMEOUT (K_MSEC(40))
/* STM32F3: maximum erase time of 40ms for a 2K sector */
#elif defined(CONFIG_SOC_SERIES_STM32F3X)
#define STM32_FLASH_TIMEOUT (K_MSEC(40))
/* STM32F4: maximum erase time of 4s for a 128K sector */
#elif defined(CONFIG_SOC_SERIES_STM32F4X)
#define STM32_FLASH_TIMEOUT (K_MSEC(4000))
@ -95,7 +98,7 @@ int flash_stm32_wait_flash_idle(struct device *dev)
static void flash_stm32_flush_caches(struct device *dev,
off_t offset, size_t len)
{
#if defined(CONFIG_SOC_SERIES_STM32F0X)
#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32F3X)
ARG_UNUSED(dev);
ARG_UNUSED(offset);
ARG_UNUSED(len);
@ -188,6 +191,8 @@ static int flash_stm32_write_protection(struct device *dev, bool enable)
struct stm32f7x_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32F0X)
struct stm32f0x_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32F3X)
struct stm32f3x_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32L4X)
struct stm32l4x_flash *regs = FLASH_STM32_REGS(dev);
#endif
@ -205,6 +210,11 @@ static int flash_stm32_write_protection(struct device *dev, bool enable)
} else {
if (regs->cr & FLASH_CR_LOCK) {
regs->keyr = FLASH_KEY1;
#ifdef CONFIG_SOC_SERIES_STM32F3X
/* On STM32F3 series some time is requested */
/* before writing again on key register */
flash_stm32_wait_flash_idle(dev);
#endif /* CONFIG_SOC_SERIES_STM32F3X */
regs->keyr = FLASH_KEY2;
}
}
@ -219,6 +229,10 @@ static struct flash_stm32_priv flash_data = {
.regs = (struct stm32f0x_flash *) DT_FLASH_DEV_BASE_ADDRESS,
.pclken = { .bus = STM32_CLOCK_BUS_AHB1,
.enr = LL_AHB1_GRP1_PERIPH_FLASH },
#elif defined(CONFIG_SOC_SERIES_STM32F3X)
.regs = (struct stm32f3x_flash *) DT_FLASH_DEV_BASE_ADDRESS,
.pclken = { .bus = STM32_CLOCK_BUS_AHB1,
.enr = LL_AHB1_GRP1_PERIPH_FLASH },
#elif defined(CONFIG_SOC_SERIES_STM32F4X)
.regs = (struct stm32f4x_flash *) DT_FLASH_DEV_BASE_ADDRESS,
#elif defined(CONFIG_SOC_SERIES_STM32F7X)
@ -251,14 +265,15 @@ static int stm32_flash_init(struct device *dev)
{
struct flash_stm32_priv *p = FLASH_STM32_PRIV(dev);
#if defined(CONFIG_SOC_SERIES_STM32L4X) || \
defined(CONFIG_SOC_SERIES_STM32F0X)
defined(CONFIG_SOC_SERIES_STM32F0X) || \
defined(CONFIG_SOC_SERIES_STM32F3X)
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
/*
* On STM32F0, Flash interface clock source is always HSI,
* so statically enable HSI here.
*/
#if defined(CONFIG_SOC_SERIES_STM32F0X)
#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32F3X)
LL_RCC_HSI_Enable();
while (!LL_RCC_HSI_IsReady()) {

View file

@ -11,7 +11,8 @@
#include <flash_registers.h>
#if defined(CONFIG_SOC_SERIES_STM32L4X) || \
defined(CONFIG_SOC_SERIES_STM32F0X)
defined(CONFIG_SOC_SERIES_STM32F0X) || \
defined(CONFIG_SOC_SERIES_STM32F3X)
#include <clock_control.h>
#include <clock_control/stm32_clock_control.h>
#endif
@ -21,6 +22,10 @@ struct flash_stm32_priv {
struct stm32f0x_flash *regs;
/* clock subsystem driving this peripheral */
struct stm32_pclken pclken;
#elif defined(CONFIG_SOC_SERIES_STM32F3X)
struct stm32f3x_flash *regs;
/* clock subsystem driving this peripheral */
struct stm32_pclken pclken;
#elif defined(CONFIG_SOC_SERIES_STM32F4X)
struct stm32f4x_flash *regs;
#elif defined(CONFIG_SOC_SERIES_STM32F7X)

View file

@ -1,151 +1,168 @@
/*
* Copyright (c) 2016 RnDity Sp. z o.o.
* Copyright (c) 2019 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <misc/__assert.h>
#include <clock_control/stm32_clock_control.h>
#define LOG_DOMAIN flash_stm32f3
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_DOMAIN);
#include "flash_stm32f3x.h"
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <flash.h>
#include <init.h>
#include <soc.h>
static int flash_stm32_erase(struct device *dev, off_t offset, size_t size)
#include "flash_stm32.h"
/* offset and len must be aligned on 2 for write
* , positive and not beyond end of flash */
bool flash_stm32_valid_range(struct device *dev, off_t offset, u32_t len,
bool write)
{
u32_t first_page_addr = 0U;
u32_t last_page_addr = 0U;
u16_t no_of_pages = size / CONFIG_FLASH_PAGE_SIZE;
u16_t page_index = 0U;
/* Check offset and size alignment. */
if (((offset % CONFIG_FLASH_PAGE_SIZE) != 0) ||
((size % CONFIG_FLASH_PAGE_SIZE) != 0) ||
(no_of_pages == 0)) {
return -EINVAL;
}
/* Find address of the first page to be erased. */
page_index = offset / CONFIG_FLASH_PAGE_SIZE;
first_page_addr = CONFIG_FLASH_BASE_ADDRESS +
page_index * CONFIG_FLASH_PAGE_SIZE;
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(first_page_addr));
/* Find address of the last page to be erased. */
page_index = ((offset + size) / CONFIG_FLASH_PAGE_SIZE) - 1;
last_page_addr = CONFIG_FLASH_BASE_ADDRESS +
page_index * CONFIG_FLASH_PAGE_SIZE;
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(last_page_addr));
while (no_of_pages) {
if (flash_stm32_erase_page(dev, first_page_addr)
!= FLASH_COMPLETE) {
return -EINVAL;
}
no_of_pages--;
first_page_addr += CONFIG_FLASH_PAGE_SIZE;
}
return 0;
return (!write || (offset % 2 == 0 && len % 2 == 0)) &&
flash_stm32_range_exists(dev, offset, len);
}
static int flash_stm32_read(struct device *dev, off_t offset,
void *data, size_t len)
static unsigned int get_page(off_t offset)
{
u32_t address = CONFIG_FLASH_BASE_ADDRESS + offset;
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
flash_stm32_read_data(data, address, len);
return 0;
return offset / FLASH_PAGE_SIZE;
}
static int flash_stm32_write(struct device *dev, off_t offset,
const void *data, size_t len)
static int erase_page(struct device *dev, unsigned int page)
{
u16_t halfword = 0U;
struct stm32f3x_flash *regs = FLASH_STM32_REGS(dev);
u32_t page_address = CONFIG_FLASH_BASE_ADDRESS;
int rc;
u32_t address =
CONFIG_FLASH_BASE_ADDRESS + offset;
u8_t remainder = 0U;
if ((len % 2) != 0) {
remainder = 1U;
/* if the control register is locked, do not fail silently */
if (regs->cr & FLASH_CR_LOCK) {
return -EIO;
}
len = len / 2;
while (len--) {
halfword = *((u8_t *)data++);
halfword |= *((u8_t *)data++) << 8;
if (flash_stm32_program_halfword(dev, address, halfword)
!= FLASH_COMPLETE) {
return -EINVAL;
}
address += 2;
/* Check that no Flash memory operation is ongoing */
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
if (remainder) {
halfword = (*((u16_t *)data)) & 0x00FF;
if (flash_stm32_program_halfword(dev, address, halfword)
!= FLASH_COMPLETE) {
return -EINVAL;
page_address += page * FLASH_PAGE_SIZE;
/* Set the PER bit and select the page you wish to erase */
regs->cr |= FLASH_CR_PER;
/* Set page address */
regs->ar = page_address;
/* Give some time to write operation to complete */
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
/* Set the STRT bit */
regs->cr |= FLASH_CR_STRT;
/* Wait for the BSY bit */
rc = flash_stm32_wait_flash_idle(dev);
regs->cr &= ~FLASH_CR_PER;
return rc;
}
int flash_stm32_block_erase_loop(struct device *dev, unsigned int offset,
unsigned int len)
{
int i, rc = 0;
i = get_page(offset);
for (; i <= get_page(offset + len - 1) ; ++i) {
rc = erase_page(dev, i);
if (rc < 0) {
break;
}
}
return 0;
return rc;
}
static int flash_stm32_protection_set(struct device *dev, bool enable)
static int write_hword(struct device *dev, off_t offset, u16_t val)
{
if (enable) {
flash_stm32_lock(dev);
} else {
flash_stm32_unlock(dev);
volatile u16_t *flash = (u16_t *)(offset + CONFIG_FLASH_BASE_ADDRESS);
struct stm32f3x_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;
}
return 0;
/* Check that no Flash main memory operation is ongoing */
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
/* Check if this half word is erased */
if (*flash != 0xFFFF) {
return -EIO;
}
/* Set the PG bit */
regs->cr |= FLASH_CR_PG;
/* Flush the register write */
tmp = regs->cr;
/* Perform the data write operation at the desired memory address */
*flash = val;
/* Wait until the BSY bit is cleared */
rc = flash_stm32_wait_flash_idle(dev);
/* Clear the PG bit */
regs->cr &= (~FLASH_CR_PG);
return rc;
}
static int flash_stm32_init(struct device *dev)
int flash_stm32_write_range(struct device *dev, unsigned int offset,
const void *data, unsigned int len)
{
const struct flash_stm32_dev_config *cfg = FLASH_CFG(dev);
int i, rc = 0;
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
for (i = 0; i < len; i += 2, offset += 2) {
rc = write_hword(dev, offset, ((const u16_t *) data)[i>>1]);
if (rc < 0) {
return rc;
}
}
if (clock_control_on(clk, (clock_control_subsys_t *) &cfg->pclken) != 0)
return -ENODEV;
return 0;
return rc;
}
static const struct flash_driver_api flash_stm32_api = {
.read = flash_stm32_read,
.write = flash_stm32_write,
.erase = flash_stm32_erase,
.write_protection = flash_stm32_protection_set,
.write_block_size = 2,
};
void flash_stm32_page_layout(struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
static struct flash_pages_layout stm32f3_flash_layout = {
.pages_count = 0,
.pages_size = 0,
};
static const struct flash_stm32_dev_config flash_device_config = {
.base = (u32_t *)DT_FLASH_DEV_BASE_ADDRESS,
.pclken = { .bus = STM32_CLOCK_BUS_APB1,
.enr = LL_AHB1_GRP1_PERIPH_FLASH},
};
ARG_UNUSED(dev);
static struct flash_stm32_dev_data flash_device_data = {
if (stm32f3_flash_layout.pages_count == 0) {
stm32f3_flash_layout.pages_count = DT_FLASH_SIZE \
* 1024 / FLASH_PAGE_SIZE;
stm32f3_flash_layout.pages_size = FLASH_PAGE_SIZE;
}
};
DEVICE_AND_API_INIT(flash_stm32, DT_FLASH_DEV_NAME,
flash_stm32_init,
&flash_device_data,
&flash_device_config,
POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&flash_stm32_api);
*layout = &stm32f3_flash_layout;
*layout_size = 1;
}

View file

@ -1,66 +0,0 @@
/*
* Copyright (c) 2016 RnDity Sp. z o.o.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_FLASH_FLASH_STM32F3X_H_
#define ZEPHYR_DRIVERS_FLASH_FLASH_STM32F3X_H_
#include <soc.h>
#include <flash.h>
#include <clock_control.h>
#include <flash_registers.h>
struct flash_stm32_dev_config {
u32_t *base;
struct stm32_pclken pclken;
};
struct flash_stm32_dev_data {
/* For future use. */
};
#define FLASH_CFG(dev) \
((const struct flash_stm32_dev_config * const)(dev)->config->config_info)
#define FLASH_DATA(dev) \
((struct flash_stm32_dev_data * const)(dev)->driver_data)
#define FLASH_STRUCT(base) \
(volatile struct stm32_flash *)(base)
/* Flash programming timeout definition. */
#define FLASH_ER_PRG_TIMEOUT ((u32_t)0x000B0000)
enum flash_status {
FLASH_BUSY = 1,
FLASH_ERROR_WRITE_PROTECTION,
FLASH_ERROR_PROGRAM,
FLASH_COMPLETE,
FLASH_TIMEOUT
};
void flash_stm32_lock(struct device *flash);
void flash_stm32_unlock(struct device *flash);
u8_t flash_stm32_program_halfword(struct device *flash,
u32_t address,
u16_t data);
u8_t flash_stm32_program_word(struct device *flash,
u32_t address,
u32_t data);
void flash_stm32_read_data(void *data, u32_t address, size_t len);
u8_t flash_stm32_wait_for_last_operation(struct device *flash,
u32_t timeout);
u8_t flash_stm32_get_status(struct device *flash);
u8_t flash_stm32_erase_page(struct device *flash,
u32_t page_address);
u8_t flash_stm32_erase_all_pages(struct device *flash);
#endif /* ZEPHYR_DRIVERS_FLASH_FLASH_STM32F3X_H_ */

View file

@ -1,208 +0,0 @@
/*
* Copyright (c) 2016 RnDity Sp. z o.o.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <clock_control/stm32_clock_control.h>
#include <misc/__assert.h>
#include <string.h>
#include "flash_stm32f3x.h"
void flash_stm32_unlock(struct device *flash)
{
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
if ((reg->cr & FLASH_CR_LOCK) != 0) {
/* Authorize the FLASH Registers access */
reg->keyr = FLASH_KEY1;
reg->keyr = FLASH_KEY2;
}
}
void flash_stm32_lock(struct device *flash)
{
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
reg->cr |= FLASH_CR_LOCK;
}
u8_t flash_stm32_program_halfword(struct device *flash,
u32_t address,
u16_t data)
{
u8_t status = FLASH_COMPLETE;
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
if (status == FLASH_COMPLETE) {
reg->cr |= FLASH_CR_PG;
*(volatile u16_t *)address = data;
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
reg->cr &= ~FLASH_CR_PG;
}
return status;
}
u8_t flash_stm32_program_word(struct device *flash,
u32_t address,
u32_t data)
{
u8_t status = FLASH_COMPLETE;
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
if (status == FLASH_COMPLETE) {
reg->cr |= FLASH_CR_PG;
*(volatile u16_t *)address = (u16_t)data;
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
if (status == FLASH_COMPLETE) {
address += 2;
*(volatile u16_t *)address = data >> 16;
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
}
reg->cr &= ~FLASH_CR_PG;
}
return status;
}
u8_t flash_stm32_wait_for_last_operation(struct device *flash,
u32_t timeout)
{
u8_t status = FLASH_COMPLETE;
/* Check for the FLASH Status */
status = flash_stm32_get_status(flash);
/* Wait for a FLASH operation to complete or a TIMEOUT to occur. */
while ((status == FLASH_BUSY) && (timeout != 0x00)) {
status = flash_stm32_get_status(flash);
timeout--;
}
if (timeout == 0x00) {
status = FLASH_TIMEOUT;
}
return status;
}
u8_t flash_stm32_get_status(struct device *flash)
{
u8_t status = FLASH_COMPLETE;
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
do {
if ((reg->sr & FLASH_SR_BSY) == FLASH_SR_BSY) {
status = FLASH_BUSY;
break;
}
if ((reg->sr & FLASH_SR_WRPERR) != (u32_t)0x00) {
status = FLASH_ERROR_WRITE_PROTECTION;
break;
}
if ((reg->sr & FLASH_SR_PGERR) != (u32_t)0x00) {
status = FLASH_ERROR_PROGRAM;
break;
}
} while (0);
return status;
}
u8_t flash_stm32_erase_page(struct device *flash,
u32_t page_address)
{
u8_t status = FLASH_COMPLETE;
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(page_address));
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
if (status == FLASH_COMPLETE) {
reg->cr |= FLASH_CR_PER;
reg->ar = page_address;
reg->cr |= FLASH_CR_STRT;
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
reg->cr &= ~FLASH_CR_PER;
}
return status;
}
u8_t flash_stm32_erase_all_pages(struct device *flash)
{
u8_t status = FLASH_COMPLETE;
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
if (status == FLASH_COMPLETE) {
reg->cr |= FLASH_CR_MER;
reg->cr |= FLASH_CR_STRT;
status = flash_stm32_wait_for_last_operation(flash,
FLASH_ER_PRG_TIMEOUT);
reg->cr &= ~FLASH_CR_MER;
}
return status;
}
void flash_stm32_read_data(void *data, u32_t address, size_t len)
{
u8_t *addr = INT_TO_POINTER(address);
memcpy(data, addr, len);
}

View file

@ -40,7 +40,7 @@ union ef_acr {
};
/* 3.3.3 Embedded flash registers */
struct stm32_flash {
struct stm32f3x_flash {
union ef_acr acr;
u32_t keyr;
u32_t optkeyr;