drivers: flash: Add STM32G4X flash support

Add flash driver support for STM32G4X SoC series.

Signed-off-by: Richard Osterloh <richard.osterloh@gmail.com>
This commit is contained in:
Richard Osterloh 2019-09-04 09:43:59 +01:00 committed by Andrew Boie
commit c68e027c28
9 changed files with 290 additions and 4 deletions

View file

@ -26,6 +26,7 @@ if(CONFIG_CLOCK_CONTROL_STM32_CUBE)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32L4X flash_stm32l4x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32L4X flash_stm32l4x.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32WBX flash_stm32wbx.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32WBX flash_stm32wbx.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32G0X flash_stm32g0x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32G0X flash_stm32g0x.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32G4X flash_stm32g4x.c)
endif() endif()
zephyr_include_directories_ifdef( zephyr_include_directories_ifdef(

View file

@ -10,7 +10,7 @@ if SOC_FAMILY_STM32
menuconfig SOC_FLASH_STM32 menuconfig SOC_FLASH_STM32
bool "STM32 flash driver" bool "STM32 flash driver"
depends on (SOC_SERIES_STM32F0X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32L4X || SOC_SERIES_STM32WBX || SOC_SERIES_STM32G0X) depends on (SOC_SERIES_STM32F0X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32L4X || SOC_SERIES_STM32WBX || SOC_SERIES_STM32G0X || SOC_SERIES_STM32G4X)
select FLASH_HAS_DRIVER_ENABLED select FLASH_HAS_DRIVER_ENABLED
default y default y
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F0X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F0X
@ -20,6 +20,7 @@ menuconfig SOC_FLASH_STM32
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F7X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F7X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32L4X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32L4X
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32WBX select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32WBX
select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32G4X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F0X 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_STM32F3X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32G0X select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32G0X
@ -27,7 +28,8 @@ menuconfig SOC_FLASH_STM32
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F7X select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F7X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32L4X select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32L4X
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32WBX select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32WBX
select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32G4X
help help
Enable STM32F0x, STM32F3x, STM32F4x, STM32F7x, STM32L4x, STM32WBx or STM32G0x series flash driver. Enable STM32F0x, STM32F3x, STM32F4x, STM32F7x, STM32L4x, STM32WBx, STM32G0x or STM32G4x series flash driver.
endif endif

View file

@ -36,6 +36,9 @@
#elif defined(CONFIG_SOC_SERIES_STM32G0X) #elif defined(CONFIG_SOC_SERIES_STM32G0X)
/* STM32G0: maximum erase time of 40ms for a 2K sector */ /* STM32G0: maximum erase time of 40ms for a 2K sector */
#define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(40)) #define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(40))
/* STM32G4: maximum erase time of 24.47ms for a 2K sector */
#elif defined(CONFIG_SOC_SERIES_STM32G4X)
#define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(25))
#endif #endif
/* Let's wait for double the max erase time to be sure that the operation is /* Let's wait for double the max erase time to be sure that the operation is
@ -133,7 +136,8 @@ static void flash_stm32_flush_caches(struct device *dev,
ARG_UNUSED(len); ARG_UNUSED(len);
#elif defined(CONFIG_SOC_SERIES_STM32F4X) || \ #elif defined(CONFIG_SOC_SERIES_STM32F4X) || \
defined(CONFIG_SOC_SERIES_STM32L4X) || \ defined(CONFIG_SOC_SERIES_STM32L4X) || \
defined(CONFIG_SOC_SERIES_STM32WBX) defined(CONFIG_SOC_SERIES_STM32WBX) || \
defined(CONFIG_SOC_SERIES_STM32G4X)
ARG_UNUSED(offset); ARG_UNUSED(offset);
ARG_UNUSED(len); ARG_UNUSED(len);
#if defined(CONFIG_SOC_SERIES_STM32F4X) #if defined(CONFIG_SOC_SERIES_STM32F4X)
@ -142,6 +146,8 @@ static void flash_stm32_flush_caches(struct device *dev,
struct stm32l4x_flash *regs = FLASH_STM32_REGS(dev); struct stm32l4x_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32WBX) #elif defined(CONFIG_SOC_SERIES_STM32WBX)
struct stm32wbx_flash *regs = FLASH_STM32_REGS(dev); struct stm32wbx_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32G4X)
struct stm32g4x_flash *regs = FLASH_STM32_REGS(dev);
#endif #endif
if (regs->acr.val & FLASH_ACR_DCEN) { if (regs->acr.val & FLASH_ACR_DCEN) {
regs->acr.val &= ~FLASH_ACR_DCEN; regs->acr.val &= ~FLASH_ACR_DCEN;
@ -232,6 +238,8 @@ static int flash_stm32_write_protection(struct device *dev, bool enable)
struct stm32wbx_flash *regs = FLASH_STM32_REGS(dev); struct stm32wbx_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32G0X) #elif defined(CONFIG_SOC_SERIES_STM32G0X)
struct stm32g0x_flash *regs = FLASH_STM32_REGS(dev); struct stm32g0x_flash *regs = FLASH_STM32_REGS(dev);
#elif defined(CONFIG_SOC_SERIES_STM32G4X)
struct stm32g4x_flash *regs = FLASH_STM32_REGS(dev);
#endif #endif
int rc = 0; int rc = 0;
@ -279,6 +287,10 @@ static struct flash_stm32_priv flash_data = {
.regs = (struct stm32g0x_flash *) DT_FLASH_DEV_BASE_ADDRESS, .regs = (struct stm32g0x_flash *) DT_FLASH_DEV_BASE_ADDRESS,
.pclken = { .bus = STM32_CLOCK_BUS_AHB1, .pclken = { .bus = STM32_CLOCK_BUS_AHB1,
.enr = LL_AHB1_GRP1_PERIPH_FLASH }, .enr = LL_AHB1_GRP1_PERIPH_FLASH },
#elif defined(CONFIG_SOC_SERIES_STM32G4X)
.regs = (struct stm32g4x_flash *) DT_FLASH_DEV_BASE_ADDRESS,
.pclken = { .bus = STM32_CLOCK_BUS_AHB1,
.enr = LL_AHB1_GRP1_PERIPH_FLASH },
#endif #endif
}; };

View file

@ -13,7 +13,8 @@
#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ #if defined(CONFIG_SOC_SERIES_STM32L4X) || \
defined(CONFIG_SOC_SERIES_STM32F0X) || \ defined(CONFIG_SOC_SERIES_STM32F0X) || \
defined(CONFIG_SOC_SERIES_STM32F3X) || \ defined(CONFIG_SOC_SERIES_STM32F3X) || \
defined(CONFIG_SOC_SERIES_STM32G0X) defined(CONFIG_SOC_SERIES_STM32G0X) || \
defined(CONFIG_SOC_SERIES_STM32G4X)
#include <drivers/clock_control.h> #include <drivers/clock_control.h>
#include <clock_control/stm32_clock_control.h> #include <clock_control/stm32_clock_control.h>
#endif #endif
@ -41,6 +42,10 @@ struct flash_stm32_priv {
struct stm32g0x_flash *regs; struct stm32g0x_flash *regs;
/* clock subsystem driving this peripheral */ /* clock subsystem driving this peripheral */
struct stm32_pclken pclken; struct stm32_pclken pclken;
#elif defined(CONFIG_SOC_SERIES_STM32G4X)
struct stm32g4x_flash *regs;
/* clock subsystem driving this peripheral */
struct stm32_pclken pclken;
#endif #endif
struct k_sem sem; struct k_sem sem;
}; };

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2019 Richard Osterloh <richard.osterloh@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_DOMAIN flash_stm32g4
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_DOMAIN);
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <drivers/flash.h>
#include <init.h>
#include <soc.h>
#include "flash_stm32.h"
#define STM32G4X_PAGE_SHIFT 11
/*
* offset and len must be aligned on 8 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)
{
return (!write || (offset % 8 == 0 && len % 8 == 0U)) &&
flash_stm32_range_exists(dev, offset, len);
}
/*
* STM32G4xx devices can have up to 64 2K pages in a single banks
*/
static unsigned int get_page(off_t offset)
{
return offset >> STM32G4X_PAGE_SHIFT;
}
static int write_dword(struct device *dev, off_t offset, u64_t val)
{
volatile u32_t *flash = (u32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS);
struct stm32g4x_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;
}
/* Check that no Flash main memory operation is ongoing */
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
/* Check if this double word is erased */
if (flash[0] != 0xFFFFFFFFUL ||
flash[1] != 0xFFFFFFFFUL) {
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[0] = (u32_t)val;
flash[1] = (u32_t)(val >> 32);
/* 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 erase_page(struct device *dev, unsigned int page)
{
struct stm32g4x_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;
}
/* Check that no Flash memory operation is ongoing */
rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}
/* Set the PER bit and select the page you wish to erase */
regs->cr |= FLASH_CR_PER;
regs->cr &= ~FLASH_CR_PNB_Msk;
regs->cr |= ((page % 256) << 3);
/* Set the STRT bit */
regs->cr |= FLASH_CR_STRT;
/* flush the register write */
tmp = regs->cr;
/* 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 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 += 8, offset += 8) {
rc = write_dword(dev, offset, ((const u64_t *) data)[i>>3]);
if (rc < 0) {
return rc;
}
}
return rc;
}
void flash_stm32_page_layout(struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
static struct flash_pages_layout stm32g4_flash_layout = {
.pages_count = 0,
.pages_size = 0,
};
ARG_UNUSED(dev);
if (stm32g4_flash_layout.pages_count == 0) {
stm32g4_flash_layout.pages_count = FLASH_SIZE / FLASH_PAGE_SIZE;
stm32g4_flash_layout.pages_size = FLASH_PAGE_SIZE;
}
*layout = &stm32g4_flash_layout;
*layout_size = 1;
}

View file

@ -26,6 +26,24 @@
}; };
soc { soc {
flash-controller@40022000 {
compatible = "st,stm32g4-flash-controller";
label = "FLASH_CTRL";
reg = <0x40022000 0x400>;
interrupts = <3 0>;
#address-cells = <1>;
#size-cells = <1>;
flash0: flash@8000000 {
compatible = "soc-nv-flash";
label = "FLASH_STM32";
write-block-size = <8>;
erase-block-size = <2048>;
};
};
rcc: rcc@40021000 { rcc: rcc@40021000 {
compatible = "st,stm32-rcc"; compatible = "st,stm32-rcc";
#clock-cells = <2>; #clock-cells = <2>;

View file

@ -0,0 +1,8 @@
title: STM32 G4 Flash Controller
description: >
This binding gives a base representation of the STM32 G4 Flash Controller
compatible: "st,stm32g4-flash-controller"
include: flash-controller.yaml

View file

@ -116,4 +116,7 @@
#define DT_UART_STM32_LPUART_1_CLOCK_BUS DT_ST_STM32_LPUART_40008000_CLOCK_BUS #define DT_UART_STM32_LPUART_1_CLOCK_BUS DT_ST_STM32_LPUART_40008000_CLOCK_BUS
#define DT_UART_STM32_LPUART_1_HW_FLOW_CONTROL DT_ST_STM32_LPUART_40008000_HW_FLOW_CONTROL #define DT_UART_STM32_LPUART_1_HW_FLOW_CONTROL DT_ST_STM32_LPUART_40008000_HW_FLOW_CONTROL
#define DT_FLASH_DEV_BASE_ADDRESS DT_ST_STM32G4_FLASH_CONTROLLER_40022000_BASE_ADDRESS
#define DT_FLASH_DEV_NAME DT_ST_STM32G4_FLASH_CONTROLLER_40022000_LABEL
/* End of SoC Level DTS fixup file */ /* End of SoC Level DTS fixup file */

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2019 Richard Osterloh <richard.osterloh@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STM32G4X_FLASH_REGISTERS_H_
#define _STM32G4X_FLASH_REGISTERS_H_
enum {
STM32G4X_FLASH_LATENCY_0 = 0x0,
STM32G4X_FLASH_LATENCY_1 = 0x1,
STM32G4X_FLASH_LATENCY_2 = 0x2,
STM32G4X_FLASH_LATENCY_3 = 0x3,
STM32G4X_FLASH_LATENCY_4 = 0x4,
STM32G4X_FLASH_LATENCY_5 = 0x5,
STM32G4X_FLASH_LATENCY_6 = 0x6,
STM32G4X_FLASH_LATENCY_7 = 0x7,
STM32G4X_FLASH_LATENCY_8 = 0x8,
STM32G4X_FLASH_LATENCY_9 = 0x9,
STM32G4X_FLASH_LATENCY_10 = 0x10,
STM32G4X_FLASH_LATENCY_11 = 0x11,
STM32G4X_FLASH_LATENCY_12 = 0x12,
STM32G4X_FLASH_LATENCY_13 = 0x13,
STM32G4X_FLASH_LATENCY_14 = 0x14,
};
/* 3.7.1 FLASH_ACR */
union __ef_acr {
u32_t val;
struct {
u32_t latency :4 __packed;
u32_t rsvd__4_7 :4 __packed;
u32_t prften :1 __packed;
u32_t icen :1 __packed;
u32_t dcen :1 __packed;
u32_t icrst :1 __packed;
u32_t dcrst :1 __packed;
u32_t run_pd :1 __packed;
u32_t sleep_pd :1 __packed;
u32_t rsvd__15_17 :3 __packed;
u32_t dbg_swend :1 __packed;
u32_t rsvd__19_31 :13 __packed;
} bit;
};
/* 3.7.13 Embedded flash registers */
struct stm32g4x_flash {
volatile union __ef_acr acr;
volatile u32_t pdkeyr;
volatile u32_t keyr;
volatile u32_t optkeyr;
volatile u32_t sr;
volatile u32_t cr;
volatile u32_t eccr;
volatile u32_t optr;
volatile u32_t pcrop1sr;
volatile u32_t pcrop1er;
volatile u32_t wrp1ar;
volatile u32_t wrp1br;
volatile u32_t pcrop2sr;
volatile u32_t pcrop2er;
volatile u32_t wrp2ar;
volatile u32_t wrp2br;
};
#endif /* _STM32G4X_FLASH_REGISTERS_H_ */