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
3 changes: 2 additions & 1 deletion drivers/flash/Kconfig.stm32
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 2 additions & 5 deletions drivers/flash/flash_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
95 changes: 90 additions & 5 deletions drivers/flash/flash_stm32_ex_op.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <zephyr/device.h>
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>

#ifdef CONFIG_USERSPACE
#include <zephyr/syscall.h>
Expand All @@ -17,6 +18,8 @@
#include <soc.h>
#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)
Expand Down Expand Up @@ -85,13 +88,79 @@ 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)
{
const struct flash_stm32_ex_op_rdp *request =
(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;
Expand All @@ -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);
}

Expand All @@ -124,10 +193,26 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in,
result = &copy;
}
#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
Expand Down
95 changes: 5 additions & 90 deletions drivers/flash/flash_stm32f4x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
42 changes: 42 additions & 0 deletions drivers/flash/flash_stm32f7x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading