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 <tbennett@2g-eng.com>
This commit is contained in:
Tyler Bennett 2025-05-06 18:13:04 -05:00 committed by Alan C. Assis
parent 11d444403e
commit 9fca766bd4
7 changed files with 1391 additions and 39 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 <nuttx/config.h>
#if defined(CONFIG_STM32F0L0G0_STM32G0)
# include "stm32g0_flash.c"
#else
# error "Flash driver unsupported on selected chip."
#endif
/****************************************************************************
* Private Functions
****************************************************************************/

View file

@ -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 <nuttx/config.h>
#include <stdint.h>
#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 */

View file

@ -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 <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/mutex.h>
#include <nuttx/signal.h>
#include <arch/barriers.h>
#include <arm_internal.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#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*/