From ee57c8e7490e733879d31be1a1f7cd421b7a9fae Mon Sep 17 00:00:00 2001 From: Feng Cheng Date: Tue, 30 Jul 2019 16:21:30 +0800 Subject: [PATCH] drivers: flash: Add the flash driver of the stm32f1x family Most of the code is copied from the stm32f0x family Tested on stm32f103ze soc Signed-off-by: Feng Cheng --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig.stm32 | 4 +- drivers/flash/flash_stm32.c | 14 +- drivers/flash/flash_stm32.h | 4 + drivers/flash/flash_stm32f1x.c | 167 ++++++++++++++++++ dts/arm/st/f1/stm32f1.dtsi | 22 ++- dts/arm/st/f1/stm32f103X8.dtsi | 12 +- dts/arm/st/f1/stm32f103Xb.dtsi | 12 +- dts/arm/st/f1/stm32f103Xe.dtsi | 11 +- dts/arm/st/f1/stm32f107.dtsi | 6 + dts/arm/st/f1/stm32f107Xc.dtsi | 12 +- .../st,stm32f1-flash-controller.yaml | 8 + soc/arm/st_stm32/stm32f1/dts_fixup.h | 4 +- soc/arm/st_stm32/stm32f1/flash_registers.h | 2 +- 14 files changed, 255 insertions(+), 24 deletions(-) create mode 100644 drivers/flash/flash_stm32f1x.c create mode 100644 dts/bindings/flash_controller/st,stm32f1-flash-controller.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 3c6fcc1bd36..59940c41040 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -19,6 +19,7 @@ if(CONFIG_CLOCK_CONTROL_STM32_CUBE) zephyr_sources(flash_stm32.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32F0X flash_stm32f0x.c) + zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32F1X flash_stm32f1x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32F3X flash_stm32f3x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32F4X flash_stm32f4x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32F7X flash_stm32f7x.c) diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index e4cddb39617..977670bda29 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -8,10 +8,11 @@ if SOC_FAMILY_STM32 config SOC_FLASH_STM32 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 || SOC_SERIES_STM32G4X) + depends on (SOC_SERIES_STM32F0X || SOC_SERIES_STM32F1X || 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 default y select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F0X + select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F1X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F3X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32G0X select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F4X @@ -20,6 +21,7 @@ config SOC_FLASH_STM32 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_STM32F1X 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_STM32F4X diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 2e32fb24001..ba18be56dc4 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -19,6 +19,9 @@ #if defined(CONFIG_SOC_SERIES_STM32F0X) #define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(40)) /* STM32F3: maximum erase time of 40ms for a 2K sector */ +#elif defined(CONFIG_SOC_SERIES_STM32F1X) +#define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(40)) +/* STM32F3: maximum erase time of 40ms for a 2K sector */ #elif defined(CONFIG_SOC_SERIES_STM32F3X) #define STM32_FLASH_MAX_ERASE_TIME (K_MSEC(40)) /* STM32F4: maximum erase time of 4s for a 128K sector */ @@ -226,6 +229,8 @@ static int flash_stm32_write_protection(struct device *dev, bool enable) { #if defined(CONFIG_SOC_SERIES_STM32F4X) struct stm32f4x_flash *regs = FLASH_STM32_REGS(dev); +#elif defined(CONFIG_SOC_SERIES_STM32F1X) + struct stm32f1x_flash *regs = FLASH_STM32_REGS(dev); #elif defined(CONFIG_SOC_SERIES_STM32F7X) struct stm32f7x_flash *regs = FLASH_STM32_REGS(dev); #elif defined(CONFIG_SOC_SERIES_STM32F0X) @@ -269,6 +274,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_STM32F1X) + .regs = (struct stm32f1x_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, @@ -316,6 +325,7 @@ 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_STM32F1X) || \ defined(CONFIG_SOC_SERIES_STM32F3X) || \ defined(CONFIG_SOC_SERIES_STM32G0X) struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME); @@ -324,7 +334,9 @@ static int stm32_flash_init(struct device *dev) * On STM32F0, Flash interface clock source is always HSI, * so statically enable HSI here. */ -#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32F3X) +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32F1X) || \ + defined(CONFIG_SOC_SERIES_STM32F3X) LL_RCC_HSI_Enable(); while (!LL_RCC_HSI_IsReady()) { diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index cce35999098..0f233058bbe 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -12,6 +12,7 @@ #if defined(CONFIG_SOC_SERIES_STM32L4X) || \ defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32F1X) || \ defined(CONFIG_SOC_SERIES_STM32F3X) || \ defined(CONFIG_SOC_SERIES_STM32G0X) || \ defined(CONFIG_SOC_SERIES_STM32G4X) @@ -24,6 +25,9 @@ struct flash_stm32_priv { struct stm32f0x_flash *regs; /* clock subsystem driving this peripheral */ struct stm32_pclken pclken; +#elif defined(CONFIG_SOC_SERIES_STM32F1X) + struct stm32f1x_flash *regs; + struct stm32_pclken pclken; #elif defined(CONFIG_SOC_SERIES_STM32F3X) struct stm32f3x_flash *regs; /* clock subsystem driving this peripheral */ diff --git a/drivers/flash/flash_stm32f1x.c b/drivers/flash/flash_stm32f1x.c new file mode 100644 index 00000000000..04739aaa936 --- /dev/null +++ b/drivers/flash/flash_stm32f1x.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2017 BayLibre, SAS + * Copyright (c) 2019 Feng Cheng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_DOMAIN flash_stm32f1 +#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_DOMAIN); + +#include +#include +#include +#include +#include +#include + +#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) +{ + return (!write || (offset % 2 == 0 && len % 2 == 0U)) && + flash_stm32_range_exists(dev, offset, len); +} + +static unsigned int get_page(off_t offset) +{ + return offset / FLASH_PAGE_SIZE; +} + +static int write_hword(struct device *dev, off_t offset, u16_t val) +{ + volatile u16_t *flash = (u16_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + struct stm32f1x_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 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 erase_page(struct device *dev, unsigned int page) +{ + struct stm32f1x_flash *regs = FLASH_STM32_REGS(dev); + u32_t page_address = CONFIG_FLASH_BASE_ADDRESS; + 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; + } + + /* Calculate the flash page address */ + page_address += page * FLASH_PAGE_SIZE; + + /* Set the PER bit and select the page you wish to erase */ + regs->cr |= FLASH_CR_PER; + regs->ar = page_address; + + /* 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 += 2, offset += 2U) { + rc = write_hword(dev, offset, ((const u16_t *) data)[i>>1]); + 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 stm32f0_flash_layout = { + .pages_count = 0, + .pages_size = 0, + }; + + ARG_UNUSED(dev); + + if (stm32f0_flash_layout.pages_count == 0) { + stm32f0_flash_layout.pages_count = (CONFIG_FLASH_SIZE * 1024) / + FLASH_PAGE_SIZE; + stm32f0_flash_layout.pages_size = FLASH_PAGE_SIZE; + } + + *layout = &stm32f0_flash_layout; + *layout_size = 1; +} diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index f134dfd237b..6b8ba40f87b 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -22,16 +22,30 @@ }; }; - flash0: flash@8000000 { - compatible = "soc-nv-flash"; - label = "FLASH_STM32"; - }; sram0: memory@20000000 { compatible = "mmio-sram"; }; soc { + + flash-controller@40022000 { + compatible = "st,stm32f1-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 = <2>; + }; + }; + rcc: rcc@40021000 { compatible = "st,stm32-rcc"; #clock-cells = <2>; diff --git a/dts/arm/st/f1/stm32f103X8.dtsi b/dts/arm/st/f1/stm32f103X8.dtsi index a6f633faab2..0ae648088c2 100644 --- a/dts/arm/st/f1/stm32f103X8.dtsi +++ b/dts/arm/st/f1/stm32f103X8.dtsi @@ -8,15 +8,19 @@ #include / { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(64)>; - }; - sram0: memory@20000000 { reg = <0x20000000 DT_SIZE_K(20)>; }; soc { + + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(64)>; + erase-block-size = ; + }; + }; + /* spi2 is present on all STM32F103x8 SoCs except * STM32F103T8. Delete node in stm32f103t8.dtsi. */ diff --git a/dts/arm/st/f1/stm32f103Xb.dtsi b/dts/arm/st/f1/stm32f103Xb.dtsi index 78d8890dc91..73803cd2e61 100644 --- a/dts/arm/st/f1/stm32f103Xb.dtsi +++ b/dts/arm/st/f1/stm32f103Xb.dtsi @@ -11,14 +11,18 @@ #include / { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(128)>; - }; - sram0: memory@20000000 { reg = <0x20000000 DT_SIZE_K(20)>; }; + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + erase-block-size = ; + }; + }; + /* spi2 is present on all STM32F103xB SoCs except * STM32F103TB. Delete node in stm32f103tb.dtsi. */ diff --git a/dts/arm/st/f1/stm32f103Xe.dtsi b/dts/arm/st/f1/stm32f103Xe.dtsi index 406de2350b6..4711bed2e47 100644 --- a/dts/arm/st/f1/stm32f103Xe.dtsi +++ b/dts/arm/st/f1/stm32f103Xe.dtsi @@ -11,15 +11,18 @@ #include / { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(512)>; - }; - sram0: memory@20000000 { reg = <0x20000000 DT_SIZE_K(64)>; }; soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(512)>; + erase-block-size = ; + }; + }; + uart4: serial@40004c00 { compatible = "st,stm32-uart"; reg = <0x40004c00 0x400>; diff --git a/dts/arm/st/f1/stm32f107.dtsi b/dts/arm/st/f1/stm32f107.dtsi index 5734bc0dc0b..e93a0253862 100644 --- a/dts/arm/st/f1/stm32f107.dtsi +++ b/dts/arm/st/f1/stm32f107.dtsi @@ -8,6 +8,12 @@ / { soc { + flash-controller@40022000 { + flash0: flash@8000000 { + erase-block-size = ; + }; + }; + uart4: serial@40004c00 { compatible = "st,stm32-uart"; reg = <0x40004c00 0x400>; diff --git a/dts/arm/st/f1/stm32f107Xc.dtsi b/dts/arm/st/f1/stm32f107Xc.dtsi index 32478beb922..ea7ad2e491c 100644 --- a/dts/arm/st/f1/stm32f107Xc.dtsi +++ b/dts/arm/st/f1/stm32f107Xc.dtsi @@ -8,11 +8,15 @@ #include / { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(256)>; - }; - sram0: memory@20000000 { reg = <0x20000000 DT_SIZE_K(64)>; }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(256)>; + }; + }; + }; }; diff --git a/dts/bindings/flash_controller/st,stm32f1-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32f1-flash-controller.yaml new file mode 100644 index 00000000000..35cc1288ce3 --- /dev/null +++ b/dts/bindings/flash_controller/st,stm32f1-flash-controller.yaml @@ -0,0 +1,8 @@ +title: STM32 F1 Flash Controller + +description: | + This binding gives a base representation of the STM32 F1 Flash Controller + +compatible: "st,stm32f1-flash-controller" + +include: flash-controller.yaml diff --git a/soc/arm/st_stm32/stm32f1/dts_fixup.h b/soc/arm/st_stm32/stm32f1/dts_fixup.h index 7238498268d..d4c1890ce02 100644 --- a/soc/arm/st_stm32/stm32f1/dts_fixup.h +++ b/soc/arm/st_stm32/stm32f1/dts_fixup.h @@ -225,7 +225,6 @@ #define DT_ADC_1_CLOCK_BITS DT_ST_STM32_ADC_40012400_CLOCK_BITS_0 #define DT_ADC_1_CLOCK_BUS DT_ST_STM32_ADC_40012400_CLOCK_BUS_0 - #define DT_CAN_1_BASE_ADDRESS DT_ST_STM32_CAN_40006400_BASE_ADDRESS #define DT_CAN_1_BUS_SPEED DT_ST_STM32_CAN_40006400_BUS_SPEED #define DT_CAN_1_NAME DT_ST_STM32_CAN_40006400_LABEL @@ -241,4 +240,7 @@ #define DT_CAN_1_CLOCK_BUS DT_ST_STM32_CAN_40006400_CLOCK_BUS #define DT_CAN_1_CLOCK_BITS DT_ST_STM32_CAN_40006400_CLOCK_BITS +#define DT_FLASH_DEV_BASE_ADDRESS DT_ST_STM32F1_FLASH_CONTROLLER_40022000_BASE_ADDRESS +#define DT_FLASH_DEV_NAME DT_ST_STM32F1_FLASH_CONTROLLER_40022000_LABEL + /* End of SoC Level DTS fixup file */ diff --git a/soc/arm/st_stm32/stm32f1/flash_registers.h b/soc/arm/st_stm32/stm32f1/flash_registers.h index c9c94dcd9d7..57a34f5e1b2 100644 --- a/soc/arm/st_stm32/stm32f1/flash_registers.h +++ b/soc/arm/st_stm32/stm32f1/flash_registers.h @@ -36,7 +36,7 @@ union __ef_acr { }; /* 3.3.3 Embedded flash registers */ -struct stm32f10x_flash { +struct stm32f1x_flash { volatile union __ef_acr acr; volatile u32_t keyr; volatile u32_t optkeyr;