From 112a3affcea4cc307a92aa86476238036b650891 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Fri, 19 Jul 2024 13:33:10 +0200 Subject: [PATCH 1/3] drivers: flash: reduce redundancy in RDP implementation on STM32 Reduce the redundancy in the readout protection implementation on STM32 MCUs. Signed-off-by: Benedikt Schmidt --- drivers/flash/flash_stm32.h | 7 +-- drivers/flash/flash_stm32_ex_op.c | 95 ++++++++++++++++++++++++++++-- drivers/flash/flash_stm32f4x.c | 95 ++---------------------------- drivers/flash/flash_stm32g4x.c | 95 ++---------------------------- drivers/flash/flash_stm32l4x.c | 97 ++----------------------------- 5 files changed, 107 insertions(+), 282 deletions(-) diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index ca08b7e16ae1c..b4dc26dd907a8 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -311,12 +311,9 @@ int flash_stm32_get_wp_sectors(const struct device *dev, uint32_t *protected_sectors); #endif #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +uint8_t flash_stm32_get_rdp_level(const struct device *dev); -int flash_stm32_update_rdp(const struct device *dev, bool enable, - bool permanent); - -int flash_stm32_get_rdp(const struct device *dev, bool *enabled, - bool *permanent); +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level); #endif /* Flash extended operations */ diff --git a/drivers/flash/flash_stm32_ex_op.c b/drivers/flash/flash_stm32_ex_op.c index 623d4e23d6d07..6f7e1fd349bcf 100644 --- a/drivers/flash/flash_stm32_ex_op.c +++ b/drivers/flash/flash_stm32_ex_op.c @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef CONFIG_USERSPACE #include @@ -17,6 +18,8 @@ #include #include "flash_stm32.h" +LOG_MODULE_REGISTER(flash_stm32_ex_op, CONFIG_FLASH_LOG_LEVEL); + #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, void *out) @@ -85,6 +88,71 @@ int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +int flash_stm32_ex_op_update_rdp(const struct device *dev, bool enable, + bool permanent) +{ + uint8_t current_level, target_level; + + current_level = flash_stm32_get_rdp_level(dev); + target_level = current_level; + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + if (!enable || !permanent) { + LOG_DBG("RDP level 2 is permanent and can't be changed!"); + return -ENOTSUP; + } + break; + case FLASH_STM32_RDP0: + if (enable) { + target_level = FLASH_STM32_RDP1; + if (permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_DBG("Permanent readout protection (RDP " + "level 0 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + } + break; + default: /* FLASH_STM32_RDP1 */ + if (enable && permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_DBG("Permanent readout protection (RDP " + "level 1 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + if (!enable) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) + target_level = FLASH_STM32_RDP0; +#else + LOG_DBG("Disabling readout protection (RDP " + "level 1 -> 0) not allowed"); + return -EACCES; +#endif + } + } + + /* Update RDP level if needed */ + if (current_level != target_level) { + LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, + target_level); + + flash_stm32_set_rdp_level(dev, target_level); + } + return 0; +} + int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, void *out) { @@ -92,6 +160,7 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, (const struct flash_stm32_ex_op_rdp *)in; struct flash_stm32_ex_op_rdp *result = (struct flash_stm32_ex_op_rdp *)out; + uint8_t current_level; #ifdef CONFIG_USERSPACE struct flash_stm32_ex_op_rdp copy; @@ -108,7 +177,7 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, #endif rc = flash_stm32_option_bytes_lock(dev, false); if (rc == 0) { - rc = flash_stm32_update_rdp(dev, request->enable, + rc = flash_stm32_ex_op_update_rdp(dev, request->enable, request->permanent); } @@ -124,10 +193,26 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, result = © } #endif - rc2 = flash_stm32_get_rdp(dev, &result->enable, - &result->permanent); - if (!rc) { - rc = rc2; + + current_level = flash_stm32_get_rdp_level(dev); + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + result->enable = true; + result->permanent = true; + break; + case FLASH_STM32_RDP0: + result->enable = false; + result->permanent = false; + break; + default: /* FLASH_STM32_RDP1 */ + result->enable = true; + result->permanent = false; } #ifdef CONFIG_USERSPACE diff --git a/drivers/flash/flash_stm32f4x.c b/drivers/flash/flash_stm32f4x.c index cc718be45936b..d1790220ed46e 100644 --- a/drivers/flash/flash_stm32f4x.c +++ b/drivers/flash/flash_stm32f4x.c @@ -295,102 +295,17 @@ int flash_stm32_get_wp_sectors(const struct device *dev, #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) -int flash_stm32_update_rdp(const struct device *dev, bool enable, - bool permanent) +uint8_t flash_stm32_get_rdp_level(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level, target_level; - current_level = - (regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos; - target_level = current_level; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - if (!enable || !permanent) { - LOG_ERR("RDP level 2 is permanent and can't be changed!"); - return -ENOTSUP; - } - break; - case FLASH_STM32_RDP0: - if (enable) { - target_level = FLASH_STM32_RDP1; - if (permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 0 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - } - break; - default: /* FLASH_STM32_RDP1 */ - if (enable && permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 1 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - if (!enable) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) - target_level = FLASH_STM32_RDP0; -#else - LOG_ERR("Disabling readout protection (RDP " - "level 1 -> 0) not allowed"); - return -EACCES; -#endif - } - } - - /* Update RDP level if needed */ - if (current_level != target_level) { - LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, - target_level); - - write_optb(dev, FLASH_OPTCR_RDP_Msk, - (uint32_t)target_level << FLASH_OPTCR_RDP_Pos); - } - return 0; + return (regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos; } -int flash_stm32_get_rdp(const struct device *dev, bool *enabled, - bool *permanent) +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) { - FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level; - - current_level = - (regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - *enabled = true; - *permanent = true; - break; - case FLASH_STM32_RDP0: - *enabled = false; - *permanent = false; - break; - default: /* FLASH_STM32_RDP1 */ - *enabled = true; - *permanent = false; - } - return 0; + write_optb(dev, FLASH_OPTCR_RDP_Msk, + (uint32_t)level << FLASH_OPTCR_RDP_Pos); } #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c index 631268a70c6ae..7e7b2c0fd4832 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -305,102 +305,17 @@ static __unused int write_optb(const struct device *dev, uint32_t mask, #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) -int flash_stm32_update_rdp(const struct device *dev, bool enable, - bool permanent) +uint8_t flash_stm32_get_rdp_level(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level, target_level; - current_level = - (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; - target_level = current_level; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - if (!enable || !permanent) { - LOG_ERR("RDP level 2 is permanent and can't be changed!"); - return -ENOTSUP; - } - break; - case FLASH_STM32_RDP0: - if (enable) { - target_level = FLASH_STM32_RDP1; - if (permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 0 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - } - break; - default: /* FLASH_STM32_RDP1 */ - if (enable && permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 1 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - if (!enable) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) - target_level = FLASH_STM32_RDP0; -#else - LOG_ERR("Disabling readout protection (RDP " - "level 1 -> 0) not allowed"); - return -EACCES; -#endif - } - } - - /* Update RDP level if needed */ - if (current_level != target_level) { - LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, - target_level); - - write_optb(dev, FLASH_OPTR_RDP_Msk, - (uint32_t)target_level << FLASH_OPTR_RDP_Pos); - } - return 0; + return (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; } -int flash_stm32_get_rdp(const struct device *dev, bool *enabled, - bool *permanent) +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) { - FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level; - - current_level = - (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - *enabled = true; - *permanent = true; - break; - case FLASH_STM32_RDP0: - *enabled = false; - *permanent = false; - break; - default: /* FLASH_STM32_RDP1 */ - *enabled = true; - *permanent = false; - } - return 0; + write_optb(dev, FLASH_OPTR_RDP_Msk, + (uint32_t)level << FLASH_OPTR_RDP_Pos); } #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index d9b0fbbcbee22..f38a36f4b36ad 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -295,107 +295,20 @@ static __unused int write_optb(const struct device *dev, uint32_t mask, #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) -int flash_stm32_update_rdp(const struct device *dev, bool enable, - bool permanent) +uint8_t flash_stm32_get_rdp_level(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level, target_level; - current_level = - (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; - target_level = current_level; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - if (!enable || !permanent) { - LOG_ERR("RDP level 2 is permanent and can't be changed!"); - return -ENOTSUP; - } - break; - case FLASH_STM32_RDP0: - if (enable) { - target_level = FLASH_STM32_RDP1; - if (permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 0 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - } - break; - default: /* FLASH_STM32_RDP1 */ - if (enable && permanent) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) - target_level = FLASH_STM32_RDP2; -#else - LOG_ERR("Permanent readout protection (RDP " - "level 1 -> 2) not allowed"); - return -ENOTSUP; -#endif - } - if (!enable) { -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) - target_level = FLASH_STM32_RDP0; -#else - LOG_ERR("Disabling readout protection (RDP " - "level 1 -> 0) not allowed"); - return -EACCES; -#endif - } - } - - /* Update RDP level if needed */ - if (current_level != target_level) { - LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, - target_level); - - write_optb(dev, FLASH_OPTR_RDP_Msk, - (uint32_t)target_level << FLASH_OPTR_RDP_Pos); - } - return 0; + return (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; } -int flash_stm32_get_rdp(const struct device *dev, bool *enabled, - bool *permanent) +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) { - FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uint8_t current_level; - - current_level = - (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; - - /* - * 0xAA = RDP level 0 (no protection) - * 0xCC = RDP level 2 (permanent protection) - * others = RDP level 1 (protection active) - */ - switch (current_level) { - case FLASH_STM32_RDP2: - *enabled = true; - *permanent = true; - break; - case FLASH_STM32_RDP0: - *enabled = false; - *permanent = false; - break; - default: /* FLASH_STM32_RDP1 */ - *enabled = true; - *permanent = false; - } - return 0; + write_optb(dev, FLASH_OPTR_RDP_Msk, + (uint32_t)level << FLASH_OPTR_RDP_Pos); } #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ - - void flash_stm32_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) From f34f7d112e3a9a6eba0695bee03119f7679ed6dc Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Fri, 19 Jul 2024 13:35:59 +0200 Subject: [PATCH 2/3] drivers: flash: implement RDP for STM32F7 Implement the readout protection for the STM32F7 series. Signed-off-by: Benedikt Schmidt --- drivers/flash/Kconfig.stm32 | 3 ++- drivers/flash/flash_stm32f7x.c | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 9fa3e8e5552e2..9a2e4d4b7d722 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -50,7 +50,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 + depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32L4X || \ + SOC_SERIES_STM32G4X || SOC_SERIES_STM32F7X select FLASH_HAS_EX_OP default n help diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c index 324b66d81979f..a1d6b9c6cb6ea 100644 --- a/drivers/flash/flash_stm32f7x.c +++ b/drivers/flash/flash_stm32f7x.c @@ -159,6 +159,48 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, return rc; } +static __unused int write_optb(const struct device *dev, uint32_t mask, + uint32_t value) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + int rc; + + if (regs->OPTCR & FLASH_OPTCR_OPTLOCK) { + return -EIO; + } + + if ((regs->OPTCR & mask) == value) { + return 0; + } + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + regs->OPTCR = (regs->OPTCR & ~mask) | value; + regs->OPTCR |= FLASH_OPTCR_OPTSTRT; + + /* Make sure previous write is completed. */ + barrier_dsync_fence_full(); + + return flash_stm32_wait_flash_idle(dev); +} + +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +uint8_t flash_stm32_get_rdp_level(const struct device *dev) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + + return (regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos; +} + +void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) +{ + write_optb(dev, FLASH_OPTCR_RDP_Msk, + (uint32_t)level << FLASH_OPTCR_RDP_Pos); +} +#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ /* Some SoC can run in single or dual bank mode, others can't. * Different SoC flash layouts are specified in various reference From 55165b75b6275bd870d82cec7483d4d34823c710 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Fri, 26 Jul 2024 14:06:00 +0200 Subject: [PATCH 3/3] tests: drivers: flash: stm32: add nucleo_f746zg Add the nucleo_f746zg to the tests for the flash driver. Signed-off-by: Benedikt Schmidt --- .../flash/stm32/boards/nucleo_f746zg.overlay | 19 +++++++++++++++++++ tests/drivers/flash/stm32/testcase.yaml | 7 +++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/drivers/flash/stm32/boards/nucleo_f746zg.overlay diff --git a/tests/drivers/flash/stm32/boards/nucleo_f746zg.overlay b/tests/drivers/flash/stm32/boards/nucleo_f746zg.overlay new file mode 100644 index 0000000000000..ad661beb63b67 --- /dev/null +++ b/tests/drivers/flash/stm32/boards/nucleo_f746zg.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 SILA Embedded Solutions GmbH + * + * 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/testcase.yaml b/tests/drivers/flash/stm32/testcase.yaml index c65df8bdffbdc..275c8aad7265a 100644 --- a/tests/drivers/flash/stm32/testcase.yaml +++ b/tests/drivers/flash/stm32/testcase.yaml @@ -35,3 +35,10 @@ tests: - CONFIG_FLASH_STM32_READOUT_PROTECTION=y filter: dt_compat_enabled("st,stm32g4-flash-controller") and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") + drivers.flash.stm32.f7: + platform_allow: + - nucleo_f746zg + extra_configs: + - 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")