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:
parent
21e389306b
commit
5b92e7af0e
8 changed files with 108 additions and 17 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue