diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 4bc76b2d5165f..c5fbc8a0fb363 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -90,6 +90,7 @@ if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) endif() if(CONFIG_SOC_FLASH_STM32) + zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) if(CONFIG_SOC_SERIES_STM32H7X) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32H7_FLASH_CONTROLLER_ENABLED flash_stm32h7x.c) elseif(CONFIG_SOC_SERIES_STM32H7RSX) @@ -106,7 +107,6 @@ if(CONFIG_SOC_FLASH_STM32) else() if(CONFIG_DT_HAS_ST_STM32_FLASH_CONTROLLER_ENABLED) zephyr_library_sources(flash_stm32.c) - zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 0d0ecf535b977..14945a4777370 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -51,7 +51,8 @@ config FLASH_STM32_WRITE_PROTECT_DISABLE_PREVENTION config FLASH_STM32_READOUT_PROTECTION bool "Extended operation for flash readout protection control" depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32L4X || \ - SOC_SERIES_STM32G4X || SOC_SERIES_STM32F7X + SOC_SERIES_STM32G4X || SOC_SERIES_STM32F7X || \ + SOC_SERIES_STM32H7X select FLASH_HAS_EX_OP default n help diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 15ced27e49565..fedcc443f4144 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -22,7 +22,6 @@ #include #include "flash_stm32.h" -#include "stm32_hsem.h" LOG_MODULE_REGISTER(flash_stm32, CONFIG_FLASH_LOG_LEVEL); @@ -59,32 +58,6 @@ int __weak flash_stm32_check_configuration(void) return 0; } -#if defined(CONFIG_MULTITHREADING) -/* - * This is named flash_stm32_sem_take instead of flash_stm32_lock (and - * similarly for flash_stm32_sem_give) to avoid confusion with locking - * actual flash pages. - */ -static inline void _flash_stm32_sem_take(const struct device *dev) -{ - k_sem_take(&FLASH_STM32_PRIV(dev)->sem, K_FOREVER); - z_stm32_hsem_lock(CFG_HW_FLASH_SEMID, HSEM_LOCK_WAIT_FOREVER); -} - -static inline void _flash_stm32_sem_give(const struct device *dev) -{ - z_stm32_hsem_unlock(CFG_HW_FLASH_SEMID); - k_sem_give(&FLASH_STM32_PRIV(dev)->sem); -} - -#define flash_stm32_sem_init(dev) k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1) -#define flash_stm32_sem_take(dev) _flash_stm32_sem_take(dev) -#define flash_stm32_sem_give(dev) _flash_stm32_sem_give(dev) -#else -#define flash_stm32_sem_init(dev) -#define flash_stm32_sem_take(dev) -#define flash_stm32_sem_give(dev) -#endif #if !defined(CONFIG_SOC_SERIES_STM32WBX) static int flash_stm32_check_status(const struct device *dev) @@ -319,7 +292,7 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); -#if defined(FLASH_OPTCR_OPTLOCK) /* F2, F4, F7 and H7 */ +#if defined(FLASH_OPTCR_OPTLOCK) /* F2, F4, F7 */ if (enable) { regs->OPTCR |= FLASH_OPTCR_OPTLOCK; } else if (regs->OPTCR & FLASH_OPTCR_OPTLOCK) { @@ -391,12 +364,11 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable) } #if defined(CONFIG_FLASH_EX_OP_ENABLED) && defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) -static int flash_stm32_control_register_disable(const struct device *dev) +int flash_stm32_control_register_disable(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); -#if defined(FLASH_CR_LOCK) /* F0, F1, F2, F3, F4, F7, L4, G0, G4, H7, WB, WL \ - */ +#if defined(FLASH_CR_LOCK) /* F0, F1, F2, F3, F4, F7, L4, G0, G4, WB, WL */ /* * Access to control register can be disabled by writing wrong key to * the key register. Option register will remain disabled until reset. @@ -421,11 +393,11 @@ static int flash_stm32_control_register_disable(const struct device *dev) #endif } -static int flash_stm32_option_bytes_disable(const struct device *dev) +int flash_stm32_option_bytes_disable(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); -#if defined(FLASH_OPTCR_OPTLOCK) /* F2, F4, F7 and H7 */ +#if defined(FLASH_OPTCR_OPTLOCK) /* F2, F4, F7 */ /* * Access to option register can be disabled by writing wrong key to * the key register. Option register will remain disabled until reset. @@ -459,41 +431,6 @@ flash_stm32_get_parameters(const struct device *dev) return &flash_stm32_parameters; } -#ifdef CONFIG_FLASH_EX_OP_ENABLED -static int flash_stm32_ex_op(const struct device *dev, uint16_t code, - const uintptr_t in, void *out) -{ - int rv = -ENOTSUP; - - flash_stm32_sem_take(dev); - - switch (code) { -#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) - case FLASH_STM32_EX_OP_SECTOR_WP: - rv = flash_stm32_ex_op_sector_wp(dev, in, out); - break; -#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) - case FLASH_STM32_EX_OP_RDP: - rv = flash_stm32_ex_op_rdp(dev, in, out); - break; -#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ -#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) - case FLASH_STM32_EX_OP_BLOCK_OPTION_REG: - rv = flash_stm32_option_bytes_disable(dev); - break; - case FLASH_STM32_EX_OP_BLOCK_CONTROL_REG: - rv = flash_stm32_control_register_disable(dev); - break; -#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */ - } - - flash_stm32_sem_give(dev); - - return rv; -} -#endif - static struct flash_stm32_priv flash_data = { .regs = (FLASH_TypeDef *) DT_INST_REG_ADDR(0), /* Getting clocks information from device tree description depending @@ -524,7 +461,7 @@ static int stm32_flash_init(const struct device *dev) { int rc; /* Below is applicable to F0, F1, F3, G0, G4, L1, L4, L5, U5 & WB55 series. - * For F2, F4, F7 & H7 series, this is not applicable. + * For F2, F4, F7 series, this is not applicable. */ #if DT_INST_NODE_HAS_PROP(0, clocks) struct flash_stm32_priv *p = FLASH_STM32_PRIV(dev); diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index b4dc26dd907a8..48e75145dfe9d 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -10,6 +10,7 @@ #define ZEPHYR_DRIVERS_FLASH_FLASH_STM32_H_ #include +#include "stm32_hsem.h" #if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_flash_controller), clocks) || \ DT_NODE_HAS_PROP(DT_INST(0, st_stm32h7_flash_controller), clocks) @@ -271,6 +272,40 @@ static inline bool flash_stm32_range_exists(const struct device *dev, } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +#if defined(CONFIG_MULTITHREADING) || defined(CONFIG_STM32H7_DUAL_CORE) +/* + * This is named flash_stm32_sem_take instead of flash_stm32_lock (and + * similarly for flash_stm32_sem_give) to avoid confusion with locking + * actual flash pages. + */ + +static inline void _flash_stm32_sem_take(const struct device *dev) +{ + k_sem_take(&FLASH_STM32_PRIV(dev)->sem, K_FOREVER); + z_stm32_hsem_lock(CFG_HW_FLASH_SEMID, HSEM_LOCK_WAIT_FOREVER); +} + +static inline void _flash_stm32_sem_give(const struct device *dev) +{ + z_stm32_hsem_unlock(CFG_HW_FLASH_SEMID); + k_sem_give(&FLASH_STM32_PRIV(dev)->sem); +} + +#define flash_stm32_sem_init(dev) k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1) +#define flash_stm32_sem_take(dev) _flash_stm32_sem_take(dev) +#define flash_stm32_sem_give(dev) _flash_stm32_sem_give(dev) +#else +#define flash_stm32_sem_init(dev) +#define flash_stm32_sem_take(dev) +#define flash_stm32_sem_give(dev) +#endif /* CONFIG_MULTITHREADING */ + +#ifdef CONFIG_FLASH_EX_OP_ENABLED +int flash_stm32_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out); +#endif /* CONFIG_FLASH_EX_OP_ENABLED */ + static inline bool flash_stm32_valid_write(off_t offset, uint32_t len) { return ((offset % FLASH_STM32_WRITE_BLOCK_SIZE == 0) && @@ -316,14 +351,9 @@ uint8_t flash_stm32_get_rdp_level(const struct device *dev); void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level); #endif -/* Flash extended operations */ -#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) -int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, - void *out); -#endif -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) -int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, - void *out); +#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) +int flash_stm32_control_register_disable(const struct device *dev); +int flash_stm32_option_bytes_disable(const struct device *dev); #endif #endif /* ZEPHYR_DRIVERS_FLASH_FLASH_STM32_H_ */ diff --git a/drivers/flash/flash_stm32_ex_op.c b/drivers/flash/flash_stm32_ex_op.c index 6f7e1fd349bcf..5e268b7b4d2c2 100644 --- a/drivers/flash/flash_stm32_ex_op.c +++ b/drivers/flash/flash_stm32_ex_op.c @@ -225,3 +225,36 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, return rc; } #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ + +int flash_stm32_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out) +{ + int rv = -ENOTSUP; + + flash_stm32_sem_take(dev); + + switch (code) { +#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) + case FLASH_STM32_EX_OP_SECTOR_WP: + rv = flash_stm32_ex_op_sector_wp(dev, in, out); + break; +#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) + case FLASH_STM32_EX_OP_RDP: + rv = flash_stm32_ex_op_rdp(dev, in, out); + break; +#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ +#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) + case FLASH_STM32_EX_OP_BLOCK_OPTION_REG: + rv = flash_stm32_option_bytes_disable(dev); + break; + case FLASH_STM32_EX_OP_BLOCK_CONTROL_REG: + rv = flash_stm32_control_register_disable(dev); + break; +#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */ + } + + flash_stm32_sem_give(dev); + + return rv; +} diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 76970d3b50b5a..e4be761f86837 100644 --- a/drivers/flash/flash_stm32h7x.c +++ b/drivers/flash/flash_stm32h7x.c @@ -62,32 +62,77 @@ struct flash_stm32_sector_t { volatile uint32_t *sr; }; -#if defined(CONFIG_MULTITHREADING) || defined(CONFIG_STM32H7_DUAL_CORE) -/* - * This is named flash_stm32_sem_take instead of flash_stm32_lock (and - * similarly for flash_stm32_sem_give) to avoid confusion with locking - * actual flash sectors. - */ -static inline void _flash_stm32_sem_take(const struct device *dev) +static __unused int write_optb(const struct device *dev, uint32_t mask, + uint32_t value) { - k_sem_take(&FLASH_STM32_PRIV(dev)->sem, K_FOREVER); - z_stm32_hsem_lock(CFG_HW_FLASH_SEMID, HSEM_LOCK_WAIT_FOREVER); + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + int rc; + + if (regs->OPTCR & FLASH_OPTCR_OPTLOCK) { + LOG_ERR("Option bytes locked"); + return -EIO; + } + + if ((regs->OPTCR & mask) == value) { + /* Done already */ + return 0; + } + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + LOG_ERR("Err flash no idle"); + return rc; + } + + regs->OPTCR = (regs->OPTCR & ~mask) | value; + regs->OPTCR |= FLASH_OPTCR_OPTSTART; + + /* Make sure previous write is completed. */ + barrier_dsync_fence_full(); + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + LOG_ERR("Err flash no idle"); + return rc; + } + + return 0; } -static inline void _flash_stm32_sem_give(const struct device *dev) +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +uint8_t flash_stm32_get_rdp_level(const struct device *dev) { - z_stm32_hsem_unlock(CFG_HW_FLASH_SEMID); - k_sem_give(&FLASH_STM32_PRIV(dev)->sem); + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + + return (regs->OPTSR_CUR & FLASH_OPTSR_RDP_Msk) >> FLASH_OPTSR_RDP_Pos; } -#define flash_stm32_sem_init(dev) k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1) -#define flash_stm32_sem_take(dev) _flash_stm32_sem_take(dev) -#define flash_stm32_sem_give(dev) _flash_stm32_sem_give(dev) -#else -#define flash_stm32_sem_init(dev) -#define flash_stm32_sem_take(dev) -#define flash_stm32_sem_give(dev) -#endif +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) +{ + write_optb(dev, FLASH_OPTSR_RDP_Msk, + (uint32_t)level << FLASH_OPTSR_RDP_Pos); +} +#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ + +int flash_stm32_option_bytes_lock(const struct device *dev, bool enable) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + + if (enable) { + regs->OPTCR |= FLASH_OPTCR_OPTLOCK; + } else if (regs->OPTCR & FLASH_OPTCR_OPTLOCK) { + regs->OPTKEYR = FLASH_OPT_KEY1; + regs->OPTKEYR = FLASH_OPT_KEY2; + } + + if (enable) { + LOG_DBG("Option bytes locked"); + } else { + LOG_DBG("Option bytes unlocked"); + } + + return 0; +} bool flash_stm32_valid_range(const struct device *dev, off_t offset, uint32_t len, bool write) { @@ -676,6 +721,9 @@ static const struct flash_driver_api flash_stm32h7_api = { #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_stm32_page_layout, #endif +#ifdef CONFIG_FLASH_EX_OP_ENABLED + .ex_op = flash_stm32_ex_op, +#endif }; static int stm32h7_flash_init(const struct device *dev) diff --git a/tests/drivers/flash/stm32/boards/stm32h735g_disco.conf b/tests/drivers/flash/stm32/boards/stm32h735g_disco.conf new file mode 100644 index 0000000000000..450fdb4f6ace0 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h735g_disco.conf @@ -0,0 +1 @@ +CONFIG_FLASH_STM32_QSPI=n diff --git a/tests/drivers/flash/stm32/boards/stm32h735g_disco.overlay b/tests/drivers/flash/stm32/boards/stm32h735g_disco.overlay new file mode 100644 index 0000000000000..2534926bd5128 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h735g_disco.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 4KiB of flash for storage_partition. */ + storage_partition: partition@f0000 { + label = "storage"; + reg = <0x000f0000 DT_SIZE_K(4)>; + }; + }; +}; diff --git a/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.conf b/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.conf new file mode 100644 index 0000000000000..450fdb4f6ace0 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.conf @@ -0,0 +1 @@ +CONFIG_FLASH_STM32_QSPI=n diff --git a/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.overlay b/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.overlay new file mode 100644 index 0000000000000..647b8f96fcd0f --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h745i_disco_stm32h745xx_m7.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&quadspi { + status = "disabled"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 4KiB of flash for storage_partition. */ + storage_partition: partition@1f000 { + label = "storage"; + reg = <0x0001f000 DT_SIZE_K(4)>; + }; + }; +}; diff --git a/tests/drivers/flash/stm32/boards/stm32h750b_dk.conf b/tests/drivers/flash/stm32/boards/stm32h750b_dk.conf new file mode 100644 index 0000000000000..450fdb4f6ace0 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h750b_dk.conf @@ -0,0 +1 @@ +CONFIG_FLASH_STM32_QSPI=n diff --git a/tests/drivers/flash/stm32/boards/stm32h750b_dk.overlay b/tests/drivers/flash/stm32/boards/stm32h750b_dk.overlay new file mode 100644 index 0000000000000..ad7464fb62235 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/stm32h750b_dk.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 4KiB of flash for storage_partition. */ + storage_partition: partition@1f000 { + label = "storage"; + reg = <0x0001f000 DT_SIZE_K(4)>; + }; + }; +}; diff --git a/tests/drivers/flash/stm32/testcase.yaml b/tests/drivers/flash/stm32/testcase.yaml index 275c8aad7265a..9a5605ac3f676 100644 --- a/tests/drivers/flash/stm32/testcase.yaml +++ b/tests/drivers/flash/stm32/testcase.yaml @@ -42,3 +42,12 @@ tests: - CONFIG_FLASH_STM32_READOUT_PROTECTION=y filter: dt_compat_enabled("st,stm32f7-flash-controller") and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") + drivers.flash.stm32.h7: + platform_allow: + - stm32h735g_disco + - stm32h750b_dk + - stm32h745i_disco/stm32h745xx/m7 + extra_configs: + - CONFIG_FLASH_STM32_READOUT_PROTECTION=y + filter: dt_compat_enabled("st,stm32h7-flash-controller") and + dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")