diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 17980298b05..c312acfc5a1 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -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_STM32WBX flash_stm32wbx.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32G0X flash_stm32g0x.c) + zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32G4X flash_stm32g4x.c) endif() zephyr_include_directories_ifdef( diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 5a8819d491b..1fb88d55c05 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -10,7 +10,7 @@ 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_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 default y 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_STM32L4X 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_STM32F3X 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_STM32L4X select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32WBX + select FLASH_HAS_PAGE_LAYOUT if SOC_SERIES_STM32G4X 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 diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index fe50b88e8ed..2e32fb24001 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -36,6 +36,9 @@ #elif defined(CONFIG_SOC_SERIES_STM32G0X) /* STM32G0: maximum erase time of 40ms for a 2K sector */ #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 /* 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); #elif defined(CONFIG_SOC_SERIES_STM32F4X) || \ 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(len); #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); #elif defined(CONFIG_SOC_SERIES_STM32WBX) struct stm32wbx_flash *regs = FLASH_STM32_REGS(dev); +#elif defined(CONFIG_SOC_SERIES_STM32G4X) + struct stm32g4x_flash *regs = FLASH_STM32_REGS(dev); #endif if (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); #elif defined(CONFIG_SOC_SERIES_STM32G0X) struct stm32g0x_flash *regs = FLASH_STM32_REGS(dev); +#elif defined(CONFIG_SOC_SERIES_STM32G4X) + struct stm32g4x_flash *regs = FLASH_STM32_REGS(dev); #endif int rc = 0; @@ -279,6 +287,10 @@ static struct flash_stm32_priv flash_data = { .regs = (struct stm32g0x_flash *) DT_FLASH_DEV_BASE_ADDRESS, .pclken = { .bus = STM32_CLOCK_BUS_AHB1, .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 }; diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index 640a785ab61..cce35999098 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -13,7 +13,8 @@ #if defined(CONFIG_SOC_SERIES_STM32L4X) || \ defined(CONFIG_SOC_SERIES_STM32F0X) || \ defined(CONFIG_SOC_SERIES_STM32F3X) || \ - defined(CONFIG_SOC_SERIES_STM32G0X) + defined(CONFIG_SOC_SERIES_STM32G0X) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) #include #include #endif @@ -41,6 +42,10 @@ struct flash_stm32_priv { struct stm32g0x_flash *regs; /* clock subsystem driving this peripheral */ struct stm32_pclken pclken; +#elif defined(CONFIG_SOC_SERIES_STM32G4X) + struct stm32g4x_flash *regs; + /* clock subsystem driving this peripheral */ + struct stm32_pclken pclken; #endif struct k_sem sem; }; diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c new file mode 100644 index 00000000000..dd8de45794b --- /dev/null +++ b/drivers/flash/flash_stm32g4x.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2019 Richard Osterloh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_DOMAIN flash_stm32g4 +#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_DOMAIN); + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index 7d8b5409eef..4764161e1a1 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -26,6 +26,24 @@ }; 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 { compatible = "st,stm32-rcc"; #clock-cells = <2>; diff --git a/dts/bindings/flash_controller/st,stm32g4-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32g4-flash-controller.yaml new file mode 100644 index 00000000000..b5393bc33d1 --- /dev/null +++ b/dts/bindings/flash_controller/st,stm32g4-flash-controller.yaml @@ -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 diff --git a/soc/arm/st_stm32/stm32g4/dts_fixup.h b/soc/arm/st_stm32/stm32g4/dts_fixup.h index 5a3d82dd384..146a5db7b2b 100644 --- a/soc/arm/st_stm32/stm32g4/dts_fixup.h +++ b/soc/arm/st_stm32/stm32g4/dts_fixup.h @@ -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_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 */ diff --git a/soc/arm/st_stm32/stm32g4/flash_registers.h b/soc/arm/st_stm32/stm32g4/flash_registers.h new file mode 100644 index 00000000000..129868dec70 --- /dev/null +++ b/soc/arm/st_stm32/stm32g4/flash_registers.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Richard Osterloh + * + * 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_ */