drivers: flash: support NRF UICR operations

Nordic UICR are non-volatile memory registers for
configuring user-specific settings. Basically it is subset of flash
memory available in the SoC.

Add support for operations on NVM which belongs to UICR.
UICR are written or read as ordinary flash memory.
For erasing UICR it is required to call erase with UICR start
address and its size (this is caused by what hardware supported).

Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
Andrzej Puzdrowski 2018-11-15 15:50:03 +01:00 committed by Carles Cufí
commit cd4fbdeac8
2 changed files with 55 additions and 9 deletions

View file

@ -59,6 +59,13 @@ config SOC_FLASH_NRF_RADIO_SYNC
help
Enable synchronization between flash memory driver and radio.
config SOC_FLASH_NRF_UICR
bool "Access to UICR"
depends on SOC_FLASH_NRF
help
Enable operations on UICR. Once enabled UICR are written or read as
ordinary flash memory. Erase is possible for whole UICR at once.
config SOC_FLASH_MCUX
bool "MCUX flash shim driver"
depends on HAS_MCUX

View file

@ -85,7 +85,7 @@ static inline bool is_aligned_32(u32_t data)
return (data & 0x3) ? false : true;
}
static inline bool is_addr_valid(off_t addr, size_t len)
static inline bool is_regular_addr_valid(off_t addr, size_t len)
{
if (addr + len > NRF_FICR->CODEPAGESIZE * NRF_FICR->CODESIZE ||
addr < 0) {
@ -95,6 +95,29 @@ static inline bool is_addr_valid(off_t addr, size_t len)
return true;
}
static inline bool is_uicr_addr_valid(off_t addr, size_t len)
{
#ifdef CONFIG_SOC_FLASH_NRF_UICR
if (addr >= (off_t)NRF_UICR + sizeof(*NRF_UICR) ||
addr < (off_t)NRF_UICR ||
len > sizeof(*NRF_UICR) ||
addr + len > (off_t)NRF_UICR + sizeof(*NRF_UICR)) {
return false;
}
return true;
#else
return false;
#endif /* CONFIG_SOC_FLASH_NRF_UICR */
}
static inline bool is_addr_valid(off_t addr, size_t len)
{
return is_regular_addr_valid(addr, len) ||
is_uicr_addr_valid(addr, len);
}
static void nvmc_wait_ready(void)
{
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {
@ -153,18 +176,24 @@ static int flash_nrf_erase(struct device *dev, off_t addr, size_t size)
u32_t n_pages = size / pg_size;
int ret;
/* Erase can only be done per page */
if (((addr % pg_size) != 0) || ((size % pg_size) != 0)) {
if (is_regular_addr_valid(addr, size)) {
/* Erase can only be done per page */
if (((addr % pg_size) != 0) || ((size % pg_size) != 0)) {
return -EINVAL;
}
if (!n_pages) {
return 0;
}
#ifdef CONFIG_SOC_FLASH_NRF_UICR
} else if (addr != (off_t)NRF_UICR || size != sizeof(*NRF_UICR)) {
return -EINVAL;
}
if (!is_addr_valid(addr, size)) {
#else
} else {
return -EINVAL;
}
if (!n_pages) {
return 0;
}
#endif /* CONFIG_SOC_FLASH_NRF_UICR */
SYNC_LOCK();
@ -420,6 +449,16 @@ static int erase_op(void *context)
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos;
nvmc_wait_ready();
#ifdef CONFIG_SOC_FLASH_NRF_UICR
if (e_ctx->flash_addr == (off_t)NRF_UICR) {
NRF_NVMC->ERASEUICR = 1;
nvmc_wait_ready();
NRF_NVMC->CONFIG = prev_nvmc_cfg;
nvmc_wait_ready();
return FLASH_OP_DONE;
}
#endif
do {
NRF_NVMC->ERASEPAGE = e_ctx->flash_addr;
nvmc_wait_ready();