diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 8809ff25bc9..d671a2bf1a0 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -31,6 +31,13 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32 ) endif() +if(CONFIG_SOC_SERIES_STM32F7X) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32 + flash_stm32.c + flash_stm32f7x.c + ) +endif() + if(CONFIG_SOC_SERIES_STM32L4X) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_STM32 flash_stm32.c diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 13b4efeb396..de9fe30b6a8 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -10,16 +10,18 @@ if SOC_FAMILY_STM32 menuconfig SOC_FLASH_STM32 bool "STM32 flash driver" - depends on (SOC_SERIES_STM32F0X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32L4X) + depends on (SOC_SERIES_STM32F0X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32L4X) select FLASH_HAS_DRIVER_ENABLED default y select FLASH_PAGE_LAYOUT if SOC_SERIES_STM32F0X 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_STM32F4X + select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32F7X select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32L4X help - Enable STM32F0x, STM32F3x, STM32F4x OR STM32L4x series flash driver. + Enable STM32F0x, STM32F3x, STM32F4x, STM32F7x OR STM32L4x series flash driver. endif diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 820a1a7fbf9..bf76b826607 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -20,6 +20,9 @@ /* STM32F4: maximum erase time of 4s for a 128K sector */ #elif defined(CONFIG_SOC_SERIES_STM32F4X) #define STM32_FLASH_TIMEOUT (K_MSEC(4000)) +/* STM32F7: maximum erase time of 4s for a 256K sector */ +#elif defined(CONFIG_SOC_SERIES_STM32F7X) +#define STM32_FLASH_TIMEOUT (K_MSEC(4000)) /* STM32L4: maximum erase time of 24.47ms for a 2K sector */ #elif defined(CONFIG_SOC_SERIES_STM32L4X) #define STM32_FLASH_TIMEOUT (K_MSEC(25)) @@ -110,6 +113,9 @@ static void flash_stm32_flush_caches(struct device *dev, regs->acr.val &= ~FLASH_ACR_DCRST; regs->acr.val |= FLASH_ACR_DCEN; } +#elif defined(CONFIG_SOC_SERIES_STM32F7X) + SCB_InvalidateDCache_by_Addr((uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + + offset), len); #endif } @@ -178,6 +184,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_STM32F7X) + 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_STM32L4X) @@ -213,6 +221,8 @@ static struct flash_stm32_priv flash_data = { .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) + .regs = (struct stm32f7x_flash *) DT_FLASH_DEV_BASE_ADDRESS, #elif defined(CONFIG_SOC_SERIES_STM32L4X) .regs = (struct stm32l4x_flash *) DT_FLASH_DEV_BASE_ADDRESS, .pclken = { .bus = STM32_CLOCK_BUS_AHB1, diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index 4f7cb45bc00..7ad41f72701 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -23,6 +23,8 @@ struct flash_stm32_priv { struct stm32_pclken pclken; #elif defined(CONFIG_SOC_SERIES_STM32F4X) struct stm32f4x_flash *regs; +#elif defined(CONFIG_SOC_SERIES_STM32F7X) + struct stm32f7x_flash *regs; #elif defined(CONFIG_SOC_SERIES_STM32L4X) struct stm32l4x_flash *regs; /* clock subsystem driving this peripheral */ diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c new file mode 100644 index 00000000000..efde9e9a469 --- /dev/null +++ b/drivers/flash/flash_stm32f7x.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2018 Aurelien Jarno + * Copyright (c) 2018 Yong Jin + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "flash_stm32.h" + +#define STM32F7X_SECTOR_MASK ((u32_t) 0xFFFFFF07) + +bool flash_stm32_valid_range(struct device *dev, off_t offset, u32_t len, + bool write) +{ + ARG_UNUSED(write); + + return flash_stm32_range_exists(dev, offset, len); +} + +static int write_byte(struct device *dev, off_t offset, u8_t val) +{ + struct stm32f7x_flash *regs = FLASH_STM32_REGS(dev); + 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; + } + + /* prepare to write a single byte */ + regs->cr = (regs->cr & CR_PSIZE_MASK) | + FLASH_PSIZE_BYTE | FLASH_CR_PG; + /* flush the register write */ + __DSB(); + + /* write the data */ + *((u8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + /* flush the register write */ + __DSB(); + + 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 stm32f7x_flash *regs = FLASH_STM32_REGS(dev); + 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; + } + + /* Dual bank mode, SNB MSB selects the bank2, + * others select sector, so we remap sector number. + */ +#if defined(FLASH_OPTCR_nDBANK) && FLASH_SECTOR_TOTAL == 24 +#if CONFIG_FLASH_SIZE == 2048 + if (sector > 11) { + sector += 4; + } +#elif CONFIG_FLASH_SIZE == 1024 + if (sector > 7) { + sector += 8; + } +#endif /* CONFIG_FLASH_SIZE */ +#endif /* defined(FLASH_OPTCR_nDBANK) && FLASH_SECTOR_TOTAL == 24 */ + + regs->cr = (regs->cr & (CR_PSIZE_MASK | STM32F7X_SECTOR_MASK)) | + FLASH_PSIZE_BYTE | + FLASH_CR_SER | + (sector << FLASH_CR_SNB_Pos) | + FLASH_CR_STRT; + /* flush the register write */ + __DSB(); + + 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; +} + + +/* Some SoC can run in single or dual bank mode, others can't. + * Different SoC flash layouts are specified in various reference + * manuals, but the flash layout for a given number of sectors is + * consistent across these manuals. The number of sectors is given + * by the HAL as FLASH_SECTOR_TOTAL. And some SoC that with same + * FLASH_SECTOR_TOTAL have different flash size. + * + * In case of 8 sectors and 24 sectors we need to differentiate + * between two cases by using the memory size. + * In case of 24 sectors we need to check if the SoC is running + * in single or dual bank mode. + */ +#ifndef FLASH_SECTOR_TOTAL +#error "Unknown flash layout" +#elif FLASH_SECTOR_TOTAL == 2 +static const struct flash_pages_layout stm32f7_flash_layout[] = { + /* RM0385, table 4: STM32F750xx */ + {.pages_count = 2, .pages_size = KB(32)}, +}; +#elif FLASH_SECTOR_TOTAL == 4 +static const struct flash_pages_layout stm32f7_flash_layout[] = { + /* RM0431, table 4: STM32F730xx */ + {.pages_count = 4, .pages_size = KB(16)}, +}; +#elif FLASH_SECTOR_TOTAL == 8 +#if CONFIG_FLASH_SIZE == 512 +static const struct flash_pages_layout stm32f7_flash_layout[] = { + /* RM0431, table 3: STM32F72xxx and STM32F732xx/F733xx */ + {.pages_count = 4, .pages_size = KB(16)}, + {.pages_count = 1, .pages_size = KB(64)}, + {.pages_count = 3, .pages_size = KB(128)}, +}; +#elif CONFIG_FLASH_SIZE == 1024 +static const struct flash_pages_layout stm32f7_flash_layout[] = { + /* RM0385, table 3: STM32F756xx and STM32F74xxx */ + {.pages_count = 4, .pages_size = KB(32)}, + {.pages_count = 1, .pages_size = KB(128)}, + {.pages_count = 3, .pages_size = KB(256)}, +}; +#endif /* CONFIG_FLASH_SIZE */ +#elif FLASH_SECTOR_TOTAL == 24 +static const struct flash_pages_layout stm32f7_flash_layout_single_bank[] = { + /* RM0410, table 3: STM32F76xxx and STM32F77xxx in single bank */ + {.pages_count = 4, .pages_size = KB(32)}, + {.pages_count = 1, .pages_size = KB(128)}, + {.pages_count = 7, .pages_size = KB(256)}, +}; +static const struct flash_pages_layout stm32f7_flash_layout_dual_bank[] = { + /* RM0410, table 4: STM32F76xxx and STM32F77xxx in dual bank */ + {.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/* !defined(FLASH_SECTOR_TOTAL) */ + +void flash_stm32_page_layout(struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ +#if FLASH_OPTCR_nDBANK + if (FLASH_STM32_REGS(dev)->optcr & FLASH_OPTCR_nDBANK) { + *layout = stm32f7_flash_layout_single_bank; + *layout_size = ARRAY_SIZE(stm32f7_flash_layout_single_bank); + } else { + *layout = stm32f7_flash_layout_dual_bank; + *layout_size = ARRAY_SIZE(stm32f7_flash_layout_dual_bank); + } +#else + ARG_UNUSED(dev); + *layout = stm32f7_flash_layout; + *layout_size = ARRAY_SIZE(stm32f7_flash_layout); +#endif +} diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 39c2c30c363..35756371458 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -27,13 +27,23 @@ compatible = "mmio-sram"; }; - flash0: flash@8000000 { - compatible = "soc-nv-flash"; - label = "FLASH_STM32"; - write-block-size = <1>; - }; - soc { + flash-controller@40023c00 { + compatible = "st,stm32f7-flash-controller"; + label = "FLASH_CTRL"; + reg = <0x40023c00 0x400>; + interrupts = <4 0>; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@8000000 { + compatible = "soc-nv-flash"; + label = "FLASH_STM32"; + + write-block-size = <1>; + }; + }; rcc: rcc@40023800 { compatible = "st,stm32-rcc"; clocks-controller; diff --git a/dts/arm/st/f7/stm32f723Xe.dtsi b/dts/arm/st/f7/stm32f723Xe.dtsi index 6c5f2564e16..2f7e167504d 100644 --- a/dts/arm/st/f7/stm32f723Xe.dtsi +++ b/dts/arm/st/f7/stm32f723Xe.dtsi @@ -12,7 +12,11 @@ reg = <0x20000000 DT_SIZE_K(256)>; }; - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(512)>; + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(512)>; + }; + }; }; }; diff --git a/dts/arm/st/f7/stm32f746Xg.dtsi b/dts/arm/st/f7/stm32f746Xg.dtsi index d75d970dc62..9e21802113a 100644 --- a/dts/arm/st/f7/stm32f746Xg.dtsi +++ b/dts/arm/st/f7/stm32f746Xg.dtsi @@ -12,7 +12,11 @@ reg = <0x20000000 DT_SIZE_K(320)>; }; - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(1024)>; + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(1024)>; + }; + }; }; }; diff --git a/dts/arm/st/f7/stm32f769Xi.dtsi b/dts/arm/st/f7/stm32f769Xi.dtsi index 4628ecbc80b..5b3005d18fc 100644 --- a/dts/arm/st/f7/stm32f769Xi.dtsi +++ b/dts/arm/st/f7/stm32f769Xi.dtsi @@ -12,7 +12,12 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(2048)>; + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(2048)>; + }; + }; }; + }; diff --git a/dts/bindings/flash_controller/st,stm32f7-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32f7-flash-controller.yaml new file mode 100644 index 00000000000..8a62e8463cf --- /dev/null +++ b/dts/bindings/flash_controller/st,stm32f7-flash-controller.yaml @@ -0,0 +1,15 @@ +--- +title: STM32 F7 Flash Controller +version: 0.1 + +description: > + This binding gives a base representation of the STM32 F7 Flash Controller + +inherits: + !include flash-controller.yaml + +properties: + compatible: + constraint: "st,stm32f7-flash-controller" + +... diff --git a/soc/arm/st_stm32/stm32f7/dts_fixup.h b/soc/arm/st_stm32/stm32f7/dts_fixup.h index 196b4df5d13..af4e7997789 100644 --- a/soc/arm/st_stm32/stm32f7/dts_fixup.h +++ b/soc/arm/st_stm32/stm32f7/dts_fixup.h @@ -355,4 +355,7 @@ #define CONFIG_RTC_0_NAME DT_ST_STM32_RTC_40002800_LABEL #define CONFIG_RTC_PRESCALER DT_ST_STM32_RTC_40002800_PRESCALER +#define DT_FLASH_DEV_BASE_ADDRESS DT_ST_STM32F7_FLASH_CONTROLLER_40023C00_BASE_ADDRESS +#define DT_FLASH_DEV_NAME DT_ST_STM32F7_FLASH_CONTROLLER_40023C00_LABEL + /* End of SoC Level DTS fixup file */