Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions drivers/flash/Kconfig.stm32
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ config SOC_FLASH_STM32
default y
select FLASH_PAGE_LAYOUT
select FLASH_HAS_PAGE_LAYOUT
select FLASH_HAS_EX_OP if SOC_SERIES_STM32F4X
select MPU_ALLOW_FLASH_WRITE if ARM_MPU
help
Enable flash driver for STM32 series
Expand All @@ -24,6 +23,7 @@ if SOC_FLASH_STM32
config FLASH_STM32_WRITE_PROTECT
bool "Extended operation for flash write protection control"
depends on SOC_SERIES_STM32F4X
select FLASH_HAS_EX_OP
default n
help
Enables flash extended operation for enabling/disabling flash write
Expand All @@ -39,7 +39,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
depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32L4X
select FLASH_HAS_EX_OP
default n
help
Enables flash extended operation for enabling/disabling flash readout
Expand Down
2 changes: 1 addition & 1 deletion drivers/flash/flash_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable)
return 0;
}

#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS)
#if defined(CONFIG_FLASH_EX_OP_ENABLED) && defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS)
static int flash_stm32_control_register_disable(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
Expand Down
16 changes: 7 additions & 9 deletions drivers/flash/flash_stm32f4x.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,7 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable,
switch (current_level) {
case FLASH_STM32_RDP2:
if (!enable || !permanent) {
__ASSERT(false, "RDP level 2 is permanent and can't be "
"changed!");
LOG_ERR("RDP level 2 is permanent and can't be changed!");
return -ENOTSUP;
}
break;
Expand All @@ -304,9 +303,8 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable,
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
target_level = FLASH_STM32_RDP2;
#else
__ASSERT(false,
"Permanent readout protection (RDP "
"level 0 -> 2) not allowed");
LOG_ERR("Permanent readout protection (RDP "
"level 0 -> 2) not allowed");
return -ENOTSUP;
#endif
}
Expand All @@ -317,17 +315,17 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable,
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
target_level = FLASH_STM32_RDP2;
#else
__ASSERT(false, "Permanent readout protection (RDP "
"level 1 -> 2) not allowed");
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
__ASSERT(false, "Disabling readout protection (RDP "
"level 1 -> 0) not allowed");
LOG_ERR("Disabling readout protection (RDP "
"level 1 -> 0) not allowed");
return -EACCES;
#endif
}
Expand Down
152 changes: 152 additions & 0 deletions drivers/flash/flash_stm32l4x.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN);
#include <zephyr/device.h>
#include <string.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/sys/barrier.h>
#include <zephyr/init.h>
#include <soc.h>

Expand Down Expand Up @@ -244,6 +245,157 @@ 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->CR & FLASH_CR_OPTLOCK) {
return -EIO;
}

if ((regs->OPTR & mask) == value) {
return 0;
}

rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}

regs->OPTR = (regs->OPTR & ~mask) | value;
regs->CR |= FLASH_CR_OPTSTRT;

/* Make sure previous write is completed. */
barrier_dsync_fence_full();

rc = flash_stm32_wait_flash_idle(dev);
if (rc < 0) {
return rc;
}

return 0;
}

#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)

/*
* Remark for future development implementing Write Protection for the L4 parts:
*
* STM32L4 allows for 2 write protected memory areas, c.f. FLASH_WEP1AR, FLASH_WRP1BR
* which are defined by their start and end pages.
*
* Other STM32 parts (i.e. F4 series) uses bitmask to select sectors.
*
* To implement Write Protection for L4 one should thus add a new EX_OP like
* FLASH_STM32_EX_OP_SECTOR_WP_RANGED in stm32_flash_api_extensions.h
*/

#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)
{
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;
}

int flash_stm32_get_rdp(const struct device *dev, bool *enabled,
bool *permanent)
{
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;
}
#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)
Expand Down
2 changes: 0 additions & 2 deletions tests/drivers/flash/stm32/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ CONFIG_ZTEST_NEW_API=y

CONFIG_FLASH=y
CONFIG_FLASH_EX_OP_ENABLED=y
CONFIG_FLASH_STM32_READOUT_PROTECTION=y
CONFIG_FLASH_STM32_WRITE_PROTECT=y
CONFIG_FLASH_STM32_BLOCK_REGISTERS=y

CONFIG_MAIN_STACK_SIZE=2048
11 changes: 11 additions & 0 deletions tests/drivers/flash/stm32/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#define EXPECTED_SIZE 512

static const struct device *const flash_dev = TEST_AREA_DEVICE;

#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
static const struct flash_parameters *flash_params;
static uint32_t sector_mask;
static uint8_t __aligned(4) expected[EXPECTED_SIZE];
Expand All @@ -39,21 +41,25 @@ static int sector_mask_from_offset(const struct device *dev, off_t offset,

return 0;
}
#endif

static void *flash_stm32_setup(void)
{
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
struct flash_stm32_ex_op_sector_wp_out wp_status;
struct flash_stm32_ex_op_sector_wp_in wp_request;
uint8_t buf[EXPECTED_SIZE];
bool is_buf_clear = true;
int rc;
#endif

/* Check if tested region fits in flash. */
zassert_true((TEST_AREA_OFFSET + EXPECTED_SIZE) < TEST_AREA_MAX,
"Test area exceeds flash size");

zassert_true(device_is_ready(flash_dev));

#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
flash_params = flash_get_parameters(flash_dev);

rc = sector_mask_from_offset(flash_dev, TEST_AREA_OFFSET, EXPECTED_SIZE,
Expand Down Expand Up @@ -102,10 +108,12 @@ static void *flash_stm32_setup(void)
for (int i = 0; i < EXPECTED_SIZE; i++) {
expected[i] = i;
}
#endif

return NULL;
}

#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
ZTEST(flash_stm32, test_stm32_write_protection)
{
struct flash_stm32_ex_op_sector_wp_in wp_request;
Expand Down Expand Up @@ -153,7 +161,9 @@ ZTEST(flash_stm32, test_stm32_write_protection)
zassert_equal(memcmp(buf, expected, EXPECTED_SIZE), 0,
"Read data doesn't match expected data");
}
#endif

#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
ZTEST(flash_stm32, test_stm32_readout_protection_disabled)
{
struct flash_stm32_ex_op_rdp rdp_status;
Expand All @@ -167,5 +177,6 @@ ZTEST(flash_stm32, test_stm32_readout_protection_disabled)

TC_PRINT("RDP is disabled\n");
}
#endif

ZTEST_SUITE(flash_stm32, NULL, flash_stm32_setup, NULL, NULL, NULL);
15 changes: 13 additions & 2 deletions tests/drivers/flash/stm32/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,20 @@ common:
- drivers
- flash
tests:
drivers.flash.stm32.default:
drivers.flash.stm32.f4:
platform_allow:
- nucleo_f429zi
- google_dragonclaw
filter: dt_compat_enabled("st,stm32-flash-controller") and
extra_configs:
- CONFIG_FLASH_STM32_WRITE_PROTECT=y
- CONFIG_FLASH_STM32_READOUT_PROTECTION=y
filter: dt_compat_enabled("st,stm32f4-flash-controller") and
dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
drivers.flash.stm32.l4:
platform_allow:
- nucleo_l452re_p
- disco_l475_iot1
extra_configs:
- CONFIG_FLASH_STM32_READOUT_PROTECTION=y
filter: dt_compat_enabled("st,stm32l4-flash-controller") and
dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")