diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7b0e6366ac..cb8e8632e7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -297,6 +297,7 @@ config ARCH_CHIP_STM32F7 select ARCH_HAVE_FETCHADD select ARCH_HAVE_I2CRESET select ARCH_HAVE_HEAPCHECK + select ARCH_HAVE_PROGMEM select ARCH_HAVE_SPI_BITORDER select ARM_HAVE_MPU_UNIFIED select ARMV7M_HAVE_STACKCHECK diff --git a/arch/arm/src/stm32f7/Make.defs b/arch/arm/src/stm32f7/Make.defs index a59e67bcff..2bbc6dc404 100644 --- a/arch/arm/src/stm32f7/Make.defs +++ b/arch/arm/src/stm32f7/Make.defs @@ -108,7 +108,7 @@ endif CHIP_ASRCS = CHIP_CSRCS = stm32_allocateheap.c stm32_exti_gpio.c stm32_gpio.c CHIP_CSRCS += stm32_irq.c stm32_lowputc.c stm32_rcc.c stm32_serial.c -CHIP_CSRCS += stm32_start.c stm32_capture.c +CHIP_CSRCS += stm32_start.c stm32_capture.c stm32_flash.c ifneq ($(CONFIG_SCHED_TICKLESS),y) CHIP_CSRCS += stm32_timerisr.c diff --git a/arch/arm/src/stm32f7/chip/stm32f72xx73xx_flash.h b/arch/arm/src/stm32f7/chip/stm32f72xx73xx_flash.h index d931bb6e9a..9de274e0ed 100644 --- a/arch/arm/src/stm32f7/chip/stm32f72xx73xx_flash.h +++ b/arch/arm/src/stm32f7/chip/stm32f72xx73xx_flash.h @@ -162,7 +162,7 @@ #define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ #define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ #define FLASH_CR_SNB_MASK (0xf << FLASH_CR_SNB_SHIFT) /* Used to clear FLASH_CR_SNB bits */ -# define FLASH_CR_SNB(n) ((uint32_t)(n & 0x7) << FLASH_CR_SNB_SHIFT)) /* Sector n, n=0..7 */ +# define FLASH_CR_SNB(n) ((uint32_t)(n & 0x7) << FLASH_CR_SNB_SHIFT) /* Sector n, n=0..7 */ #define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ #define FLASH_CR_PSIZE_MASK (3 << FLASH_CR_PSIZE_SHIFT) # define FLASH_CR_PSIZE_X8 (0 << FLASH_CR_PSIZE_SHIFT) /* Program x8 */ diff --git a/arch/arm/src/stm32f7/chip/stm32f74xx75xx_flash.h b/arch/arm/src/stm32f7/chip/stm32f74xx75xx_flash.h index a7624471d0..08b62e191a 100644 --- a/arch/arm/src/stm32f7/chip/stm32f74xx75xx_flash.h +++ b/arch/arm/src/stm32f7/chip/stm32f74xx75xx_flash.h @@ -151,7 +151,7 @@ #define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ #define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ #define FLASH_CR_SNB_MASK (0xf << FLASH_CR_SNB_SHIFT) -# define FLASH_CR_SNB(n) ((uint32_t)((n) % 8) << FLASH_CR_SNB_SHIFT) | ((n / 8) << 6)) /* Sector n, n=0..23 */ +# define FLASH_CR_SNB(n) (((uint32_t)((n) % 8) << FLASH_CR_SNB_SHIFT) | ((n / 8) << 6)) /* Sector n, n=0..23 */ #define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ #define FLASH_CR_PSIZE_MASK (3 << FLASH_CR_PSIZE_SHIFT) # define FLASH_CR_PSIZE_X8 (0 << FLASH_CR_PSIZE_SHIFT) /* Program x8 */ diff --git a/arch/arm/src/stm32f7/chip/stm32f76xx77xx_flash.h b/arch/arm/src/stm32f7/chip/stm32f76xx77xx_flash.h index 9ceeff0221..1e10204086 100644 --- a/arch/arm/src/stm32f7/chip/stm32f76xx77xx_flash.h +++ b/arch/arm/src/stm32f7/chip/stm32f76xx77xx_flash.h @@ -1,7 +1,7 @@ /************************************************************************************ * arch/arm/src/stm32f7/chip/stm32f74xx75xx_flash.h * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane * @@ -106,8 +106,8 @@ # define STM32_FLASH_NPAGES 12 # define STM32_FLASH_SIZE _K((4 * 32) + (1 * 128) + (7 * 256)) # define STM32_FLASH_SIZES {_K(32), _K(32), _K(32), _K(32), \ - _K(128), _K(256), _K(256), _K(256) \ - _K(256), _K(256), _K(256), _K(256)} + _K(128), _K(256), _K(256), _K(256), \ + _K(256), _K(256), _K(256), _K(256)} #endif /* Register Offsets *****************************************************************/ @@ -165,7 +165,7 @@ #define FLASH_CR_MER_MER1 (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */ #define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */ #define FLASH_CR_SNB_MASK (0x1f << FLASH_CR_SNB_SHIFT) -# define FLASH_CR_SNB(n) ((uint32_t)((n) % 12) << FLASH_CR_SNB_SHIFT) | ((n / 12) << 7)) /* Sector n, n=0..23 */ +# define FLASH_CR_SNB(n) (((uint32_t)((n) % 12) << FLASH_CR_SNB_SHIFT) | ((n / 12) << 7)) /* Sector n, n=0..23 */ #define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */ #define FLASH_CR_PSIZE_MASK (3 << FLASH_CR_PSIZE_SHIFT) # define FLASH_CR_PSIZE_X8 (0 << FLASH_CR_PSIZE_SHIFT) /* Program x8 */ diff --git a/arch/arm/src/stm32f7/stm32_flash.c b/arch/arm/src/stm32f7/stm32_flash.c new file mode 100644 index 0000000000..0975997e70 --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_flash.c @@ -0,0 +1,423 @@ +/************************************************************************************ + * arch/arm/src/stm32f7/stm32_flash.c + * + * Copyright (C) 2018 Wolpike LLC. All rights reserved. + * Author: Evgeniy Bobkov + * + * Ported from stm32f20xxf40xx_flash.c, this is the original license: + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/* Provides standard flash access functions, to be used by the flash mtd driver. + * The interface is defined in the include/nuttx/progmem.h + * + * Requirements during write/erase operations on FLASH: + * - HSI must be ON. + * - Low Power Modes are not permitted during write/erase + */ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include "chip/stm32_flash.h" +#include "up_arch.h" +#include "cache.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#define FLASH_KEY1 0x45670123 +#define FLASH_KEY2 0xcdef89ab +#define FLASH_OPTKEY1 0x08192a3b +#define FLASH_OPTKEY2 0x4c5d6e7f +#define FLASH_ERASEDVALUE 0xff + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +static sem_t g_sem = SEM_INITIALIZER(1); + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +static void up_waste(void) +{ +} + +static void sem_lock(void) +{ + int ret; + + do + { + /* Take the semaphore (perhaps waiting) */ + + ret = sem_wait(&g_sem); + + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret == -EINTR); +} + +static inline void sem_unlock(void) +{ + sem_post(&g_sem); +} + +static void flash_unlock(void) +{ + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) + { + up_waste(); + } + + if (getreg32(STM32_FLASH_CR) & FLASH_CR_LOCK) + { + /* Unlock sequence */ + + putreg32(FLASH_KEY1, STM32_FLASH_KEYR); + putreg32(FLASH_KEY2, STM32_FLASH_KEYR); + } +} + +static void flash_lock(void) +{ + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +void stm32_flash_unlock(void) +{ + sem_lock(); + flash_unlock(); + sem_unlock(); +} + +void stm32_flash_lock(void) +{ + sem_lock(); + flash_lock(); + sem_unlock(); +} + +/************************************************************************************ + * Name: stm32_flash_writeprotect + * + * Description: + * Enable or disable the write protection of a flash sector. + * + ************************************************************************************/ + +int stm32_flash_writeprotect(size_t page, bool enabled) +{ + uint32_t reg; + uint32_t val; + + if (page >= STM32_FLASH_NPAGES) + { + return -EFAULT; + } + + /* Select the register that contains the bit to be changed */ + + if (page < 12) + { + reg = STM32_FLASH_OPTCR; + } +#if defined(CONFIG_STM32_FLASH_CONFIG_I) + else + { + reg = STM32_FLASH_OPTCR1; + page -= 12; + } +#else + else + { + return -EFAULT; + } +#endif + + /* Read the option status */ + + val = getreg32(reg); + + /* Set or clear the protection */ + + if (enabled) + { + val &= ~(1 << (16+page) ); + } + else + { + val |= (1 << (16+page) ); + } + + /* Unlock options */ + + putreg32(FLASH_OPTKEY1, STM32_FLASH_OPTKEYR); + putreg32(FLASH_OPTKEY2, STM32_FLASH_OPTKEYR); + + /* Write options */ + + putreg32(val, reg); + + /* Trigger programming */ + + modifyreg32(STM32_FLASH_OPTCR, 0, FLASH_OPTCR_OPTSTRT); + + /* Wait for completion */ + + while(getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) up_waste(); + + /* Re-lock options */ + + modifyreg32(STM32_FLASH_OPTCR, 0, FLASH_OPTCR_OPTLOCK); + return 0; +} + +size_t up_progmem_pagesize(size_t page) +{ + static const size_t page_sizes[STM32_FLASH_NPAGES] = STM32_FLASH_SIZES; + + if (page >= sizeof(page_sizes) / sizeof(*page_sizes)) + { + return 0; + } + else + { + return page_sizes[page]; + } +} + +ssize_t up_progmem_getpage(size_t addr) +{ + size_t page_end = 0; + size_t i; + + if (addr >= STM32_FLASH_BASE) + { + addr -= STM32_FLASH_BASE; + } + + if (addr >= STM32_FLASH_SIZE) + { + return -EFAULT; + } + + for (i = 0; i < STM32_FLASH_NPAGES; ++i) + { + page_end += up_progmem_pagesize(i); + if (page_end > addr) + { + return i; + } + } + + return -EFAULT; +} + +size_t up_progmem_getaddress(size_t page) +{ + size_t base_address = STM32_FLASH_BASE; + size_t i; + + if (page >= STM32_FLASH_NPAGES) + { + return SIZE_MAX; + } + + for (i = 0; i < page; ++i) + { + base_address += up_progmem_pagesize(i); + } + + return base_address; +} + +size_t up_progmem_npages(void) +{ + return STM32_FLASH_NPAGES; +} + +bool up_progmem_isuniform(void) +{ +#ifdef STM32_FLASH_PAGESIZE + return true; +#else + return false; +#endif +} + +ssize_t up_progmem_ispageerased(size_t page) +{ + size_t addr; + size_t count; + size_t bwritten = 0; + + if (page >= STM32_FLASH_NPAGES) + { + return -EFAULT; + } + + /* Verify */ + + for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page); + count; count--, addr++) + { + if (getreg8(addr) != FLASH_ERASEDVALUE) + { + bwritten++; + } + } + + return bwritten; +} + +ssize_t up_progmem_erasepage(size_t page) +{ + if (page >= STM32_FLASH_NPAGES) + { + return -EFAULT; + } + + sem_lock(); + + /* Get flash ready and begin erasing single page */ + + flash_unlock(); + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_SER); + modifyreg32(STM32_FLASH_CR, FLASH_CR_SNB_MASK, FLASH_CR_SNB(page)); + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_STRT); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) up_waste(); + + modifyreg32(STM32_FLASH_CR, FLASH_CR_SER, 0); + sem_unlock(); + + /* Verify */ + + if (up_progmem_ispageerased(page) == 0) + { + return up_progmem_pagesize(page); /* success */ + } + else + { + return -EIO; /* failure */ + } +} + +ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) +{ + uint8_t *byte = (uint8_t *)buf; + size_t written = count; + + /* Check for valid address range */ + + if (addr >= STM32_FLASH_BASE) + { + addr -= STM32_FLASH_BASE; + } + + if ((addr+count) > STM32_FLASH_SIZE) + { + return -EFAULT; + } + + sem_lock(); + + /* Get flash ready and begin flashing */ + + flash_unlock(); + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); + + /* TODO: implement up_progmem_write() to support other sizes than 8-bits */ + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PSIZE_MASK, FLASH_CR_PSIZE_X8); + + for (addr += STM32_FLASH_BASE; count; count -= 1, byte++, addr += 1) + { + /* Write half-word and wait to complete */ + + putreg8(*byte, addr); + + /* Data synchronous Barrier (DSB) just after the write operation. This will + * force the CPU to respect the sequence of instruction (no optimization). + */ + + ARM_DSB(); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) up_waste(); + + /* Verify */ + + if (getreg32(STM32_FLASH_SR) & FLASH_CR_SER) + { + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + sem_unlock(); + return -EROFS; + } + + if (getreg8(addr) != *byte) + { + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + sem_unlock(); + return -EIO; + } + } + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + + sem_unlock(); + return written; +} diff --git a/arch/arm/src/stm32h7/chip/stm32h7x3xx_flash.h b/arch/arm/src/stm32h7/chip/stm32h7x3xx_flash.h index 824093b69b..e2f389c516 100644 --- a/arch/arm/src/stm32h7/chip/stm32h7x3xx_flash.h +++ b/arch/arm/src/stm32h7/chip/stm32h7x3xx_flash.h @@ -136,7 +136,7 @@ #define FLASH_CR_START (1 << 7) /* Bit 7: Erase start */ #define FLASH_CR_SNB_SHIFT (8) /* Bits 8-10: Sector number */ #define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT) /* Used to clear FLASH_CR_SNB bits */ -# define FLASH_CR_SNB(n) ((uint32_t)(n & 0x7) << FLASH_CR_SNB_SHIFT)) /* Sector n, n=0..7 */ +# define FLASH_CR_SNB(n) ((uint32_t)(n & 0x7) << FLASH_CR_SNB_SHIFT) /* Sector n, n=0..7 */ /* Bits 11-14: Reserved */ #define FLASH_CR_CRCEN (1 << 15) /* Bit 15: CRC control enable */ #define FLASH_CR_EOPIE (1 << 16) /* Bit 16: End-of-program interrupt enable */