drivers: flash: stm32: add STM32 option bytes extended ops

Add two new flash extended operations for reading and writing STM32
option bytes from the application code.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
Fabio Baltieri 2024-11-29 07:28:52 +00:00 committed by Fabio Baltieri
parent 21e389306b
commit 5b92e7af0e
8 changed files with 108 additions and 17 deletions

View file

@ -85,6 +85,14 @@ config FLASH_STM32_BLOCK_REGISTERS
registers improves system security, because flash content (or
protection settings) can't be changed even when exploit was found.
config FLASH_STM32_OPTION_BYTES
bool "Extended operation for option bytes access"
select FLASH_HAS_EX_OP
default n
help
Enables flash extended operations that can be used to read and write
STM32 option bytes.
config USE_MICROCHIP_QSPI_FLASH_WITH_STM32
bool "Include patch for Microchip qspi flash when running with stm32"
depends on DT_HAS_ST_STM32_QSPI_NOR_ENABLED

View file

@ -326,6 +326,11 @@ int flash_stm32_wait_flash_idle(const struct device *dev);
int flash_stm32_option_bytes_lock(const struct device *dev, bool enable);
uint32_t flash_stm32_option_bytes_read(const struct device *dev);
int flash_stm32_option_bytes_write(const struct device *dev, uint32_t mask,
uint32_t value);
#ifdef CONFIG_SOC_SERIES_STM32WBX
int flash_stm32_check_status(const struct device *dev);
#endif /* CONFIG_SOC_SERIES_STM32WBX */

View file

@ -252,6 +252,41 @@ int flash_stm32_ex_op(const struct device *dev, uint16_t code,
rv = flash_stm32_control_register_disable(dev);
break;
#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */
#if defined(CONFIG_FLASH_STM32_OPTION_BYTES) && ( \
defined(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED) || \
defined(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED) || \
defined(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED) || \
defined(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED))
case FLASH_STM32_EX_OP_OPTB_READ:
if (out == NULL) {
rv = -EINVAL;
break;
}
*(uint32_t *)out = flash_stm32_option_bytes_read(dev);
rv = 0;
break;
case FLASH_STM32_EX_OP_OPTB_WRITE:
int rv2;
rv = flash_stm32_option_bytes_lock(dev, false);
if (rv > 0) {
break;
}
rv2 = flash_stm32_option_bytes_write(dev, UINT32_MAX, (uint32_t)in);
/* returned later, we always re-lock */
rv = flash_stm32_option_bytes_lock(dev, true);
if (rv > 0) {
break;
}
rv = rv2;
break;
#endif
}
flash_stm32_sem_give(dev);

View file

@ -231,8 +231,8 @@ 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)
int flash_stm32_option_bytes_write(const struct device *dev, uint32_t mask,
uint32_t value)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
int rc;
@ -264,6 +264,13 @@ static __unused int write_optb(const struct device *dev, uint32_t mask,
return 0;
}
uint32_t flash_stm32_option_bytes_read(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
return regs->OPTCR;
}
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
int flash_stm32_update_wp_sectors(const struct device *dev,
uint32_t changed_sectors,
@ -279,7 +286,8 @@ int flash_stm32_update_wp_sectors(const struct device *dev,
/* Sector is protected when bit == 0. Flip protected_sectors bits */
protected_sectors = ~protected_sectors & changed_sectors;
return write_optb(dev, changed_sectors, protected_sectors);
return flash_stm32_option_bytes_write(dev, changed_sectors,
protected_sectors);
}
int flash_stm32_get_wp_sectors(const struct device *dev,
@ -304,8 +312,8 @@ uint8_t flash_stm32_get_rdp_level(const struct device *dev)
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);
flash_stm32_option_bytes_write(dev, FLASH_OPTCR_RDP_Msk,
(uint32_t)level << FLASH_OPTCR_RDP_Pos);
}
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

View file

@ -159,8 +159,8 @@ 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)
int flash_stm32_option_bytes_write(const struct device *dev, uint32_t mask,
uint32_t value)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
int rc;
@ -187,6 +187,13 @@ static __unused int write_optb(const struct device *dev, uint32_t mask,
return flash_stm32_wait_flash_idle(dev);
}
uint32_t flash_stm32_option_bytes_read(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
return regs->OPTCR;
}
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
uint8_t flash_stm32_get_rdp_level(const struct device *dev)
{
@ -197,8 +204,8 @@ uint8_t flash_stm32_get_rdp_level(const struct device *dev)
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);
flash_stm32_option_bytes_write(dev, FLASH_OPTCR_RDP_Msk,
(uint32_t)level << FLASH_OPTCR_RDP_Pos);
}
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

View file

@ -255,8 +255,8 @@ 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)
int flash_stm32_option_bytes_write(const struct device *dev, uint32_t mask,
uint32_t value)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
int rc;
@ -288,6 +288,13 @@ static __unused int write_optb(const struct device *dev, uint32_t mask,
return 0;
}
uint32_t flash_stm32_option_bytes_read(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
return regs->OPTR;
}
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
/*
@ -314,8 +321,8 @@ uint8_t flash_stm32_get_rdp_level(const struct device *dev)
void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level)
{
write_optb(dev, FLASH_OPTR_RDP_Msk,
(uint32_t)level << FLASH_OPTR_RDP_Pos);
flash_stm32_option_bytes_write(dev, FLASH_OPTR_RDP_Msk,
(uint32_t)level << FLASH_OPTR_RDP_Pos);
}
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

View file

@ -246,8 +246,8 @@ 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)
int flash_stm32_option_bytes_write(const struct device *dev, uint32_t mask,
uint32_t value)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
int rc;
@ -279,6 +279,13 @@ static __unused int write_optb(const struct device *dev, uint32_t mask,
return 0;
}
uint32_t flash_stm32_option_bytes_read(const struct device *dev)
{
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
return regs->OPTR;
}
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
/*
@ -305,8 +312,8 @@ uint8_t flash_stm32_get_rdp_level(const struct device *dev)
void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level)
{
write_optb(dev, FLASH_OPTR_RDP_Msk,
(uint32_t)level << FLASH_OPTR_RDP_Pos);
flash_stm32_option_bytes_write(dev, FLASH_OPTR_RDP_Msk,
(uint32_t)level << FLASH_OPTR_RDP_Pos);
}
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

View file

@ -48,6 +48,20 @@ enum stm32_ex_ops {
* erasing or writing.
*/
FLASH_STM32_EX_OP_BLOCK_CONTROL_REG,
/*
* STM32 option bytes read.
*
* Read the option bytes content, out takes a *uint32_t, in is unused.
*/
FLASH_STM32_EX_OP_OPTB_READ,
/*
* STM32 option bytes write.
*
* Write the option bytes content, in takes the new value, out is
* unused. Note that the new value only takes effect after the device
* is restarted.
*/
FLASH_STM32_EX_OP_OPTB_WRITE,
};
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)