Skip to content

Commit

Permalink
drivers: flash: stm32h7: add support for blocking registers
Browse files Browse the repository at this point in the history
Add support for blocking flash control registers and option bytes for
STM32H7 chips.

Signed-off-by: Dawid Niedzwiecki <[email protected]>
  • Loading branch information
niedzwiecki-dawid committed Feb 3, 2025
1 parent 382e317 commit 5a992a0
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 5 deletions.
64 changes: 64 additions & 0 deletions drivers/flash/flash_stm32h7x.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,70 @@ int flash_stm32_get_wp_sectors(const struct device *dev, uint64_t *protected_sec
}
#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */

#ifdef CONFIG_FLASH_STM32_BLOCK_REGISTERS
int flash_stm32_control_register_disable(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);

/*
* Access to control register can be disabled by writing wrong key to
* the key register. Option register will remain disabled until reset.
* Writing wrong key causes a bus fault, so we need to set FAULTMASK to
* disable faults, and clear bus fault pending bit before enabling them
* again.
*/
regs->CR1 |= FLASH_CR_LOCK;
#ifdef DUAL_BANK
regs->CR2 |= FLASH_CR_LOCK;
#endif /* DUAL_BANK */

__set_FAULTMASK(1);
regs->KEYR1 = 0xffffffff;

#ifdef DUAL_BANK
regs->KEYR2 = 0xffffffff;
#endif /* DUAL_BANK */
/* Make sure that the fault occurs before we clear it. */
barrier_dsync_fence_full();

/* Clear Bus Fault pending bit */
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
/* Make sure to clear the fault before changing the fault mask. */
barrier_dsync_fence_full();

__set_FAULTMASK(0);

return 0;
}

int flash_stm32_option_bytes_disable(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);

/*
* Access to option register can be disabled by writing wrong key to
* the key register. Option register will remain disabled until reset.
* Writing wrong key causes a bus fault, so we need to set FAULTMASK to
* disable faults, and clear bus fault pending bit before enabling them
* again.
*/
regs->OPTCR |= FLASH_OPTCR_OPTLOCK;

__set_FAULTMASK(1);
regs->OPTKEYR = 0xffffffff;
/* Make sure that the fault occurs before we clear it. */
barrier_dsync_fence_full();

/* Clear Bus Fault pending bit */
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
/* Make sure to clear the fault before changing the fault mask. */
barrier_dsync_fence_full();
__set_FAULTMASK(0);

return 0;
}
#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */

int flash_stm32_option_bytes_lock(const struct device *dev, bool enable)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
Expand Down
45 changes: 40 additions & 5 deletions tests/drivers/flash/stm32/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
#include <zephyr/devicetree.h>
#include <zephyr/storage/flash_map.h>
#include <zephyr/sys/barrier.h>

#define TEST_AREA storage_partition
#define TEST_AREA_OFFSET FIXED_PARTITION_OFFSET(TEST_AREA)
Expand Down Expand Up @@ -200,15 +201,46 @@ static void flash_cr_unlock(void)
{
FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;

#ifdef CONFIG_SOC_SERIES_STM32H7X
regs->KEYR1 = FLASH_KEY1;
regs->KEYR1 = FLASH_KEY2;
#ifdef DUAL_BANK
regs->KEYR2 = FLASH_KEY1;
regs->KEYR2 = FLASH_KEY2;
#endif /* DUAL_BANK */
#else /* CONFIG_SOC_SERIES_STM32H7X */
regs->KEYR = FLASH_KEY1;
regs->KEYR = FLASH_KEY2;
#endif /* CONFIG_SOC_SERIES_STM32H7X */
barrier_dsync_fence_full();
}

static bool flash_cr_locked(void)
static bool flash_cr_is_locked(void)
{
FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;

#ifdef CONFIG_SOC_SERIES_STM32H7X
return regs->CR1 & FLASH_CR_LOCK;
#ifdef DUAL_BANK
return (regs->CR1 & FLASH_CR_LOCK) && (regs->CR2 & FLASH_CR_LOCK);
#endif /* DUAL_BANK */
#else /* CONFIG_SOC_SERIES_STM32H7X */
return regs->CR & FLASH_CR_LOCK;
#endif /* CONFIG_SOC_SERIES_STM32H7X */
}

static bool flash_cr_is_unlocked(void)
{
FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;

#ifdef CONFIG_SOC_SERIES_STM32H7X
return !(regs->CR1 & FLASH_CR_LOCK);
#ifdef DUAL_BANK
return !((regs->CR1 & FLASH_CR_LOCK) || (regs->CR2 & FLASH_CR_LOCK));
#endif /* DUAL_BANK */
#else /* CONFIG_SOC_SERIES_STM32H7X */
return !(regs->CR & FLASH_CR_LOCK);
#endif /* CONFIG_SOC_SERIES_STM32H7X */
}

ZTEST(flash_stm32, test_stm32_block_registers)
Expand All @@ -227,24 +259,27 @@ ZTEST(flash_stm32, test_stm32_block_registers)
flash_stm32_option_bytes_lock(flash_dev, false);
/* Clear Bus Fault pending bit */
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
barrier_dsync_fence_full();
__set_FAULTMASK(0);
zassert_true(flash_opt_locked(), "OPT unlocked after being blocked");

/* Test CR lock. */
zassert_true(flash_cr_locked(), "CR should be locked by default");
zassert_true(flash_cr_is_locked(), "CR should be locked by default");
TC_PRINT("Unlocking CR\n");
flash_cr_unlock();
zassert_false(flash_cr_locked(), "Unable to unlock CR");
zassert_true(flash_cr_is_unlocked(), "Unable to unlock CR");
TC_PRINT("Blocking CR\n");
flash_ex_op(flash_dev, FLASH_STM32_EX_OP_BLOCK_CONTROL_REG, (uintptr_t)NULL, NULL);
zassert_true(flash_cr_locked(), "Blocking CR didn't lock CR");
zassert_true(flash_cr_is_locked(), "Blocking CR didn't lock CR");
__set_FAULTMASK(1);
TC_PRINT("Try to unlock blocked CR\n");
flash_cr_unlock();
/* Clear Bus Fault pending bit */
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
barrier_dsync_fence_full();
__set_FAULTMASK(0);
zassert_true(flash_cr_locked(), "CR unlocked after being blocked");
/* Make sure previous write is completed. */
zassert_true(flash_cr_is_locked(), "CR unlocked after being blocked");
}
#endif

Expand Down
8 changes: 8 additions & 0 deletions tests/drivers/flash/stm32/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ tests:
- CONFIG_FLASH_STM32_WRITE_PROTECT=y
filter: dt_compat_enabled("st,stm32h7-flash-controller") and
dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
drivers.flash.stm32.h7.block_registers:
platform_allow:
- nucleo_h743zi
- google_icetower
extra_configs:
- CONFIG_FLASH_STM32_BLOCK_REGISTERS=y
filter: dt_compat_enabled("st,stm32h7-flash-controller") and
dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")

0 comments on commit 5a992a0

Please sign in to comment.