From 9fca766bd4cab759d54956a21b3687033b29b48b Mon Sep 17 00:00:00 2001 From: Tyler Bennett Date: Tue, 6 May 2025 18:13:04 -0500 Subject: [PATCH] arch/arm/stm32f0l0g0: Add STM32G0 Flash driver. Add arch files and Kconfig options to interface with the progmem driver on STM32G0 MCUs. Signed-off-by: Tyler Bennett --- arch/arm/Kconfig | 3 +- arch/arm/src/stm32f0l0g0/Kconfig | 200 +++- arch/arm/src/stm32f0l0g0/Make.defs | 4 + .../src/stm32f0l0g0/hardware/stm32g0_flash.h | 225 ++++- arch/arm/src/stm32f0l0g0/stm32_flash.c | 37 + arch/arm/src/stm32f0l0g0/stm32_flash.h | 67 ++ arch/arm/src/stm32f0l0g0/stm32g0_flash.c | 894 ++++++++++++++++++ 7 files changed, 1391 insertions(+), 39 deletions(-) create mode 100644 arch/arm/src/stm32f0l0g0/stm32_flash.c create mode 100644 arch/arm/src/stm32f0l0g0/stm32_flash.h create mode 100644 arch/arm/src/stm32f0l0g0/stm32g0_flash.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3bf480bc21..608b466f35 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -517,6 +517,7 @@ config ARCH_CHIP_STM32L0 config ARCH_CHIP_STM32G0 bool "STMicro STM32 G0" select ARCH_CORTEXM0 + select ARCH_HAVE_PROGMEM ---help--- STMicro STM32G0 architectures (ARM Cortex-M0+). @@ -1487,7 +1488,7 @@ config ARM_SEMIHOSTING_HOSTFS_CACHE_COHERENCE bool "Cache coherence in semihosting hostfs" depends on ARCH_DCACHE ---help--- - Flush & Invalidte cache before & after bkpt instruction. + Flush & Invalidate cache before & after bkpt instruction. endif # ARM_SEMIHOSTING_HOSTFS diff --git a/arch/arm/src/stm32f0l0g0/Kconfig b/arch/arm/src/stm32f0l0g0/Kconfig index 1929f4b107..7008d2b13e 100644 --- a/arch/arm/src/stm32f0l0g0/Kconfig +++ b/arch/arm/src/stm32f0l0g0/Kconfig @@ -454,81 +454,193 @@ config ARCH_CHIP_STM32F098VC config ARCH_CHIP_STM32G070CB bool "STM32G070CB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G070KB bool "STM32G070KB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G070RB bool "STM32G070RB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071EB bool "STM32G071EB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071G8 bool "STM32G071G8" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071GB bool "STM32G071GB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071G8XN bool "STM32G071G8XN" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071GBXN bool "STM32G071GBXN" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071K8 bool "STM32G071K8" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071KB bool "STM32G071KB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071K8XN bool "STM32G071K8XN" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071KBXN bool "STM32G071KBXN" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071C8 bool "STM32G071C8" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071CB bool "STM32G071CB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071R8 bool "STM32G071R8" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_8 depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G071RB bool "STM32G071RB" select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1KB + bool "STM32G0B1KB" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1CB + bool "STM32G0B1CB" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1RB + bool "STM32G0B1RB" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1MB + bool "STM32G0B1MB" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1VB + bool "STM32G0B1VB" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_B + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1KC + bool "STM32G0B1KC" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_C + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1CC + bool "STM32G0B1CC" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_C + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1RC + bool "STM32G0B1RC" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_C + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1MC + bool "STM32G0B1MC" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_C + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1VC + bool "STM32G0B1VC" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_C + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1KE + bool "STM32G0B1KE" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1CE + bool "STM32G0B1CE" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1RE + bool "STM32G0B1RE" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1NE + bool "STM32G0B1NE" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1ME + bool "STM32G0B1ME" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E + depends on ARCH_CHIP_STM32G0 + +config ARCH_CHIP_STM32G0B1VE + bool "STM32G0B1VE" + select STM32F0L0G0_STM32G0 + select STM32F0L0G0_FLASH_CONFIG_E depends on ARCH_CHIP_STM32G0 config ARCH_CHIP_STM32G0B1KB @@ -960,10 +1072,56 @@ config ARCH_CHIP_STM32C092RC endchoice # ST STM32F0/L0/G0/C0 Chip Selection +# Flash configurations + +config STM32F0L0G0_FLASH_CONFIG_4 + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_6 + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_8 + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_B + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_C + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_D + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_E + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_F + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_G + bool + default n + +config STM32F0L0G0_FLASH_CONFIG_I + bool + default n + +config STM32F0L0G0_FLASH_OVERRIDE + bool "Override Flash Designator" + default n + choice prompt "Override Flash Size Designator" - default STM32F0L0G0_FLASH_CONFIG_DEFAULT - depends on ARCH_CHIP_STM32 + depends on STM32F0L0G0_FLASH_OVERRIDE + default STM32F0L0G0_FLASH_OVERRIDE_B ---help--- STM32F series parts numbering (sans the package type) ends with a number or letter that designates the FLASH size. @@ -985,44 +1143,38 @@ choice STM32 Chip Selection. Examples: - If the STM32F407VE is chosen, the Flash configuration would be 'E', if a variant of + If the STM32G071RB is chosen, the Flash configuration would be 'B', if a variant of the part with a 2048 KiB Flash is released in the future one could simply select the 'I' designator here. - If an STM32F42xxx or Series parts is chosen the default Flash configuration will be 'G' - and can be set herein to 'I' to choose the larger FLASH part. - -config STM32F0L0G0_FLASH_CONFIG_DEFAULT - bool "Default" - -config STM32F0L0G0_FLASH_CONFIG_4 +config STM32F0L0G0_FLASH_OVERRIDE_4 bool "4 16KiB" -config STM32F0L0G0_FLASH_CONFIG_6 +config STM32F0L0G0_FLASH_OVERRIDE_6 bool "6 32KiB" -config STM32F0L0G0_FLASH_CONFIG_8 +config STM32F0L0G0_FLASH_OVERRIDE_8 bool "8 64KiB" -config STM32F0L0G0_FLASH_CONFIG_B +config STM32F0L0G0_FLASH_OVERRIDE_B bool "B 128KiB" -config STM32F0L0G0_FLASH_CONFIG_C +config STM32F0L0G0_FLASH_OVERRIDE_C bool "C 256KiB" -config STM32F0L0G0_FLASH_CONFIG_D +config STM32F0L0G0_FLASH_OVERRIDE_D bool "D 384KiB" -config STM32F0L0G0_FLASH_CONFIG_E +config STM32F0L0G0_FLASH_OVERRIDE_E bool "E 512KiB" -config STM32F0L0G0_FLASH_CONFIG_F +config STM32F0L0G0_FLASH_OVERRIDE_F bool "F 768KiB" -config STM32F0L0G0_FLASH_CONFIG_G +config STM32F0L0G0_FLASH_OVERRIDE_G bool "G 1024KiB" -config STM32F0L0G0_FLASH_CONFIG_I +config STM32F0L0G0_FLASH_OVERRIDE_I bool "I 2048KiB" endchoice @@ -1204,6 +1356,16 @@ config STM32F0L0G0_DFU Configure and position code for use with the STMicro DFU bootloader. Do not select this option if you will load code using JTAG/SWM. +config STM32F0L0G0_PROGMEM + bool "Flash PROGMEM support" + default n + depends on ARCH_HAVE_PROGMEM + select MTD + select MTD_PROGMEM + ---help--- + Add progmem support, start block and end block options are provided to + obtain a uniform flash memory mapping. + choice prompt "SysTick clock source" default STM32F0L0G0_SYSTICK_CORECLK diff --git a/arch/arm/src/stm32f0l0g0/Make.defs b/arch/arm/src/stm32f0l0g0/Make.defs index 6415a39736..3178c7be86 100644 --- a/arch/arm/src/stm32f0l0g0/Make.defs +++ b/arch/arm/src/stm32f0l0g0/Make.defs @@ -49,6 +49,10 @@ ifeq ($(CONFIG_BUILD_PROTECTED),y) CHIP_CSRCS += stm32_userspace.c endif +ifeq ($(CONFIG_STM32F0L0G0_PROGMEM),y) +CHIP_CSRCS += stm32_flash.c +endif + ifeq ($(CONFIG_STM32F0L0G0_GPIOIRQ),y) CHIP_CSRCS += stm32_gpioint.c endif diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32g0_flash.h b/arch/arm/src/stm32f0l0g0/hardware/stm32g0_flash.h index 4587cd50ef..5d5780116b 100644 --- a/arch/arm/src/stm32f0l0g0/hardware/stm32g0_flash.h +++ b/arch/arm/src/stm32f0l0g0/hardware/stm32g0_flash.h @@ -47,8 +47,16 @@ #define STM32_FLASH_PCROP1AER_OFFSET 0x0028 #define STM32_FLASH_WPR1AR_OFFSET 0x002c #define STM32_FLASH_WPR1BR_OFFSET 0x0030 -#define STM32_FLASH_WPR1BSR_OFFSET 0x0034 +#define STM32_FLASH_PCROP1BSR_OFFSET 0x0034 #define STM32_FLASH_PCROP1BER_OFFSET 0x0038 + +#define STM32_FLASH_PCROP2ASR_OFFSET 0x0044 +#define STM32_FLASH_PCROP2AER_OFFSET 0x0048 +#define STM32_FLASH_WRP2AR_OFFSET 0x004c +#define STM32_FLASH_WRP2BR_OFFSET 0x0050 +#define STM32_FLASH_PCROP2BSR_OFFSET 0x0054 +#define STM32_FLASH_PCROP2BER_OFFSET 0x0058 + #define STM32_FLASH_SECR_OFFSET 0x0080 /* Register Addresses *******************************************************/ @@ -64,32 +72,211 @@ #define STM32_FLASH_PCROP1AER (STM32_FLASHIF_BAER+STM32_FLASH_PCROP1AER_OFFSET) #define STM32_FLASH_WPR1AR (STM32_FLASHIF_BASE+STM32_FLASH_WPR1AR_OFFSET) #define STM32_FLASH_WPR1BR (STM32_FLASHIF_BASE+STM32_FLASH_WPR1BR_OFFSET) -#define STM32_FLASH_WPR1BSR (STM32_FLASHIF_BASE+STM32_FLASH_WPR1BSR_OFFSET) +#define STM32_FLASH_PCROP1BSR (STM32_FLASHIF_BASE+STM32_FLASH_WPR1BSR_OFFSET) #define STM32_FLASH_PCROP1BER (STM32_FLASHIF_BASE+STM32_FLASH_PCROP1BER_OFFSET) +#define STM32_FLASH_PCROP2ASR (STM32_FLASHIF_BASE+STM32_FLASH_PCROP2ASR_OFFSET) +#define STM32_FLASH_PCROP2AER (STM32_FLASHIF_BASE+STM32_FLASH_PCROP2AER_OFFSET) +#define STM32_FLASH_WRP2AR (STM32_FLASHIF_BASE+STM32_FLASH_WRP2AR_OFFSET) +#define STM32_FLASH_WRP2BR (STM32_FLASHIF_BASE+STM32_FLASH_WRP2BR_OFFSET) +#define STM32_FLASH_PCROP2BSR (STM32_FLASHIF_BASE+STM32_FLASH_PCROP2BSR_OFFSET) +#define STM32_FLASH_PCROP2BER (STM32_FLASHIF_BASE+STM32_FLASH_PCROP2BER_OFFSET) #define STM32_FLASH_SECR (STM32_FLASHIF_BASE+STM32_FLASH_SECR_OFFSET) /* Register Bitfield Definitions ********************************************/ /* Flash Access Control Register (ACR) */ -#define FLASH_ACR_LATENCY_SHIFT (0) /* Bits 0-2: Flash memory access latency*/ -#define FLASH_ACR_LATENCY_MASK (7 << FLASH_ACR_LATENCY_SHIFT) -# define FLASH_ACR_LATENCY(n) ((n) << FLASH_ACR_LATENCY_SHIFT) -# define FLASH_ACR_LATENCY_0 (0 << FLASH_ACR_LATENCY_SHIFT) /* 000: Zero wait states */ -# define FLASH_ACR_LATENCY_1 (1 << FLASH_ACR_LATENCY_SHIFT) /* 001: One wait state */ -# define FLASH_ACR_LATENCY_2 (2 << FLASH_ACR_LATENCY_SHIFT) /* 010: Two wait states */ +#define FLASH_ACR_LATENCY_SHIFT (0) /* Bits 0-2: Flash memory access latency*/ +#define FLASH_ACR_LATENCY_MASK (7 << FLASH_ACR_LATENCY_SHIFT) +# define FLASH_ACR_LATENCY(n) ((n) << FLASH_ACR_LATENCY_SHIFT) +# define FLASH_ACR_LATENCY_0 (0 << FLASH_ACR_LATENCY_SHIFT) /* 000: Zero wait states */ +# define FLASH_ACR_LATENCY_1 (1 << FLASH_ACR_LATENCY_SHIFT) /* 001: One wait state */ +# define FLASH_ACR_LATENCY_2 (2 << FLASH_ACR_LATENCY_SHIFT) /* 010: Two wait states */ - /* Bits 3-7: Reserved */ -#define FLASH_ACR_PRFTEN (1 << 8) /* Bit 8: Prefetch enable */ -#define FLASH_ACR_ICEN (1 << 9) /* Bit 9: Instruction cache enable */ - /* Bit 10:Reserved */ -#define FLASH_ACR_ICRST (1 << 11) /* Bit 11:Instruction cache reset */ - /* Bits 12-15: Reserved */ -#define FLASH_ACR_EMPTY (1 << 16) /* Bit 16: Main Flash memory area empty */ - /* Bit 17: Reserved */ -#define FLASH_ACR_DBGSWEN (1 << 18) /* Bit 18: Debug access software enable */ - /* Bits 19-31: Reserved */ + /* Bits 3-7: Reserved */ +#define FLASH_ACR_PRFTEN (1 << 8) /* Bit 8: Prefetch enable */ +#define FLASH_ACR_ICEN (1 << 9) /* Bit 9: Instruction cache enable */ + /* Bit 10:Reserved */ +#define FLASH_ACR_ICRST (1 << 11) /* Bit 11:Instruction cache reset */ + /* Bits 12-15: Reserved */ +#define FLASH_ACR_EMPTY (1 << 16) /* Bit 16: Main Flash memory area empty */ + /* Bit 17: Reserved */ +#define FLASH_ACR_DBGSWEN (1 << 18) /* Bit 18: Debug access software enable */ + /* Bits 19-31: Reserved */ -/* TODO */ +/* Flash Status Register (SR) */ + +#define FLASH_SR_EOP (1) /* Bit 0: End of operation */ +#define FLASH_SR_OPERR (1 << 1) /* Bit 1: Operation error */ + /* Bit 2: Reserved */ +#define FLASH_SR_PROGERR (1 << 3) /* Bit 3: Programming error */ +#define FLASH_SR_WRPERR (1 << 4) /* Bit 4: Write protection error */ +#define FLASH_SR_PGAERR (1 << 5) /* Bit 5: Programming alignment error */ +#define FLASH_SR_SIZERR (1 << 6) /* Bit 6: Size error */ +#define FLASH_SR_PGSERR (1 << 7) /* Bit 7: Programming sequence error */ +#define FLASH_SR_MISSERR (1 << 8) /* Bit 8: Fast programming data miss error */ +#define FLASH_SR_FASTERR (1 << 9) /* Bit 9: Fast programming error */ + /* Bits 10-13: Reserved */ +#define FLASH_SR_RDERR (1 << 14) /* Bit 14: PCROP read error */ +#define FLASH_SR_OPTVERR (1 << 15) /* Bit 15: Option and engineering bits loading validity error */ +#define FLASH_SR_BSY1 (1 << 16) /* Bit 16: Busy */ +#define FLASH_SR_BSY2 (1 << 17) /* Bit 17: Busy */ +#define FLASH_SR_CFGBSY (1 << 18) /* Bit 18: Programming or erase configuration busy */ + /* Bits 19-31: Reserved */ + +/* Flash Control Register (CR) */ + +#define FLASH_CR_PG (1) /* Bit 0: Flash memory programming enable */ +#define FLASH_CR_PER (1 << 1) /* Bit 1: Page erase enable */ +#define FLASH_CR_MER1 (1 << 2) /* Bit 2: Mass erase (Bank 1) */ +#define FLASH_CR_PNB_SHIFT (3) /* Bits 3-12: Page number selection */ +#define FLASH_CR_PNB_MASK (0x3ff << FLASH_CR_PNB_SHIFT) +# define FLASH_CR_PNB(n) ((n) << FLASH_CR_PNB_SHIFT) + +#define FLASH_CR_BKER (1 << 13) /* Bit 13: Bank selection for erase operation */ + /* Bit 14: Reserved */ +#define FLASH_CR_MER2 (1 << 15) /* Bit 15: Mass erase, Bank 2 */ +#define FLASH_CR_STRT (1 << 16) /* Bit 16: Start erase operation */ +#define FLASH_CR_OPTSTRT (1 << 17) /* Bit 17: Start of modification of option bytes */ +#define FLASH_CR_FSTPG (1 << 18) /* Bit 18: Fast programming enable */ + /* Bits 19-23: Reserved */ +#define FLASH_CR_EOPIE (1 << 24) /* Bit 24: End-of-operation interrupt enable */ +#define FLASH_CR_ERRIE (1 << 25) /* Bit 25: Error interrupt enable */ +#define FLASH_CR_RDERRIE (1 << 26) /* Bit 26: PCROP read error interrupt enable */ +#define FLASH_CR_OBL_LAUNCH (1 << 27) /* Bit 27: Option byte load launch */ +#define FLASH_CR_SEC_PROT (1 << 28) /* Bit 28: Securable memory area protection enable (Bank 1) */ +#define FLASH_CR_SEC_PROT2 (1 << 29) /* Bit 29: Securable memory area protection enable (Bank 2) */ +#define FLASH_CR_OPTLOCK (1 << 30) /* Bit 30: Options Lock */ +#define FLASH_CR_LOCK (1 << 31) /* Bit 31: FLASH_CR Lock */ + +/* Flash ECC register (ECCR) */ + +#define FLASH_ECCR_ADDR_ECC_SHIFT (0) /* Bits 0-13: ECC fail double-word address offset */ +#define FLASH_ECCR_ADDR_ECC_MASK (0x3fff << FLASH_ECCR_ADDR_ECC_SHIFT) + /* Bits 14-19: Reserved */ +#define FLASH_ECCR_SYSF_ECC (1 << 20) /* Bit 20: System flash memory ECC fail */ + /* Bits 21-23: Reserved */ +#define FLASH_ECCR_ECCCIE (1 << 24) /* Bit 24: ECC correction interrupt enable */ + /* Bits 25-29: Reserved */ +#define FLASH_ECCR_ECCC (1 << 30) /* Bit 30: ECC correction */ +#define FLASH_ECCR_ECCD (1 << 31) /* Bit 31: ECC detection */ + +/* Flash ECC register 2 (ECCR2) */ + +#define FLASH_ECCR2_ADDR_ECC_SHIFT (0) /* Bits 0-13: ECC fail double-word address offset */ +#define FLASH_ECCR2_ADDR_ECC_MASK (0x3fff << FLASH_ECCR2_ADDR_ECC_SHIFT) + /* Bits 14-19: Reserved */ +#define FLASH_ECCR2_SYSF_ECC (1 << 20) /* Bit 20: System flash memory ECC fail */ + /* Bits 21-23: Reserved */ +#define FLASH_ECCR2_ECCCIE (1 << 24) /* Bit 24: ECC correction interrupt enable */ + /* Bits 25-29: Reserved */ +#define FLASH_ECCR2_ECCC (1 << 30) /* Bit 30: ECC correction */ +#define FLASH_ECCR2_ECCD (1 << 31) /* Bit 31: ECC detection */ + +/* Flash Option Register (OPTR) */ + +#define FLASH_OPTR_RDP_SHIFT (0) +#define FLASH_OPTR_RDP_MASK (0xff << FLASH_OPTR_RDP_SHIFT) +#define FLASH_OPTR_BOR_EN (1 << 8) /* Brown out reset enable */ +#define FLASH_OPTR_BORR_LEV_SHIFT (9) /* BOR threshold at rising Vdd supply */ +#define FLASH_OPTR_BORR_LEV_MASK (0x3 << FLASH_OPTR_BORR_LEV_SHIFT) +#define FLASH_OPTR_BORF_LEV_SHIFT (11) /* BOR thresholda t falling Vdd supply */ +#define FLASH_OPTR_BORF_LEV_MASK (0x3 << FLASH_OPTR_BORF_LEV_SHIFT) +#define FLASH_OPTR_NRST_STOP (1 << 13) +#define FLASH_OPTR_NRST_STDBY (1 << 14) +#define FLASH_OPTR_NRSTS_SHDW (1 << 15) +#define FLASH_OPTR_IDWG_SW (1 << 16) /* Bit 16: Independent watchdog selection */ +#define FLASH_OPTR_IDWG_STOP (1 << 17) /* Bit 17: Independent watchdog counter freeze in stop mode */ +#define FLASH_OPTR_IDWG_STDBY (1 << 18) /* Bit 18: Independent watchdog counter freeze in Standby mode */ +#define FLASH_OPTR_WWDG_SW (1 << 19) /* Bit 19: Window watchdog selection */ +#define FLASH_OPTR_NSWAP_BANK (1 << 20) /* Bit 20: Empty check boot configuration */ +#define FLASH_OPTR_DUAL_BANK (1 << 21) /* Bit 21: Dual-bank on 512 Kbytes or 256 Kbytes flash memory devices */ +#define FLASH_OPTR_RAM_PARITY_CHECK (1 << 22) /* Bit 22: SRAm parity check control */ + /* Bit 23: Reserved */ +#define FLASH_OPTR_NBOOT_SEL (1 << 24) +#define FLASH_OPTR_NBOOT1 (1 << 25) +#define FLASH_OPTR_NBOOT0 (1 << 26) +#define FLASH_OPTR_NRST_MODE_SHIFT (27) +#define FLASH_OPTR_NRST_MODE_MASK (0x3 << FLASH_OPTR_NRST_MODE_SHIFT) +#define FLASH_OPTR_IRHEN (1 << 29) /* Bit 29: Internal reset holder enable */ + +/* Flash PCROP area A start address register (PCROP1ASR) */ + +#define FLASH_PCROP1ASR_STRT_SHIFT (0) +#define FLASH_PCROP1ASR_STRT_MASK (0x1ff << FLASH_PCROP1ASR_STRT_SHIFT) + +/* Flash PCROP area A end address register (PCROP1AER) */ + +#define FLASH_PCROP1AER_PCROP1A_END_SHIFT (0) +#define FLASH_PCROP1AER_PCROP1A_END_MASK (0x1ff << FLASH_PCROP1AER_PCROP1A_END_SHIFT) +#define FLASH_PCROP1AER_PCROP_RDP (1 << 31) + +/* Flash WRP area A address register (WRP1AR) */ + +#define FLASH_WRP1AR_WRP1A_STRT_SHIFT (0) +#define FLASH_WRP1AR_WRP1A_STRT_MASK (0x7f << FLASH_WRP1AR_WRP1A_STRT_SHIFT) +#define FLASH_WRP1AR_WRP1A_END_SHIFT (16) +#define FLASH_WRP1AR_WRP1A_END_MASK (0x7f << FLASH_WRP1AR_WRP1A_END_SHIFT) + +/* Flash WRP area B address register (WRP1BR) */ + +#define FLASH_WRP1BR_WRP1B_STRT_SHIFT (0) +#define FLASH_WRP1BR_WRP1B_STRT_MASK (0x7f << FLASH_WRP1BR_WRP1B_STRT_SHIFT) +#define FLASH_WRP1BR_WRP1B_END_SHIFT (16) +#define FLASH_WRP1BR_WRP1B_END_MASK (0x7f << FLASH_WRP1BR_WRP1B_END_SHIFT) + +/* Flash PCROP area B start address register (PCROP1BSR) */ + +#define FLASH_PCROP1BSR_PCROP1B_STRT_SHIFT (0) +#define FLASH_PCROP1BSR_PCROP1B_STRT_MASK (0x1ff << FLASH_PCROP1BSR_PCROP1B_STRT_SHIFT) + +/* Flash PCROP area B end address register (PCROP1BER) */ + +#define FLASH_PCROP1BER_PCROP1B_END_SHIFT (0) +#define FLASH_PCROP1BER_PCROP1B_END_MASK (0x1ff << FLASH_PCROP1BER_PCROP1B_END_SHIFT) + +/* Flash PCROP2 area A start address register (PCROP2ASR) */ + +#define FLASH_PCROP2ASR_PCROP2A_STRT_SHIFT (0) +#define FLASH_PCROP2ASR_PCROP2A_STRT_MASK (0x1ff << FLASH_PCROP2ASR_PCROP2A_STRT_SHIFT) + +/* Flash PCROP2 area A end address register (PCROP2AER) */ + +#define FLASH_PCROP2AER_PCROP2A_END_SHIFT (0) +#define FLASH_PCROP2AER_PCROP2A_END_MASK (0x1ff << FLASH_PCROP2AER_PCROP2A_END_SHIFT) + +/* Flash WRP area A address register (WRP2AR) */ + +#define FLASH_WRP2AR_WRP2A_STRT_SHIFT (0) +#define FLASH_WRP2AR_WRP2A_STRT_MASK (0x7f << FLASH_WRP2AR_WRP2A_STRT_SHIFT) +#define FLASH_WRP2AR_WRP2A_END_SHIFT (16) +#define FLASH_WRP2AR_WRP2A_END_MASK (0x7f << FLASH_WRP2AR_WRP2A_END_SHIFT) + +/* Flash WRP area B address register (WRP2BR) */ + +#define FLASH_WRP2BR_WRP2B_STRT_SHIFT (0) +#define FLASH_WRP2BR_WRP2B_STRT_MASK (0x7f << FLASH_WRP2BR_WRP2B_STRT_SHIFT) +#define FLASH_WRP2BR_WRP2B_END_SHIFT (16) +#define FLASH_WRP2BR_WRP2B_END_MASK (0x7f << FLASH_WRP2BR_WRP2B_END_SHIFT) + +/* Flash PCROP2 area B start address register (PCROP2BSR) */ + +#define FLASH_PCROP2BSR_PCROP2B_STRT_SHIFT (0) +#define FLASH_PCROP2BSR_PCROP2B_STRT_MASK (0x1ff << FLASH_PCROP2BSR_PCROP2B_STRT_SHIFT) + +/* Flash PCROP2 area B end address register (PCROP2BER) */ + +#define FLASH_PCROP2BER_PCROP2B_END_SHIFT (0) +#define FLASH_PCROP2BER_PCROP2B_END_MASK (0x1ff << FLASH_PCROP2BER_PCROP2B_END_SHIFT) + +/* Flash Security register (SECR) */ + +#define FLASH_SECR_SEC_SIZE_SHIFT (0) /* Bits 0-7: Securable memory area size (Bank 1) */ +#define FLASH_SECR_SEC_SIZE_MASK (0xff << FLASH_SECR_SEC_SIZE_SHIFT) + /* Bits 8-15: Reserved */ +#define FLASH_SECR_BOOT_LOCK (1 << 16) /* Bit 16: Used to force boot from user area */ +#define FLASH_SECR_SEC_SIZE2_SHIFT (20) /* Bits 20-27: Securable memory area size (Bank 2) */ +#define FLASH_SECR_SEC_SIZE2_MASK (0xff << FLASH_SECR_SEC_SIZE2_SHIFT) + /* Bits 28-31: Reserved */ #endif /* __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32G0_FLASH_H */ diff --git a/arch/arm/src/stm32f0l0g0/stm32_flash.c b/arch/arm/src/stm32f0l0g0/stm32_flash.c new file mode 100644 index 0000000000..cd3b6e2ace --- /dev/null +++ b/arch/arm/src/stm32f0l0g0/stm32_flash.c @@ -0,0 +1,37 @@ +/**************************************************************************** + * arch/arm/src/stm32f0l0g0/stm32_flash.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_STM32F0L0G0_STM32G0) +# include "stm32g0_flash.c" +#else +# error "Flash driver unsupported on selected chip." +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ diff --git a/arch/arm/src/stm32f0l0g0/stm32_flash.h b/arch/arm/src/stm32f0l0g0/stm32_flash.h new file mode 100644 index 0000000000..1c670fa862 --- /dev/null +++ b/arch/arm/src/stm32f0l0g0/stm32_flash.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * arch/arm/src/stm32f0l0g0/stm32_flash.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32F0L0G0_STM32_FLASH_H +#define __ARCH_ARM_SRC_STM32F0L0G0_STM32_FLASH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "hardware/stm32_flash.h" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +void stm32_flash_getopt(uint32_t *opt); + +int stm32_flash_optmodify(uint32_t clear, uint32_t set); + +void stm32_flash_lock(void); + +void stm32_flash_unlock(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_FLASH_H */ \ No newline at end of file diff --git a/arch/arm/src/stm32f0l0g0/stm32g0_flash.c b/arch/arm/src/stm32f0l0g0/stm32g0_flash.c new file mode 100644 index 0000000000..c99b7df949 --- /dev/null +++ b/arch/arm/src/stm32f0l0g0/stm32g0_flash.c @@ -0,0 +1,894 @@ +/**************************************************************************** + * arch/arm/src/stm32f0l0g0/stm32g0_flash.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Provides standard flash access functions, to be used by the flash mtd + * driver. The interface is defined in the include/nuttx/progmem.h + * + * Notes: + * - Terminology: the G0xx reference manual [RM0444] refers to erase blocks + * as 'pages'. In this file, erase blocks are referred to as 'blocks' and + * the smallest write allowed is referred to as a 'page'. The STMicro + * reference manuals are not consistent in naming convention. + * - Blocking Nature: up_progmem_write() and up_progmem_eraseblock() will + * both block without releasing (up_udelay) while waiting for flash + * operations to complete. Take this into account for applications + * that use these functions. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "stm32_flash.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "hardware/stm32_flash.h" +#include "hardware/stm32_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define _K(x) ((x)*1024) +#define FLASH_BLOCK_SIZE _K(2) +#define FLASH_PAGE_SIZE 8 + +#if !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_4) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_6) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_8) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_B) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_C) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_E) && \ + !defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE) +# error "No valid flash configuration was defined." +#endif + +#ifdef CONFIG_STM32F0L0G0_FLASH_OVERRIDE +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_4 +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_6 +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_8 +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_B +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_C +# undef CONFIG_STM32F0L0G0_FLASH_CONFIG_E +# if defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_4) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_4 +# elif defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_6) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_6 +# elif defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_8) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_8 +# elif defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_B) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_B +# elif defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_C) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_C +# elif defined(CONFIG_STM32F0L0G0_FLASH_OVERRIDE_E) +# define CONFIG_STM32F0L0G0_FLASH_CONFIG_E +# else +# error "Invalid flash configuration override provided" +# endif +#endif + +#if defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_4) +# define FLASH_NBLOCKS 8 +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_6) +# define FLASH_NBLOCKS 16 +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_8) +# define FLASH_NBLOCKS 32 +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_B) +# define FLASH_NBLOCKS 64 +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_C) +# define FLASH_NBLOCKS 128 +# define FLASH_DUAL_BANK 1 +# define FLASH_BANK2_BASE 0x08020000 +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_E) +# define FLASH_NBLOCKS 256 +# define FLASH_DUAL_BANK 1 +# define FLASH_BANK2_BASE 0x08040000 +#else +# error "Invalid flash configuration defined" +#endif + +#ifdef FLASH_DUAL_BANK +# define FLASH_BANKSIZE (FLASH_NBLOCKS * FLASH_BLOCK_SIZE / 2) +#else +# define FLASH_BANKSIZE (FLASH_NBLOCKS * FLASH_BLOCK_SIZE) +#endif + +/* Dual bank G0B1 MCUs have a non-linear mapping of block number between + * banks. Bank 2 starts at block number 256, even if bank 1 ends at 63 + * or 127. + */ + +#define FLASH_BANK2_START_BLOCKNUM 256 + +#define FLASH_TOTALSIZE (FLASH_NBLOCKS * FLASH_BLOCK_SIZE) +#define FLASH_NPAGES (FLASH_NBLOCKS * FLASH_BLOCK_SIZE / FLASH_PAGE_SIZE) +#define FLASH_KEY1 0x45670123 +#define FLASH_KEY2 0xcdef89ab +#define FLASH_OPTKEY1 0x08192a3b +#define FLASH_OPTKEY2 0x4c5d6e7f +#define FLASH_ERASEDVALUE 0xffu +#define FLASH_ERASEDVALUE_DW 0xffffffffu + +#define FLASH_TIMEOUT 5000000 /* 5s */ + +#define FLASH_SR_CLEAR_ERROR_FLAGS (FLASH_SR_OPERR|FLASH_SR_PROGERR|FLASH_SR_WRPERR|\ + FLASH_SR_PGAERR|FLASH_SR_SIZERR|FLASH_SR_PGSERR|\ + FLASH_SR_MISSERR|FLASH_SR_FASTERR|FLASH_SR_RDERR|FLASH_SR_OPTVERR) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_flash_priv_s +{ + uint32_t base; /* FLASH base address */ + uint32_t stblock; /* The first block number */ + uint32_t stpage; /* The first page number */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void flash_unlock_cr(void); +static void flash_lock_cr(void); +static bool flash_unlock_opt(void); +static void flash_lock_opt(void); +static int flash_israngeerased(size_t startaddress, size_t size); +static inline struct stm32_flash_priv_s *flash_bank(size_t address); +static int flash_wait_for_operation(void); +static int flash_verify_blocknum(size_t block); +static uint32_t flash_block_address(size_t block); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct stm32_flash_priv_s flash_bank1_priv = +{ + .base = STM32_FLASH_BASE, + .stblock = 0, + .stpage = 0 +}; + +#ifdef FLASH_DUAL_BANK +static struct stm32_flash_priv_s flash_bank2_priv = +{ + .base = FLASH_BANK2_BASE, + .stblock = FLASH_BANK2_START_BLOCKNUM, + .stpage = (FLASH_NPAGES / 2) +}; +#endif + +static mutex_t g_lock = NXMUTEX_INITIALIZER; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: flash_bank + * + * Description: + * Returns the priv pointer to the correct bank + * + ****************************************************************************/ + +static inline struct stm32_flash_priv_s *flash_bank(size_t address) +{ + struct stm32_flash_priv_s *priv = NULL; + + if (address >= flash_bank1_priv.base && + address < flash_bank1_priv.base + FLASH_BANKSIZE) + { + priv = &flash_bank1_priv; + } +#ifdef FLASH_DUAL_BANK + else if (address >= flash_bank2_priv.base && + address < flash_bank2_priv.base + FLASH_BANKSIZE) + { + priv = &flash_bank2_priv; + } +#endif + + return priv; +} + +/**************************************************************************** + * Name: flash_israngeerased + * + * Description: + * Returns count of non-erased words + * + ****************************************************************************/ + +static int flash_israngeerased(size_t startaddress, size_t size) +{ + uint32_t *addr; + uint8_t *baddr; + size_t count = 0; + size_t bwritten = 0; + + if (!flash_bank(startaddress) || !flash_bank(startaddress + size - 1)) + { + return -EIO; + } + + addr = (uint32_t *)startaddress; + + while (count + 4 <= size) + { + if (getreg32(addr) != FLASH_ERASEDVALUE_DW) + { + bwritten++; + } + + addr++; + count += 4; + } + + baddr = (uint8_t *)addr; + + while (count < size) + { + if (getreg8(baddr) != FLASH_ERASEDVALUE) + { + /* Technically counting more than once per word but OK since + * anything that is non-zero is a failure anyways. + */ + + bwritten++; + } + + baddr++; + count++; + } + + return bwritten; +} + +/**************************************************************************** + * Name: flash_wait_for_operation() + * + * Description: + * Wait for last write/erase operation to finish + * Return error in case of timeout + * + * Returned Value: + * Zero or error value + * + * -EBUSY: Timeout while waiting for previous write/erase operation to + * complete + * + ****************************************************************************/ + +static int flash_wait_for_operation(void) +{ + int i; + bool timeout = true; + + UP_DSB(); + + for (i = 0; i < FLASH_TIMEOUT; i += 10) + { + if (!(getreg32(STM32_FLASH_SR) & + (FLASH_SR_CFGBSY | FLASH_SR_BSY1 | FLASH_SR_BSY2))) + { + timeout = false; + break; + } + + up_udelay(10); + } + + if (timeout) + { + return -EBUSY; + } + + return 0; +} + +/**************************************************************************** + * Name: flash_unlock_cr + * + * Description: + * Unlock flash control register, if it is not already unlocked. + * + ****************************************************************************/ + +static void flash_unlock_cr(void) +{ + /* FLASH_CR cannot be written when BSY1 flag set */ + + while (getreg32(STM32_FLASH_SR) & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) + { + } + + if (getreg32(STM32_FLASH_CR) & FLASH_CR_LOCK) + { + putreg32(FLASH_KEY1, STM32_FLASH_KEYR); + putreg32(FLASH_KEY2, STM32_FLASH_KEYR); + } + + DEBUGASSERT((getreg32(STM32_FLASH_CR) & FLASH_CR_LOCK) == 0); +} + +/**************************************************************************** + * Name: flash_lock_cr + * + * Description: + * Lock flash control register. + * + ****************************************************************************/ + +static void flash_lock_cr(void) +{ + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); +} + +/**************************************************************************** + * Name: flash_unlock_opt + * + * Description: + * Unlock flash option bytes register, if it is not already unlocked. + * + ****************************************************************************/ + +static bool flash_unlock_opt(void) +{ + bool was_locked = false; + flash_unlock_cr(); + + if (getreg32(STM32_FLASH_CR) & FLASH_CR_OPTLOCK) + { + was_locked = true; + + putreg32(FLASH_OPTKEY1, STM32_FLASH_OPTKEYR); + putreg32(FLASH_OPTKEY2, STM32_FLASH_OPTKEYR); + } + + DEBUGASSERT((getreg32(STM32_FLASH_CR) & FLASH_CR_OPTLOCK) == 0); + + return was_locked; +} + +/**************************************************************************** + * Name: flash_lock_opt + * + * Description: + * Lock flash option bytes register. + * + ****************************************************************************/ + +static void flash_lock_opt(void) +{ + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_OPTLOCK); +} + +/**************************************************************************** + * Name: flash_verify_blocknum + * + * Description: + * Verify the provided block number is valid based on the flash + * configuration. This is done because the reference implementation and + * reference manual refer to non-contiguous block (page) numbers for the + * flash layout on dual-bank devices. + * + * Returned Value: + * Zero or negated errno value. + * + * -EFAULT: Block number provided falls outside of the ranges specified in + * reference manual. + ****************************************************************************/ + +static int flash_verify_blocknum(size_t block) +{ +#ifdef FLASH_DUAL_BANK +#if defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_C) + if ((block < 0 || block > 63) && (block < 256 || block > 319)) + { + return -EFAULT; + } +#elif defined(CONFIG_STM32F0L0G0_FLASH_CONFIG_E) + if ((block < 0 || block > 127) && (block < 256 || block > 383)) + { + return -EFAULT; + } +#else +# error "Dual bank flash config not supported by flash driver" +#endif +#else + if (block > FLASH_NBLOCKS) + { + return -EFAULT; + } +#endif + + return 0; +} + +/**************************************************************************** + * Name: flash_block_address + * + * Description: + * Find the start address for the given block number. + * + * Returned Value: + * Memory address corresponding to given block number. + * + * Assumptions: + * This function assumes the block number has already been verified. Take + * care to make sure the block number is valid for the specific chip using + * flash_verify_blocknum() first. + ****************************************************************************/ + +static uint32_t flash_block_address(size_t block) +{ + uint32_t addr; +#ifdef FLASH_DUAL_BANK + if (block >= flash_bank2_priv.stblock) + { + addr = flash_bank2_priv.base + + (block - flash_bank2_priv.stblock) * FLASH_BLOCK_SIZE; + } + else + { + addr = flash_bank1_priv.base + block * FLASH_BLOCK_SIZE; + } +#else + addr = flash_bank1_priv.base + block * FLASH_BLOCK_SIZE; +#endif + return addr; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_flash_unlock + * + * Description: + * Unlock flash control register (FLASH_CR) + * + ****************************************************************************/ + +void stm32_flash_unlock(void) +{ + nxmutex_lock(&g_lock); + flash_unlock_cr(); + nxmutex_unlock(&g_lock); +} + +/**************************************************************************** + * Name: stm32_flash_lock + * + * Description: + * Lock flash control register (FLASH_CR) + * + ****************************************************************************/ + +void stm32_flash_lock(void) +{ + nxmutex_lock(&g_lock); + flash_lock_cr(); + nxmutex_unlock(&g_lock); +} + +/**************************************************************************** + * Name: stm32_flash_getopt + * + * Description: + * Read the current flash option bytes from FLASH_OPTR + * + * Input Parameters: + * opt - location to store read of FLASH_OPTR + * + ****************************************************************************/ + +void stm32_flash_getopt(uint32_t *opt) +{ + *opt = getreg32(STM32_FLASH_OPTR); +} + +/**************************************************************************** + * Name: stm32_flash_optmodify + * + * Description: + * Modifies the current flash option bytes, given bits to set and clear. + * + * Input Parameters: + * clear - clear bits for FLASH_OPTR + * set - set bits for FLASH_OPTR + * + * Returned Value: + * Zero or error value + * + * -EBUSY: Timeout waiting for previous FLASH operation to occur, or + * there was data in the flash data buffer. + * + * Notes: + * This function WILL BLOCK and NOT release the thread. This is a sensitive + * operation with the potential to brick the device if interrupted. So, for + * the actual opt modify start, this function uses a tight while loop to + * wait for completion. + * + ****************************************************************************/ + +int stm32_flash_optmodify(uint32_t clear, uint32_t set) +{ + int ret; + bool was_locked; + + ret = flash_wait_for_operation(); + if (ret != 0) + { + return -EBUSY; + } + + was_locked = flash_unlock_opt(); + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_CLEAR_ERROR_FLAGS); + + modifyreg32(STM32_FLASH_OPTR, clear, set); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY1) + { + } + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_OPTSTRT); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY1) + { + } + + if (was_locked) + { + flash_lock_opt(); + } + + return 0; +} + +#ifdef CONFIG_ARCH_HAVE_PROGMEM + +/* up_progmem_x functions defined in nuttx/include/nuttx/progmem.h + * + * Notes on Implementation: + * - The driver implementations DO NOT enforce memory address boundaries. + * For processors with less than 2MB flash, the user is responsible for + * not writing to memory between banks. + * + */ + +size_t up_progmem_pagesize(size_t page) +{ + return FLASH_PAGE_SIZE; +} + +ssize_t up_progmem_getpage(size_t addr) +{ + struct stm32_flash_priv_s *priv; + + priv = flash_bank(addr); + + if (priv == NULL) + { + return -EFAULT; + } + + return priv->stpage + ((addr - priv->base) / FLASH_PAGE_SIZE); +} + +size_t up_progmem_getaddress(size_t page) +{ + struct stm32_flash_priv_s *priv; + + if (page >= FLASH_NPAGES) + { + return SIZE_MAX; + } + + priv = flash_bank(STM32_FLASH_BASE + (page * FLASH_PAGE_SIZE)); + + if (!priv) + { + return SIZE_MAX; + } + + return priv->base + (page - priv->stpage) * FLASH_PAGE_SIZE; +} + +size_t up_progmem_neraseblocks(void) +{ + return FLASH_NBLOCKS; +} + +bool up_progmem_isuniform(void) +{ + /* So... Every other implementation of this in STM chips returns this as + * true. However, the description in include/nuttx/progmem.h states this to + * mean "does size of erase 'page' == size of read/write 'page'". Which is + * NOT true for most of these chips. + * + * On the G0, erase blocks are 2K and read/write page is 64 bit. + */ + + return false; +} + +ssize_t up_progmem_ispageerased(size_t page) +{ + size_t addr; + size_t count; + size_t bwritten = 0; + + if (page >= 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; +} + +size_t up_progmem_erasesize(size_t block) +{ + return FLASH_BLOCK_SIZE; +} + +ssize_t up_progmem_eraseblock(size_t block) +{ + int ret; + size_t block_address; + + ret = flash_verify_blocknum(block); + if (ret < 0) + { + return -EFAULT; + } + + block_address = flash_block_address(block); + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return (ssize_t)ret; + } + + if (flash_wait_for_operation()) + { + ret = -EIO; + goto exit_with_lock; + } + + /* Get flash ready and begin erasing single block */ + + flash_unlock_cr(); + + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_CLEAR_ERROR_FLAGS); + + /* By now, know that the block number is valid and corresponds to a + * bank (if dual bank). So, don't need to verify that it is in bounds. + */ + +#ifdef FLASH_DUAL_BANK + + /* Note to future developers: The CR register definition in the reference + * manual [RM0444] is not clear on if bank selection is necessary. The PNB + * definition seems to imply that writing block numbers corresponding to + * bank 2 should just work. This is NOT the case. Writing 256 to PNB will + * cause block (page) 0 to be erased. Therefore, must switch BKER bit to + * match the correct bank. + */ + + if (block >= flash_bank2_priv.stblock) + { + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_BKER); + } + else + { + modifyreg32(STM32_FLASH_CR, FLASH_CR_BKER, 0); + } +#endif + + /* Setup erase parameters and start */ + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PNB_MASK, + FLASH_CR_PER | (block << FLASH_CR_PNB_SHIFT)); + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_STRT); + + /* Wait for erase operation to complete */ + + if (flash_wait_for_operation()) + { + ret = -EIO; + goto exit_with_unlock; + } + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PNB_MASK | FLASH_CR_PER, 0); + + ret = 0; + up_invalidate_dcache(block_address, block_address + FLASH_BLOCK_SIZE); + +exit_with_unlock: + flash_lock_cr(); + +exit_with_lock: + nxmutex_unlock(&g_lock); + + if (ret == 0 && + flash_israngeerased(block_address, up_progmem_erasesize(block)) == 0) + { + ret = up_progmem_erasesize(block); /* Success */ + } + else + { + ret = -EIO; + } + + return ret; +} + +ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) +{ + struct stm32_flash_priv_s *priv; + uint32_t *fp; + uint32_t *rp; + uint32_t *ll = (uint32_t *)buf; + size_t faddr; + size_t written = count; + int ret; + const size_t pagesize = up_progmem_pagesize(0); /* 64-bit, 8 bytes per page */ + const size_t llperpage = pagesize / sizeof(uint32_t); + size_t pcount = count / pagesize; + + priv = flash_bank(addr); + + if (priv == NULL) + { + return -EFAULT; + } + + /* Check for valid address range */ + + if (addr < priv->base || + addr + count > priv->base + (FLASH_BANKSIZE)) + { + return -EFAULT; + } + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return (ssize_t)ret; + } + + /* Check address and count alignment */ + + DEBUGASSERT(!(addr % pagesize)); + DEBUGASSERT(!(count % pagesize)); + + if (flash_wait_for_operation()) + { + written = -EIO; + goto exit_with_lock; + } + + /* Get flash ready for write */ + + flash_unlock_cr(); + + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_CLEAR_ERROR_FLAGS); + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); + + /* Write */ + + for (ll = (uint32_t *)buf, faddr = addr; pcount; + pcount -= 1, ll += llperpage, faddr += pagesize) + { + fp = (uint32_t *)faddr; + rp = ll; + + UP_MB(); + + /* Write 2 32 bit word and wait to complete */ + + *fp++ = *rp++; + *fp++ = *rp++; + + /* Data synchronous Barrier (DSB) just after the write operation. This + * will force the CPU to respect the sequence of instruction (no + * optimization). + */ + + UP_MB(); + + if (flash_wait_for_operation()) + { + written = -EIO; + goto exit_with_unlock; + } + + /* Future improvements may add ECC checking here. */ + } + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + +exit_with_unlock: + flash_lock_cr(); + + if (written > 0) + { + for (ll = (uint32_t *)buf, faddr = addr, pcount = count / pagesize; + pcount; pcount -= 1, ll += llperpage, faddr += pagesize) + { + fp = (uint32_t *)faddr; + rp = ll; + + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_CLEAR_ERROR_FLAGS); + + if ((*fp++ != *rp++) || + (*fp++ != *rp++)) + { + written = -EIO; + break; + } + + /* Future improvements may add ECC checking here. */ + } + + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_CLEAR_ERROR_FLAGS); + } + +exit_with_lock: + nxmutex_unlock(&g_lock); + return written; +} + +uint8_t up_progmem_erasestate(void) +{ + return FLASH_ERASEDVALUE; +} + +#endif /* CONFIG_ARCH_HAVE_PROGMEM*/ \ No newline at end of file