/* * Copyright (c) 2018 Aurelien Jarno * Copyright (c) 2018 Yong Jin * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include "flash_stm32.h" bool flash_stm32_valid_range(const struct device *dev, off_t offset, uint32_t len, bool write) { ARG_UNUSED(write); return flash_stm32_range_exists(dev, offset, len); } static inline void flush_cache(FLASH_TypeDef *regs) { if (regs->ACR & FLASH_ACR_ARTEN) { regs->ACR &= ~FLASH_ACR_ARTEN; /* Reference manual: * The ART cache can be flushed only if the ART accelerator * is disabled (ARTEN = 0). */ regs->ACR |= FLASH_ACR_ARTRST; regs->ACR &= ~FLASH_ACR_ARTRST; regs->ACR |= FLASH_ACR_ARTEN; } } static int write_byte(const struct device *dev, off_t offset, uint8_t val) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); int rc; /* if the control register is locked, do not fail silently */ if (regs->CR & FLASH_CR_LOCK) { return -EIO; } rc = flash_stm32_wait_flash_idle(dev); if (rc < 0) { return rc; } /* prepare to write a single byte */ regs->CR = (regs->CR & CR_PSIZE_MASK) | FLASH_PSIZE_BYTE | FLASH_CR_PG; /* flush the register write */ barrier_dsync_fence_full(); /* write the data */ *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; /* flush the register write */ barrier_dsync_fence_full(); rc = flash_stm32_wait_flash_idle(dev); regs->CR &= (~FLASH_CR_PG); return rc; } static int erase_sector(const struct device *dev, uint32_t sector) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); int rc; /* if the control register is locked, do not fail silently */ if (regs->CR & FLASH_CR_LOCK) { return -EIO; } rc = flash_stm32_wait_flash_idle(dev); if (rc < 0) { return rc; } /* Dual bank mode, SNB MSB selects the bank2, * others select sector, so we remap sector number. */ #if defined(FLASH_OPTCR_nDBANK) && FLASH_SECTOR_TOTAL == 24 #if CONFIG_FLASH_SIZE == 2048 if (sector > 11) { sector += 4U; } #elif CONFIG_FLASH_SIZE == 1024 if (sector > 7) { sector += 8U; } #endif /* CONFIG_FLASH_SIZE */ #endif /* defined(FLASH_OPTCR_nDBANK) && FLASH_SECTOR_TOTAL == 24 */ regs->CR = (regs->CR & ~(FLASH_CR_PSIZE | FLASH_CR_SNB)) | FLASH_PSIZE_BYTE | FLASH_CR_SER | (sector << FLASH_CR_SNB_Pos) | FLASH_CR_STRT; /* flush the register write */ barrier_dsync_fence_full(); rc = flash_stm32_wait_flash_idle(dev); regs->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB); return rc; } int flash_stm32_block_erase_loop(const struct device *dev, unsigned int offset, unsigned int len) { struct flash_pages_info info; uint32_t start_sector, end_sector; uint32_t i; int rc = 0; rc = flash_get_page_info_by_offs(dev, offset, &info); if (rc) { return rc; } start_sector = info.index; rc = flash_get_page_info_by_offs(dev, offset + len - 1, &info); if (rc) { return rc; } end_sector = info.index; for (i = start_sector; i <= end_sector; i++) { rc = erase_sector(dev, i); if (rc < 0) { break; } } return rc; } int flash_stm32_write_range(const struct device *dev, unsigned int offset, const void *data, unsigned int len) { int i, rc = 0; for (i = 0; i < len; i++, offset++) { rc = write_byte(dev, offset, ((const uint8_t *) data)[i]); if (rc < 0) { return rc; } } 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 * manuals, but the flash layout for a given number of sectors is * consistent across these manuals. The number of sectors is given * by the HAL as FLASH_SECTOR_TOTAL. And some SoC that with same * FLASH_SECTOR_TOTAL have different flash size. * * In case of 8 sectors and 24 sectors we need to differentiate * between two cases by using the memory size. * In case of 24 sectors we need to check if the SoC is running * in single or dual bank mode. */ #ifndef FLASH_SECTOR_TOTAL #error "Unknown flash layout" #elif FLASH_SECTOR_TOTAL == 2 static const struct flash_pages_layout stm32f7_flash_layout[] = { /* RM0385, table 4: STM32F750xx */ {.pages_count = 2, .pages_size = KB(32)}, }; #elif FLASH_SECTOR_TOTAL == 4 static const struct flash_pages_layout stm32f7_flash_layout[] = { /* RM0431, table 4: STM32F730xx */ {.pages_count = 4, .pages_size = KB(16)}, }; #elif FLASH_SECTOR_TOTAL == 8 #if CONFIG_FLASH_SIZE == 512 static const struct flash_pages_layout stm32f7_flash_layout[] = { /* RM0431, table 3: STM32F72xxx and STM32F732xx/F733xx */ {.pages_count = 4, .pages_size = KB(16)}, {.pages_count = 1, .pages_size = KB(64)}, {.pages_count = 3, .pages_size = KB(128)}, }; #elif CONFIG_FLASH_SIZE == 1024 static const struct flash_pages_layout stm32f7_flash_layout[] = { /* RM0385, table 3: STM32F756xx and STM32F74xxx */ {.pages_count = 4, .pages_size = KB(32)}, {.pages_count = 1, .pages_size = KB(128)}, {.pages_count = 3, .pages_size = KB(256)}, }; #endif /* CONFIG_FLASH_SIZE */ #elif FLASH_SECTOR_TOTAL == 24 static const struct flash_pages_layout stm32f7_flash_layout_single_bank[] = { /* RM0410, table 3: STM32F76xxx and STM32F77xxx in single bank */ {.pages_count = 4, .pages_size = KB(32)}, {.pages_count = 1, .pages_size = KB(128)}, {.pages_count = 7, .pages_size = KB(256)}, }; static const struct flash_pages_layout stm32f7_flash_layout_dual_bank[] = { /* RM0410, table 4: STM32F76xxx and STM32F77xxx in dual bank */ {.pages_count = 4, .pages_size = KB(16)}, {.pages_count = 1, .pages_size = KB(64)}, {.pages_count = 7, .pages_size = KB(128)}, {.pages_count = 4, .pages_size = KB(16)}, {.pages_count = 1, .pages_size = KB(64)}, {.pages_count = 7, .pages_size = KB(128)}, }; #else #error "Unknown flash layout" #endif/* !defined(FLASH_SECTOR_TOTAL) */ void flash_stm32_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) { #if FLASH_OPTCR_nDBANK if (FLASH_STM32_REGS(dev)->OPTCR & FLASH_OPTCR_nDBANK) { *layout = stm32f7_flash_layout_single_bank; *layout_size = ARRAY_SIZE(stm32f7_flash_layout_single_bank); } else { *layout = stm32f7_flash_layout_dual_bank; *layout_size = ARRAY_SIZE(stm32f7_flash_layout_dual_bank); } #else ARG_UNUSED(dev); *layout = stm32f7_flash_layout; *layout_size = ARRAY_SIZE(stm32f7_flash_layout); #endif }