summaryrefslogtreecommitdiff
path: root/src/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c4769
1 files changed, 0 insertions, 4769 deletions
diff --git a/src/common.c b/src/common.c
deleted file mode 100644
index 4541aa3..0000000
--- a/src/common.c
+++ /dev/null
@@ -1,4769 +0,0 @@
-#define DEBUG_FLASH 0
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <helper.h>
-#include <logging.h>
-#include <md5.h>
-#include <stlink.h>
-
-#ifdef STLINK_HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#else
-#include <mmap.h>
-#endif
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-#ifdef _MSC_VER
-#define __attribute__(x)
-#endif
-
-#define BANK_1 0
-#define BANK_2 1
-
-/* stm32f FPEC flash controller interface, pm0063 manual */
-// TODO - all of this needs to be abstracted out....
-// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2,
-// August 2012)
-#define FLASH_REGS_ADDR 0x40022000
-#define FLASH_REGS_SIZE 0x28
-
-#define FLASH_ACR (FLASH_REGS_ADDR + 0x00)
-#define FLASH_KEYR (FLASH_REGS_ADDR + 0x04)
-#define FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x08)
-#define FLASH_SR (FLASH_REGS_ADDR + 0x0c)
-#define FLASH_CR (FLASH_REGS_ADDR + 0x10)
-#define FLASH_AR (FLASH_REGS_ADDR + 0x14)
-#define FLASH_OBR (FLASH_REGS_ADDR + 0x1c)
-#define FLASH_WRPR (FLASH_REGS_ADDR + 0x20)
-
-// STM32F10x_XL has two flash memory banks with separate registers to control
-// the second bank.
-#define FLASH_KEYR2 (FLASH_REGS_ADDR + 0x44)
-#define FLASH_SR2 (FLASH_REGS_ADDR + 0x4c)
-#define FLASH_CR2 (FLASH_REGS_ADDR + 0x50)
-#define FLASH_AR2 (FLASH_REGS_ADDR + 0x54)
-
-// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
-#define FLASH_RDPTR_KEY 0x00a5
-#define FLASH_KEY1 0x45670123
-#define FLASH_KEY2 0xcdef89ab
-
-#define FLASH_L0_PRGKEY1 0x8c9daebf
-#define FLASH_L0_PRGKEY2 0x13141516
-
-#define FLASH_L0_PEKEY1 0x89abcdef
-#define FLASH_L0_PEKEY2 0x02030405
-
-#define FLASH_OPTKEY1 0x08192A3B
-#define FLASH_OPTKEY2 0x4C5D6E7F
-
-#define FLASH_F0_OPTKEY1 0x45670123
-#define FLASH_F0_OPTKEY2 0xCDEF89AB
-
-#define FLASH_L0_OPTKEY1 0xFBEAD9C8
-#define FLASH_L0_OPTKEY2 0x24252627
-
-#define FLASH_SR_BSY 0
-#define FLASH_SR_PG_ERR 2
-#define FLASH_SR_WRPRT_ERR 4
-#define FLASH_SR_EOP 5
-
-#define FLASH_SR_ERROR_MASK ((1 << FLASH_SR_PG_ERR) | (1 << FLASH_SR_WRPRT_ERR))
-
-#define FLASH_CR_PG 0
-#define FLASH_CR_PER 1
-#define FLASH_CR_MER 2
-#define FLASH_CR_OPTPG 4
-#define FLASH_CR_STRT 6
-#define FLASH_CR_LOCK 7
-#define FLASH_CR_OPTWRE 9
-
-#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
-#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
-#define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
-#define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
-#define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
-#define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
-#define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
-#define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
-#define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
-#define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
-#define FLASH_L1_FPRG 10
-#define FLASH_L1_PROG 3
-
-// Flash registers common to STM32G0 and STM32G4 series.
-#define STM32Gx_FLASH_REGS_ADDR ((uint32_t)0x40022000)
-#define STM32Gx_FLASH_ACR (STM32Gx_FLASH_REGS_ADDR + 0x00)
-#define STM32Gx_FLASH_KEYR (STM32Gx_FLASH_REGS_ADDR + 0x08)
-#define STM32Gx_FLASH_OPTKEYR (STM32Gx_FLASH_REGS_ADDR + 0x0c)
-#define STM32Gx_FLASH_SR (STM32Gx_FLASH_REGS_ADDR + 0x10)
-#define STM32Gx_FLASH_CR (STM32Gx_FLASH_REGS_ADDR + 0x14)
-#define STM32Gx_FLASH_ECCR (STM32Gx_FLASH_REGS_ADDR + 0x18)
-#define STM32Gx_FLASH_OPTR (STM32Gx_FLASH_REGS_ADDR + 0x20)
-
-// G0 (RM0444 Table 1, sec 3.7)
-// Mostly the same as G4 chips, but the notation
-// varies a bit after the 'OPTR' register.
-#define STM32G0_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR)
-#define STM32G0_FLASH_PCROP1ASR (STM32G0_FLASH_REGS_ADDR + 0x24)
-#define STM32G0_FLASH_PCROP1AER (STM32G0_FLASH_REGS_ADDR + 0x28)
-#define STM32G0_FLASH_WRP1AR (STM32G0_FLASH_REGS_ADDR + 0x2C)
-#define STM32G0_FLASH_WRP1BR (STM32G0_FLASH_REGS_ADDR + 0x30)
-#define STM32G0_FLASH_PCROP1BSR (STM32G0_FLASH_REGS_ADDR + 0x34)
-#define STM32G0_FLASH_PCROP1BER (STM32G0_FLASH_REGS_ADDR + 0x38)
-#define STM32G0_FLASH_SECR (STM32G0_FLASH_REGS_ADDR + 0x80)
-
-// G4 (RM0440 Table 17, sec 3.7.19)
-// Mostly the same as STM32G0 chips, but there are a few extra
-// registers because 'cat 3' devices can have two Flash banks.
-#define STM32G4_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR)
-#define STM32G4_FLASH_PDKEYR (STM32G4_FLASH_REGS_ADDR + 0x04)
-#define STM32G4_FLASH_PCROP1SR (STM32G4_FLASH_REGS_ADDR + 0x24)
-#define STM32G4_FLASH_PCROP1ER (STM32G4_FLASH_REGS_ADDR + 0x28)
-#define STM32G4_FLASH_WRP1AR (STM32G4_FLASH_REGS_ADDR + 0x2C)
-#define STM32G4_FLASH_WRP1BR (STM32G4_FLASH_REGS_ADDR + 0x30)
-#define STM32G4_FLASH_PCROP2SR (STM32G4_FLASH_REGS_ADDR + 0x44)
-#define STM32G4_FLASH_PCROP2ER (STM32G4_FLASH_REGS_ADDR + 0x48)
-#define STM32G4_FLASH_WRP2AR (STM32G4_FLASH_REGS_ADDR + 0x4C)
-#define STM32G4_FLASH_WRP2BR (STM32G4_FLASH_REGS_ADDR + 0x50)
-#define STM32G4_FLASH_SEC1R (STM32G4_FLASH_REGS_ADDR + 0x70)
-#define STM32G4_FLASH_SEC2R (STM32G4_FLASH_REGS_ADDR + 0x74)
-
-// G0/G4 FLASH control register
-#define STM32Gx_FLASH_CR_PG (0) /* Program */
-#define STM32Gx_FLASH_CR_PER (1) /* Page erase */
-#define STM32Gx_FLASH_CR_MER1 (2) /* Mass erase */
-#define STM32Gx_FLASH_CR_PNB (3) /* Page number */
-#define STM32G0_FLASH_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */
-#define STM32G4_FLASH_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */
-#define STM32Gx_FLASH_CR_MER2 (15) /* Mass erase (2nd bank)*/
-#define STM32Gx_FLASH_CR_STRT (16) /* Start */
-#define STM32Gx_FLASH_CR_OPTSTRT \
- (17) /* Start of modification of option bytes */
-#define STM32Gx_FLASH_CR_FSTPG (18) /* Fast programming */
-#define STM32Gx_FLASH_CR_EOPIE (24) /* End of operation interrupt enable */
-#define STM32Gx_FLASH_CR_ERRIE (25) /* Error interrupt enable */
-#define STM32Gx_FLASH_CR_OBL_LAUNCH (27) /* Forces the option byte loading */
-#define STM32Gx_FLASH_CR_OPTLOCK (30) /* Options Lock */
-#define STM32Gx_FLASH_CR_LOCK (31) /* FLASH_CR Lock */
-
-// G0/G4 FLASH status register
-#define STM32Gx_FLASH_SR_ERROR_MASK (0x3fa)
-#define STM32Gx_FLASH_SR_PROGERR (3)
-#define STM32Gx_FLASH_SR_WRPERR (4)
-#define STM32Gx_FLASH_SR_PGAERR (5)
-#define STM32Gx_FLASH_SR_BSY (16) /* FLASH_SR Busy */
-#define STM32Gx_FLASH_SR_EOP (0) /* FLASH_EOP End of Operation */
-
-// G4 FLASH option register
-#define STM32G4_FLASH_OPTR_DBANK (22) /* FLASH_OPTR Dual Bank Mode */
-
-// WB (RM0434)
-#define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000)
-#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00)
-#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08)
-#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C)
-#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10)
-#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14)
-#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18)
-#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20)
-#define STM32WB_FLASH_PCROP1ASR (STM32WB_FLASH_REGS_ADDR + 0x24)
-#define STM32WB_FLASH_PCROP1AER (STM32WB_FLASH_REGS_ADDR + 0x28)
-#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C)
-#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30)
-#define STM32WB_FLASH_PCROP1BSR (STM32WB_FLASH_REGS_ADDR + 0x34)
-#define STM32WB_FLASH_PCROP1BER (STM32WB_FLASH_REGS_ADDR + 0x38)
-#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C)
-#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C)
-#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60)
-#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64)
-#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80)
-#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84)
-
-// WB Flash control register.
-#define STM32WB_FLASH_CR_STRT (16) /* Start */
-#define STM32WB_FLASH_CR_OPTLOCK (30) /* Option Lock */
-#define STM32WB_FLASH_CR_LOCK (31) /* Lock */
-// WB Flash status register.
-#define STM32WB_FLASH_SR_ERROR_MASK (0x3f8) /* SR [9:3] */
-#define STM32WB_FLASH_SR_PROGERR (3) /* Programming alignment error */
-#define STM32WB_FLASH_SR_WRPERR (4) /* Write protection error */
-#define STM32WB_FLASH_SR_PGAERR (5) /* Programming error */
-#define STM32WB_FLASH_SR_BSY (16) /* Busy */
-
-// 32L4 register base is at FLASH_REGS_ADDR (0x40022000)
-#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
-#define STM32L4_FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x0C)
-#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
-#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
-#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
-
-#define STM32L4_FLASH_SR_ERROR_MASK 0x3f8 /* SR [9:3] */
-#define STM32L4_FLASH_SR_PROGERR 3
-#define STM32L4_FLASH_SR_WRPERR 4
-#define STM32L4_FLASH_SR_PGAERR 5
-#define STM32L4_FLASH_SR_BSY 16
-
-#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
-#define STM32L4_FLASH_CR_OPTLOCK 30 /* Lock option bytes */
-#define STM32L4_FLASH_CR_PG 0 /* Program */
-#define STM32L4_FLASH_CR_PER 1 /* Page erase */
-#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
-#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
-#define STM32L4_FLASH_CR_STRT 16 /* Start command */
-#define STM32L4_FLASH_CR_OPTSTRT 17 /* Start writing option bytes */
-#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
-#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
-#define STM32L4_FLASH_CR_OBL_LAUNCH 27 /* Option bytes reload */
-// Bits requesting flash operations (useful when we want to clear them)
-#define STM32L4_FLASH_CR_OPBITS \
- (uint32_t)((1lu << STM32L4_FLASH_CR_PG) | (1lu << STM32L4_FLASH_CR_PER) | \
- (1lu << STM32L4_FLASH_CR_MER1) | (1lu << STM32L4_FLASH_CR_MER1))
-// Page is fully specified by BKER and PNB
-#define STM32L4_FLASH_CR_PAGEMASK (uint32_t)(0x1fflu << STM32L4_FLASH_CR_PNB)
-
-#define STM32L4_FLASH_OPTR_DUALBANK 21
-
-// STM32L0x flash register base and offsets RM0090 - DM00031020.pdf
-#define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000)
-#define STM32L1_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
-
-#define STM32L0_FLASH_PELOCK (0)
-#define STM32L0_FLASH_OPTLOCK (2)
-#define STM32L0_FLASH_OBL_LAUNCH (18)
-
-#define STM32L0_FLASH_SR_ERROR_MASK 0x00013F00
-#define STM32L0_FLASH_SR_WRPERR 8
-#define STM32L0_FLASH_SR_PGAERR 9
-#define STM32L0_FLASH_SR_NOTZEROERR 16
-
-#define FLASH_ACR_OFF ((uint32_t)0x00)
-#define FLASH_PECR_OFF ((uint32_t)0x04)
-#define FLASH_PDKEYR_OFF ((uint32_t)0x08)
-#define FLASH_PEKEYR_OFF ((uint32_t)0x0c)
-#define FLASH_PRGKEYR_OFF ((uint32_t)0x10)
-#define FLASH_OPTKEYR_OFF ((uint32_t)0x14)
-#define FLASH_SR_OFF ((uint32_t)0x18)
-#define FLASH_OBR_OFF ((uint32_t)0x1c)
-#define FLASH_WRPR_OFF ((uint32_t)0x20)
-
-// STM32F7
-#define FLASH_F7_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F7_KEYR (FLASH_F7_REGS_ADDR + 0x04)
-#define FLASH_F7_OPT_KEYR (FLASH_F7_REGS_ADDR + 0x08)
-#define FLASH_F7_SR (FLASH_F7_REGS_ADDR + 0x0c)
-#define FLASH_F7_CR (FLASH_F7_REGS_ADDR + 0x10)
-#define FLASH_F7_OPTCR (FLASH_F7_REGS_ADDR + 0x14)
-#define FLASH_F7_OPTCR1 (FLASH_F7_REGS_ADDR + 0x18)
-#define FLASH_F7_OPTCR_LOCK 0
-#define FLASH_F7_OPTCR_START 1
-#define FLASH_F7_CR_STRT 16
-#define FLASH_F7_CR_LOCK 31
-#define FLASH_F7_CR_SER 1
-#define FLASH_F7_CR_SNB 3
-#define FLASH_F7_CR_SNB_MASK 0xf8
-#define FLASH_F7_SR_BSY 16
-#define FLASH_F7_SR_ERS_ERR 7 /* Erase Sequence Error */
-#define FLASH_F7_SR_PGP_ERR 6 /* Programming parallelism error */
-#define FLASH_F7_SR_PGA_ERR 5 /* Programming alignment error */
-#define FLASH_F7_SR_WRP_ERR 4 /* Write protection error */
-#define FLASH_F7_SR_OP_ERR 1 /* Operation error */
-#define FLASH_F7_SR_EOP 0 /* End of operation */
-#define FLASH_F7_OPTCR1_BOOT_ADD0 0
-#define FLASH_F7_OPTCR1_BOOT_ADD1 16
-
-#define FLASH_F7_SR_ERROR_MASK \
- ((1 << FLASH_F7_SR_ERS_ERR) | (1 << FLASH_F7_SR_PGP_ERR) | \
- (1 << FLASH_F7_SR_PGA_ERR) | (1 << FLASH_F7_SR_WRP_ERR) | \
- (1 << FLASH_F7_SR_OP_ERR))
-
-// STM32F4
-#define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04)
-#define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08)
-#define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c)
-#define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10)
-#define FLASH_F4_OPTCR (FLASH_F4_REGS_ADDR + 0x14)
-#define FLASH_F4_OPTCR_LOCK 0
-#define FLASH_F4_OPTCR_START 1
-#define FLASH_F4_CR_STRT 16
-#define FLASH_F4_CR_LOCK 31
-#define FLASH_F4_CR_SER 1
-#define FLASH_F4_CR_SNB 3
-#define FLASH_F4_CR_SNB_MASK 0xf8
-#define FLASH_F4_SR_ERROR_MASK 0x000000F0
-#define FLASH_F4_SR_PGAERR 5
-#define FLASH_F4_SR_WRPERR 4
-#define FLASH_F4_SR_BSY 16
-
-// STM32F2
-#define FLASH_F2_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F2_KEYR (FLASH_F2_REGS_ADDR + 0x04)
-#define FLASH_F2_OPT_KEYR (FLASH_F2_REGS_ADDR + 0x08)
-#define FLASH_F2_SR (FLASH_F2_REGS_ADDR + 0x0c)
-#define FLASH_F2_CR (FLASH_F2_REGS_ADDR + 0x10)
-#define FLASH_F2_OPT_CR (FLASH_F2_REGS_ADDR + 0x14)
-#define FLASH_F2_OPT_LOCK_BIT (1u << 0)
-#define FLASH_F2_CR_STRT 16
-#define FLASH_F2_CR_LOCK 31
-
-#define FLASH_F2_CR_SER 1
-#define FLASH_F2_CR_SNB 3
-#define FLASH_F2_CR_SNB_MASK 0x78
-#define FLASH_F2_SR_BSY 16
-
-// STM32H7xx
-#define FLASH_H7_CR_LOCK 0
-#define FLASH_H7_CR_PG 1
-#define FLASH_H7_CR_SER 2
-#define FLASH_H7_CR_BER 3
-#define FLASH_H7_CR_PSIZE 4
-#define FLASH_H7_CR_START(chipid) (chipid == STLINK_CHIPID_STM32_H7AX ? 5 : 7)
-#define FLASH_H7_CR_SNB 8
-#define FLASH_H7_CR_SNB_MASK 0x700
-
-#define FLASH_H7_SR_QW 2
-#define FLASH_H7_SR_WRPERR 17
-#define FLASH_H7_SR_PGSERR 18
-#define FLASH_H7_SR_STRBERR 19
-#define FLASH_H7_SR_ERROR_MASK \
- ((1 << FLASH_H7_SR_PGSERR) | (1 << FLASH_H7_SR_STRBERR) | \
- (1 << FLASH_H7_SR_WRPERR))
-
-#define FLASH_H7_OPTCR_OPTLOCK 0
-#define FLASH_H7_OPTCR_OPTSTART 1
-#define FLASH_H7_OPTCR_MER 4
-
-#define FLASH_H7_OPTSR_OPT_BUSY 0
-#define FLASH_H7_OPTSR_OPTCHANGEERR 30
-
-#define FLASH_H7_OPTCCR_CLR_OPTCHANGEERR 30
-
-#define FLASH_H7_REGS_ADDR ((uint32_t)0x52002000)
-#define FLASH_H7_KEYR1 (FLASH_H7_REGS_ADDR + 0x04)
-#define FLASH_H7_KEYR2 (FLASH_H7_REGS_ADDR + 0x104)
-#define FLASH_H7_OPT_KEYR (FLASH_H7_REGS_ADDR + 0x08)
-#define FLASH_H7_OPT_KEYR2 (FLASH_H7_REGS_ADDR + 0x108)
-#define FLASH_H7_CR1 (FLASH_H7_REGS_ADDR + 0x0c)
-#define FLASH_H7_CR2 (FLASH_H7_REGS_ADDR + 0x10c)
-#define FLASH_H7_SR1 (FLASH_H7_REGS_ADDR + 0x10)
-#define FLASH_H7_SR2 (FLASH_H7_REGS_ADDR + 0x110)
-#define FLASH_H7_CCR1 (FLASH_H7_REGS_ADDR + 0x14)
-#define FLASH_H7_CCR2 (FLASH_H7_REGS_ADDR + 0x114)
-#define FLASH_H7_OPTCR (FLASH_H7_REGS_ADDR + 0x18)
-#define FLASH_H7_OPTCR2 (FLASH_H7_REGS_ADDR + 0x118)
-#define FLASH_H7_OPTSR_CUR (FLASH_H7_REGS_ADDR + 0x1c)
-#define FLASH_H7_OPTCCR (FLASH_H7_REGS_ADDR + 0x24)
-
-#define STM32F0_DBGMCU_CR 0xE0042004
-#define STM32F0_DBGMCU_CR_IWDG_STOP 8
-#define STM32F0_DBGMCU_CR_WWDG_STOP 9
-
-#define STM32F4_DBGMCU_APB1FZR1 0xE0042008
-#define STM32F4_DBGMCU_APB1FZR1_WWDG_STOP 11
-#define STM32F4_DBGMCU_APB1FZR1_IWDG_STOP 12
-
-#define STM32L0_DBGMCU_APB1_FZ 0x40015808
-#define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11
-#define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12
-
-#define STM32H7_DBGMCU_APB1HFZ 0x5C001054
-#define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18
-
-#define STM32WB_DBGMCU_APB1FZR1 0xE004203C
-#define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11
-#define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12
-
-#define STM32F1_RCC_AHBENR 0x40021014
-#define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32F4_RCC_AHB1ENR 0x40023830
-#define STM32F4_RCC_DMAEN 0x00600000 // DMA2EN | DMA1EN
-
-#define STM32G0_RCC_AHBENR 0x40021038
-#define STM32G0_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32G4_RCC_AHB1ENR 0x40021048
-#define STM32G4_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32L0_RCC_AHBENR 0x40021030
-#define STM32L0_RCC_DMAEN 0x00000001 // DMAEN
-
-#define STM32H7_RCC_AHB1ENR 0x58024538
-#define STM32H7_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32WB_RCC_AHB1ENR 0x58000048
-#define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define L1_WRITE_BLOCK_SIZE 0x80
-#define L0_WRITE_BLOCK_SIZE 0x40
-
-// Endianness
-// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-// These functions encode and decode little endian uint16 and uint32 values.
-
-void write_uint32(unsigned char *buf, uint32_t ui) {
- buf[0] = ui;
- buf[1] = ui >> 8;
- buf[2] = ui >> 16;
- buf[3] = ui >> 24;
-}
-
-void write_uint16(unsigned char *buf, uint16_t ui) {
- buf[0] = ui;
- buf[1] = ui >> 8;
-}
-
-uint32_t read_uint32(const unsigned char *c, const int pt) {
- return ((uint32_t)c[pt]) | ((uint32_t)c[pt + 1] << 8) |
- ((uint32_t)c[pt + 2] << 16) | ((uint32_t)c[pt + 3] << 24);
-}
-
-uint16_t read_uint16(const unsigned char *c, const int pt) {
- return ((uint16_t)c[pt]) | ((uint16_t)c[pt + 1] << 8);
-}
-
-static uint32_t get_stm32l0_flash_base(stlink_t *sl) {
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_L0:
- case STLINK_CHIPID_STM32_L0_CAT5:
- case STLINK_CHIPID_STM32_L0_CAT2:
- case STLINK_CHIPID_STM32_L011:
- return (STM32L0_FLASH_REGS_ADDR);
-
- case STLINK_CHIPID_STM32_L1_CAT2:
- case STLINK_CHIPID_STM32_L1_MEDIUM:
- case STLINK_CHIPID_STM32_L1_MEDIUM_PLUS:
- case STLINK_CHIPID_STM32_L1_HIGH:
- return (STM32L1_FLASH_REGS_ADDR);
-
- default:
- WLOG("Flash base use default L0 address");
- return (STM32L0_FLASH_REGS_ADDR);
- }
-}
-
-static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) {
- uint32_t rdp;
- stlink_read_debug32(sl, FLASH_WRPR, &rdp);
- return (rdp & 0xff);
-}
-
-static inline uint32_t read_flash_cr(stlink_t *sl, unsigned bank) {
- uint32_t reg, res;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- reg = FLASH_F4_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- reg = FLASH_F7_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- reg = STM32L4_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- reg = STM32WB_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- } else {
- reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- stlink_read_debug32(sl, reg, &res);
-
-#if DEBUG_FLASH
- fprintf(stdout, "CR:0x%x\n", res);
-#endif
- return (res);
-}
-
-static inline unsigned int is_flash_locked(stlink_t *sl) {
- /* return non zero for true */
- uint32_t cr_lock_shift;
- uint32_t cr_reg;
- uint32_t n;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- cr_reg = FLASH_CR;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_lock_shift = FLASH_F4_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_lock_shift = FLASH_F7_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- cr_lock_shift = STM32L0_FLASH_PELOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_lock_shift = STM32Gx_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_lock_shift = STM32WB_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = FLASH_H7_CR1;
- cr_lock_shift = FLASH_H7_CR_LOCK;
- } else {
- ELOG("unsupported flash method, abort\n");
- return (-1);
- }
-
- stlink_read_debug32(sl, cr_reg, &n);
- return (n & (1u << cr_lock_shift));
-}
-
-static void unlock_flash(stlink_t *sl) {
- uint32_t key_reg, key2_reg = 0;
- uint32_t flash_key1 = FLASH_KEY1;
- uint32_t flash_key2 = FLASH_KEY2;
- /* The unlock sequence consists of 2 write cycles where 2 key values are
- * written to the FLASH_KEYR register. An invalid sequence results in a
- * definitive lock of the FPEC block until next reset.
- */
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F0) {
- key_reg = FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- key_reg = FLASH_KEYR;
- key2_reg = FLASH_KEYR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- key_reg = FLASH_F4_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- key_reg = FLASH_F7_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF;
- flash_key1 = FLASH_L0_PEKEY1;
- flash_key2 = FLASH_L0_PEKEY2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- key_reg = STM32L4_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- key_reg = STM32Gx_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- key_reg = STM32WB_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- key_reg = FLASH_H7_KEYR1;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- key2_reg = FLASH_H7_KEYR2;
- }
- } else {
- ELOG("unsupported flash method, abort\n");
- return;
- }
-
- stlink_write_debug32(sl, key_reg, flash_key1);
- stlink_write_debug32(sl, key_reg, flash_key2);
-
- if (key2_reg) {
- stlink_write_debug32(sl, key2_reg, flash_key1);
- stlink_write_debug32(sl, key2_reg, flash_key2);
- }
-}
-
-/* unlock flash if already locked */
-static int unlock_flash_if(stlink_t *sl) {
- if (is_flash_locked(sl)) {
- unlock_flash(sl);
-
- if (is_flash_locked(sl)) {
- WLOG("Failed to unlock flash!\n");
- return (-1);
- }
- }
-
- DLOG("Successfully unlocked flash\n");
- return (0);
-}
-
-static void lock_flash(stlink_t *sl) {
- uint32_t cr_lock_shift, cr_reg, n, cr2_reg = 0;
- uint32_t cr_mask = 0xffffffffu;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F0) {
- cr_reg = FLASH_CR;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- cr_reg = FLASH_CR;
- cr2_reg = FLASH_CR2;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_lock_shift = FLASH_F4_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_lock_shift = FLASH_F7_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- cr_lock_shift = STM32L0_FLASH_PELOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_lock_shift = STM32Gx_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_lock_shift = STM32WB_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = FLASH_H7_CR1;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- cr2_reg = FLASH_H7_CR2;
- }
- cr_lock_shift = FLASH_H7_CR_LOCK;
- cr_mask = ~(1u << FLASH_H7_CR_SER);
- } else {
- ELOG("unsupported flash method, abort\n");
- return;
- }
-
- stlink_read_debug32(sl, cr_reg, &n);
- n &= cr_mask;
- n |= (1u << cr_lock_shift);
- stlink_write_debug32(sl, cr_reg, n);
-
- if (cr2_reg) {
- n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift);
- stlink_write_debug32(sl, cr2_reg, n);
- }
-}
-
-static bool is_flash_option_locked(stlink_t *sl) {
- uint32_t optlock_shift, optcr_reg;
- int active_bit_level = 1;
- uint32_t n;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optcr_reg = FLASH_CR;
- optlock_shift = FLASH_CR_OPTWRE;
- active_bit_level = 0; /* bit is "option write enable", not lock */
- break;
- case STLINK_FLASH_TYPE_F4:
- optcr_reg = FLASH_F4_OPTCR;
- optlock_shift = FLASH_F4_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_F7:
- optcr_reg = FLASH_F7_OPTCR;
- optlock_shift = FLASH_F7_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_L0:
- optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- optlock_shift = STM32L0_FLASH_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_L4:
- optcr_reg = STM32L4_FLASH_CR;
- optlock_shift = STM32L4_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optcr_reg = STM32Gx_FLASH_CR;
- optlock_shift = STM32Gx_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_WB:
- optcr_reg = STM32WB_FLASH_CR;
- optlock_shift = STM32WB_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_H7:
- optcr_reg = FLASH_H7_OPTCR;
- optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return -1;
- }
-
- stlink_read_debug32(sl, optcr_reg, &n);
-
- if (active_bit_level == 0) {
- return (!(n & (1u << optlock_shift)));
- }
-
- return (n & (1u << optlock_shift));
-}
-
-static int lock_flash_option(stlink_t *sl) {
- uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0;
- int active_bit_level = 1;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optcr_reg = FLASH_CR;
- optlock_shift = FLASH_CR_OPTWRE;
- active_bit_level = 0;
- break;
- case STLINK_FLASH_TYPE_F4:
- optcr_reg = FLASH_F4_OPTCR;
- optlock_shift = FLASH_F4_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_F7:
- optcr_reg = FLASH_F7_OPTCR;
- optlock_shift = FLASH_F7_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_L0:
- optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- optlock_shift = STM32L0_FLASH_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_L4:
- optcr_reg = STM32L4_FLASH_CR;
- optlock_shift = STM32L4_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optcr_reg = STM32Gx_FLASH_CR;
- optlock_shift = STM32Gx_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_WB:
- optcr_reg = STM32WB_FLASH_CR;
- optlock_shift = STM32WB_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_H7:
- optcr_reg = FLASH_H7_OPTCR;
- optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
- optcr2_reg = FLASH_H7_OPTCR2;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return -1;
- }
-
- stlink_read_debug32(sl, optcr_reg, &n);
-
- if (active_bit_level == 0) {
- n &= ~(1u << optlock_shift);
- } else {
- n |= (1u << optlock_shift);
- }
-
- stlink_write_debug32(sl, optcr_reg, n);
-
- if (optcr2_reg) {
- stlink_read_debug32(sl, optcr2_reg, &n);
-
- if (active_bit_level == 0) {
- n &= ~(1u << optlock_shift);
- } else {
- n |= (1u << optlock_shift);
- }
-
- stlink_write_debug32(sl, optcr2_reg, n);
- }
-
- return (0);
-}
-
-static int unlock_flash_option(stlink_t *sl) {
- uint32_t optkey_reg, optkey2_reg = 0;
- uint32_t optkey1 = FLASH_OPTKEY1;
- uint32_t optkey2 = FLASH_OPTKEY2;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optkey_reg = FLASH_OPTKEYR;
- optkey1 = FLASH_F0_OPTKEY1;
- optkey2 = FLASH_F0_OPTKEY2;
- break;
- case STLINK_FLASH_TYPE_F4:
- optkey_reg = FLASH_F4_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_F7:
- optkey_reg = FLASH_F7_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_L0:
- optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF;
- optkey1 = FLASH_L0_OPTKEY1;
- optkey2 = FLASH_L0_OPTKEY2;
- break;
- case STLINK_FLASH_TYPE_L4:
- optkey_reg = STM32L4_FLASH_OPTKEYR;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optkey_reg = STM32Gx_FLASH_OPTKEYR;
- break;
- case STLINK_FLASH_TYPE_WB:
- optkey_reg = STM32WB_FLASH_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_H7:
- optkey_reg = FLASH_H7_OPT_KEYR;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
- optkey2_reg = FLASH_H7_OPT_KEYR2;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return (-1);
- }
-
- stlink_write_debug32(sl, optkey_reg, optkey1);
- stlink_write_debug32(sl, optkey_reg, optkey2);
-
- if (optkey2_reg) {
- stlink_write_debug32(sl, optkey2_reg, optkey1);
- stlink_write_debug32(sl, optkey2_reg, optkey2);
- }
-
- return (0);
-}
-
-static int unlock_flash_option_if(stlink_t *sl) {
- if (is_flash_option_locked(sl)) {
- if (unlock_flash_option(sl)) {
- ELOG("Could not unlock flash option!\n");
- return (-1);
- }
-
- if (is_flash_option_locked(sl)) {
- ELOG("Failed to unlock flash option!\n");
- return (-1);
- }
- }
-
- DLOG("Successfully unlocked flash option\n");
- return (0);
-}
-
-static void set_flash_cr_pg(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, x;
-
- x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- x |= 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- x |= 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- x &= ~STM32L4_FLASH_CR_OPBITS;
- x |= (1 << STM32L4_FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- x |= (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- x |= (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- x |= (1 << FLASH_H7_CR_PG);
- } else {
- cr_reg = FLASH_CR;
- x = (1 << FLASH_CR_PG);
- }
-
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static void clear_flash_cr_pg(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, n;
- uint32_t bit = FLASH_CR_PG;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- bit = FLASH_H7_CR_PG;
- } else {
- cr_reg = FLASH_CR;
- }
-
- n = read_flash_cr(sl, bank) & ~(1 << bit);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-static void set_flash_cr_per(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, val;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void clear_flash_cr_per(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-static void set_flash_cr_mer(stlink_t *sl, bool v, unsigned bank) {
- uint32_t val, cr_reg, cr_mer, cr_pg;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_mer = 1 << FLASH_CR_MER;
- cr_pg = 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_mer = 1 << FLASH_CR_MER;
- cr_pg = 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
- cr_pg = (1 << STM32L4_FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_mer = (1 << STM32Gx_FLASH_CR_MER1);
-
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- cr_mer |= (1 << STM32Gx_FLASH_CR_MER2);
- }
-
- cr_pg = (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_mer = (1 << FLASH_CR_MER);
- cr_pg = (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- cr_mer = (1 << FLASH_H7_CR_BER);
- cr_pg = (1 << FLASH_H7_CR_PG);
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- cr_mer = (1 << FLASH_CR_MER);
- cr_pg = (1 << FLASH_CR_PG);
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
-
- if (val & cr_pg) {
- // STM32F030 will drop MER bit if PG was set
- val &= ~cr_pg;
- stlink_write_debug32(sl, cr_reg, val);
- }
-
- if (v) {
- val |= cr_mer;
- } else {
- val &= ~cr_mer;
- }
-
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void set_flash_cr_strt(stlink_t *sl, unsigned bank) {
- uint32_t val, cr_reg, cr_strt;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_strt = 1 << FLASH_F4_CR_STRT;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_strt = 1 << FLASH_F7_CR_STRT;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_strt = (1 << STM32L4_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_strt = (1 << STM32Gx_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_strt = (1 << STM32WB_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id);
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- cr_strt = (1 << FLASH_CR_STRT);
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= cr_strt;
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static inline uint32_t read_flash_sr(stlink_t *sl, unsigned bank) {
- uint32_t res, sr_reg;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_reg = FLASH_F4_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_reg = FLASH_F7_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_reg = STM32L4_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_reg = STM32Gx_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_reg = STM32WB_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
- } else {
- ELOG("method 'read_flash_sr' is unsupported\n");
- return (-1);
- }
-
- stlink_read_debug32(sl, sr_reg, &res);
- return (res);
-}
-
-static inline int write_flash_sr(stlink_t *sl, unsigned bank, uint32_t val) {
- uint32_t sr_reg;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_reg = FLASH_F4_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_reg = FLASH_F7_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_reg = STM32L4_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_reg = STM32Gx_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_reg = STM32WB_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
- } else {
- ELOG("method 'write_flash_sr' is unsupported\n");
- return (-1);
- }
-
- return stlink_write_debug32(sl, sr_reg, val);
-}
-
-static inline unsigned int is_flash_busy(stlink_t *sl) {
- uint32_t sr_busy_shift;
- unsigned int res;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L0)) {
- sr_busy_shift = FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_busy_shift = FLASH_F4_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_busy_shift = FLASH_F7_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_busy_shift = STM32L4_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_busy_shift = STM32Gx_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_busy_shift = STM32WB_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_busy_shift = FLASH_H7_SR_QW;
- } else {
- ELOG("method 'is_flash_busy' is unsupported\n");
- return (-1);
- }
-
- res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift);
- }
-
- return (res);
-}
-
-static void wait_flash_busy(stlink_t *sl) {
- // TODO: add some delays here
- while (is_flash_busy(sl))
- ;
-}
-
-static void wait_flash_busy_progress(stlink_t *sl) {
- int i = 0;
- fprintf(stdout, "Mass erasing");
- fflush(stdout);
-
- while (is_flash_busy(sl)) {
- usleep(10000);
- i++;
-
- if (i % 100 == 0) {
- fprintf(stdout, ".");
- fflush(stdout);
- }
- }
-
- fprintf(stdout, "\n");
-}
-
-static void clear_flash_error(stlink_t *sl) {
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_F4:
- write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_F7:
- write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- write_flash_sr(sl, BANK_1, STM32Gx_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_L0:
- write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_L4:
- write_flash_sr(sl, BANK_1, STM32L4_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_H7:
- write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK);
- }
- break;
- case STLINK_FLASH_TYPE_WB:
- write_flash_sr(sl, BANK_1, STM32WB_FLASH_SR_ERROR_MASK);
- break;
- default:
- break;
- }
-}
-
-static int check_flash_error(stlink_t *sl) {
- uint32_t res = 0;
- uint32_t WRPERR, PROGERR, PGAERR;
-
- WRPERR = PROGERR = PGAERR = 0;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK;
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK;
- }
- WRPERR = (1 << FLASH_SR_WRPRT_ERR);
- PROGERR = (1 << FLASH_SR_PG_ERR);
- break;
- case STLINK_FLASH_TYPE_F4:
- res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK;
- WRPERR = (1 << FLASH_F4_SR_WRPERR);
- PGAERR = (1 << FLASH_F4_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_F7:
- res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK;
- WRPERR = (1 << FLASH_F7_SR_WRP_ERR);
- PROGERR = (1 << FLASH_F7_SR_PGP_ERR);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- res = read_flash_sr(sl, BANK_1) & STM32Gx_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32Gx_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32Gx_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32Gx_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_L0:
- res = read_flash_sr(sl, BANK_1) & STM32L0_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32L0_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32L0_FLASH_SR_NOTZEROERR);
- PGAERR = (1 << STM32L0_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_L4:
- res = read_flash_sr(sl, BANK_1) & STM32L4_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32L4_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32L4_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32L4_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_H7:
- res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK;
- }
- WRPERR = (1 << FLASH_H7_SR_WRPERR);
- break;
- case STLINK_FLASH_TYPE_WB:
- res = read_flash_sr(sl, BANK_1) & STM32WB_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32WB_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32WB_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32WB_FLASH_SR_PGAERR);
- break;
- default:
- break;
- }
-
- if (res) {
- if (WRPERR && (WRPERR & res) == WRPERR) {
- ELOG("Flash memory is write protected\n");
- res &= ~WRPERR;
- } else if (PROGERR && (PROGERR & res) == PROGERR) {
- ELOG("Flash memory contains a non-erased value\n");
- res &= ~PROGERR;
- } else if (PGAERR && (PGAERR & res) == PGAERR) {
- ELOG("Invalid flash address\n");
- res &= ~PGAERR;
- }
-
- if (res) {
- ELOG("Flash programming error: %#010x\n", res);
- }
- return (-1);
- }
-
- return (0);
-}
-
-static void stop_wdg_in_debug(stlink_t *sl) {
- uint32_t dbgmcu_cr;
- uint32_t set;
- uint32_t value;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- case STLINK_FLASH_TYPE_G4:
- dbgmcu_cr = STM32F0_DBGMCU_CR;
- set =
- (1 << STM32F0_DBGMCU_CR_IWDG_STOP) | (1 << STM32F0_DBGMCU_CR_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_F4:
- case STLINK_FLASH_TYPE_F7:
- case STLINK_FLASH_TYPE_L4:
- dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1;
- set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) |
- (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_L0:
- case STLINK_FLASH_TYPE_G0:
- dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ;
- set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) |
- (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_H7:
- dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ;
- set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_WB:
- dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1;
- set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) |
- (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP);
- break;
- default:
- return;
- }
-
- if (!stlink_read_debug32(sl, dbgmcu_cr, &value)) {
- stlink_write_debug32(sl, dbgmcu_cr, value | set);
- }
-}
-
-static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int bckpRstr) {
- uint32_t rcc, rcc_dma_mask, value;
-
- rcc = rcc_dma_mask = value = 0;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- rcc = STM32F1_RCC_AHBENR;
- rcc_dma_mask = STM32F1_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_F4:
- case STLINK_FLASH_TYPE_F7:
- rcc = STM32F4_RCC_AHB1ENR;
- rcc_dma_mask = STM32F4_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_G0:
- rcc = STM32G0_RCC_AHBENR;
- rcc_dma_mask = STM32G0_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_G4:
- case STLINK_FLASH_TYPE_L4:
- rcc = STM32G4_RCC_AHB1ENR;
- rcc_dma_mask = STM32G4_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_L0:
- rcc = STM32L0_RCC_AHBENR;
- rcc_dma_mask = STM32L0_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_H7:
- rcc = STM32H7_RCC_AHB1ENR;
- rcc_dma_mask = STM32H7_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_WB:
- rcc = STM32WB_RCC_AHB1ENR;
- rcc_dma_mask = STM32WB_RCC_DMAEN;
- break;
- default:
- return;
- }
-
- if (!stlink_read_debug32(sl, rcc, &value)) {
- if (bckpRstr) {
- value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp;
- } else {
- fl->rcc_dma_bkp = value & rcc_dma_mask;
- value &= ~rcc_dma_mask;
- }
- stlink_write_debug32(sl, rcc, value);
- }
-}
-
-static inline void write_flash_ar(stlink_t *sl, uint32_t n, unsigned bank) {
- stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n);
-}
-
-static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n,
- unsigned bank) {
- uint32_t cr_reg, psize_shift;
- uint32_t x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- psize_shift = FLASH_H7_CR_PSIZE;
- } else {
- cr_reg = FLASH_F4_CR;
- psize_shift = 8;
- }
-
- x &= ~(0x03 << psize_shift);
- x |= (n << psize_shift);
-#if DEBUG_FLASH
- fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, unsigned bank) {
- uint32_t cr_reg, snb_mask, snb_shift, ser_shift;
- uint32_t x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- snb_mask = FLASH_H7_CR_SNB_MASK;
- snb_shift = FLASH_H7_CR_SNB;
- ser_shift = FLASH_H7_CR_SER;
- } else {
- cr_reg = FLASH_F4_CR;
- snb_mask = FLASH_F4_CR_SNB_MASK;
- snb_shift = FLASH_F4_CR_SNB;
- ser_shift = FLASH_F4_CR_SER;
- }
-
- x &= ~snb_mask;
- x |= (n << snb_shift);
- x |= (1 << ser_shift);
-#if DEBUG_FLASH
- fprintf(stdout, "SNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
- stlink_write_debug32(sl, STM32L4_FLASH_SR,
- 0xFFFFFFFF & ~(1 << STM32L4_FLASH_SR_BSY));
- uint32_t x = read_flash_cr(sl, BANK_1);
- x &= ~STM32L4_FLASH_CR_OPBITS;
- x &= ~STM32L4_FLASH_CR_PAGEMASK;
- x &= ~(1 << STM32L4_FLASH_CR_MER1);
- x &= ~(1 << STM32L4_FLASH_CR_MER2);
- x |= (n << STM32L4_FLASH_CR_PNB);
- x |= (uint32_t)(1lu << STM32L4_FLASH_CR_PER);
-#if DEBUG_FLASH
- fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
-}
-
-// Delegates to the backends...
-
-void stlink_close(stlink_t *sl) {
- DLOG("*** stlink_close ***\n");
-
- if (!sl) {
- return;
- }
-
- sl->backend->close(sl);
- free(sl);
-}
-
-int stlink_exit_debug_mode(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_exit_debug_mode ***\n");
- ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY);
-
- if (ret == -1) {
- return (ret);
- }
-
- return (sl->backend->exit_debug_mode(sl));
-}
-
-int stlink_enter_swd_mode(stlink_t *sl) {
- DLOG("*** stlink_enter_swd_mode ***\n");
- return (sl->backend->enter_swd_mode(sl));
-}
-
-// Force the core into the debug mode -> halted state.
-int stlink_force_debug(stlink_t *sl) {
- DLOG("*** stlink_force_debug_mode ***\n");
- int res = sl->backend->force_debug(sl);
- // Stop the watchdogs in the halted state for suppress target reboot
- stop_wdg_in_debug(sl);
- return (res);
-}
-
-int stlink_exit_dfu_mode(stlink_t *sl) {
- DLOG("*** stlink_exit_dfu_mode ***\n");
- return (sl->backend->exit_dfu_mode(sl));
-}
-
-int stlink_core_id(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_core_id ***\n");
- ret = sl->backend->core_id(sl);
-
- if (ret == -1) {
- ELOG("Failed to read core_id\n");
- return (ret);
- }
-
- if (sl->verbose > 2) {
- stlink_print_data(sl);
- }
-
- DLOG("core_id = 0x%08x\n", sl->core_id);
- return (ret);
-}
-
-// stlink_chip_id() is called by stlink_load_device_params()
-// do not call this procedure directly.
-int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
- int ret;
- cortex_m3_cpuid_t cpu_id;
-
- // Read the CPU ID to determine where to read the core id
- if (stlink_cpu_id(sl, &cpu_id) ||
- cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) {
- ELOG("Can not connect to target. Please use \'connect under reset\' and "
- "try again\n");
- return -1;
- }
-
- /*
- * the chip_id register in the reference manual have
- * DBGMCU_IDCODE / DBG_IDCODE name
- *
- */
-
- if ((sl->core_id == STM32H7_CORE_ID || sl->core_id == STM32H7_CORE_ID_JTAG) &&
- cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) {
- // STM32H7 chipid in 0x5c001000 (RM0433 pg3189)
- ret = stlink_read_debug32(sl, 0x5c001000, chip_id);
- } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 ||
- cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) {
- // STM32F0 (RM0091, pg914; RM0360, pg713)
- // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917)
- // STM32G0 (RM0444, pg1367)
- ret = stlink_read_debug32(sl, 0x40015800, chip_id);
- } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) {
- // STM32L5 (RM0438, pg2157)
- ret = stlink_read_debug32(sl, 0xE0044000, chip_id);
- } else /* СM3, СM4, CM7 */ {
- // default chipid address
-
- // STM32F1 (RM0008, pg1087; RM0041, pg681)
- // STM32F2 (RM0033, pg1326)
- // STM32F3 (RM0316, pg1095; RM0313, pg874)
- // STM32F7 (RM0385, pg1676; RM0410, pg1912)
- // STM32L1 (RM0038, pg861)
- // STM32L4 (RM0351, pg1840; RM0394, pg1560)
- // STM32G4 (RM0440, pg2086)
- // STM32WB (RM0434, pg1406)
- ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
- }
-
- if (ret || !(*chip_id)) {
- *chip_id = 0;
- ELOG("Could not find chip id!\n");
- } else {
- *chip_id = (*chip_id) & 0xfff;
-
- // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for
- // F2/F4
- if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) {
- *chip_id = 0x413;
- }
- }
-
- return (ret);
-}
-
-/**
- * Cortex M tech ref manual, CPUID register description
- * @param sl stlink context
- * @param cpuid pointer to the result object
- */
-int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) {
- uint32_t raw;
-
- if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) {
- cpuid->implementer_id = 0;
- cpuid->variant = 0;
- cpuid->part = 0;
- cpuid->revision = 0;
- return (-1);
- }
-
- cpuid->implementer_id = (raw >> 24) & 0x7f;
- cpuid->variant = (raw >> 20) & 0xf;
- cpuid->part = (raw >> 4) & 0xfff;
- cpuid->revision = raw & 0xf;
- return (0);
-}
-
-/**
- * Reads and decodes the flash parameters, as dynamically as possible
- * @param sl
- * @return 0 for success, or -1 for unsupported core type.
- */
-int stlink_load_device_params(stlink_t *sl) {
- // This seems to normally work so is unnecessary info for a normal user.
- // Demoted to debug. -- REW
- DLOG("Loading device parameters....\n");
- const struct stlink_chipid_params *params = NULL;
- stlink_core_id(sl);
- uint32_t flash_size;
-
- if (stlink_chip_id(sl, &sl->chip_id)) {
- return (-1);
- }
-
- params = stlink_chipid_get_params(sl->chip_id);
-
- if (params == NULL) {
- WLOG("unknown chip id! %#x\n", sl->chip_id);
- return (-1);
- }
-
- if (params->flash_type == STLINK_FLASH_TYPE_UNKNOWN) {
- WLOG("Invalid flash type, please check device declaration\n");
- sl->flash_size = 0;
- return (0);
- }
-
- // These are fixed...
- sl->flash_base = STM32_FLASH_BASE;
- sl->sram_base = STM32_SRAM_BASE;
- stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size);
-
- if (params->flash_size_reg & 2) {
- flash_size = flash_size >> 16;
- }
-
- flash_size = flash_size & 0xffff;
-
- if ((sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW ||
- sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS) &&
- (flash_size == 0)) {
- sl->flash_size = 128 * 1024;
- } else if (sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2) {
- sl->flash_size = (flash_size & 0xff) * 1024;
- } else if ((sl->chip_id & 0xFFF) == STLINK_CHIPID_STM32_L1_HIGH) {
- // 0 is 384k and 1 is 256k
- if (flash_size == 0) {
- sl->flash_size = 384 * 1024;
- } else {
- sl->flash_size = 256 * 1024;
- }
- } else {
- sl->flash_size = flash_size * 1024;
- }
-
- sl->flash_type = params->flash_type;
- sl->flash_pgsz = params->flash_pagesize;
- sl->sram_size = params->sram_size;
- sl->sys_base = params->bootrom_base;
- sl->sys_size = params->bootrom_size;
- sl->option_base = params->option_base;
- sl->option_size = params->option_size;
- sl->chip_flags = params->flags;
-
- // medium and low devices have the same chipid. ram size depends on flash
- // size. STM32F100xx datasheet Doc ID 16455 Table 2
- if (sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW &&
- sl->flash_size < 64 * 1024) {
- sl->sram_size = 0x1000;
- }
-
- if (sl->chip_id == STLINK_CHIPID_STM32_G4_CAT3) {
- uint32_t flash_optr;
- stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, &flash_optr);
-
- if (!(flash_optr & (1 << STM32G4_FLASH_OPTR_DBANK))) {
- sl->flash_pgsz <<= 1;
- }
- }
-
- // H7 devices with small flash has one bank
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK &&
- sl->flash_type == STLINK_FLASH_TYPE_H7) {
- if ((flash_size / sl->flash_pgsz) <= 1)
- sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK;
- }
-
- ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n",
- params->description, (unsigned)(sl->sram_size / 1024),
- (unsigned)(sl->flash_size / 1024),
- (sl->flash_pgsz < 1024) ? (unsigned)(sl->flash_pgsz)
- : (unsigned)(sl->flash_pgsz / 1024),
- (sl->flash_pgsz < 1024) ? "byte" : "KiB");
-
- return (0);
-}
-
-int stlink_jtag_reset(stlink_t *sl, int value) {
- DLOG("*** stlink_jtag_reset ***\n");
- return (sl->backend->jtag_reset(sl, value));
-}
-
-int stlink_soft_reset(stlink_t *sl, int halt_on_reset) {
- int ret;
- unsigned timeout;
- uint32_t dhcsr, dfsr;
-
- DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : "");
-
- // halt core and enable debugging (if not already done)
- // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6)
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT |
- STLINK_REG_DHCSR_C_DEBUGEN);
-
- // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10)
- if (halt_on_reset) {
- stlink_write_debug32(
- sl, STLINK_REG_CM3_DEMCR,
- STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR |
- STLINK_REG_CM3_DEMCR_VC_BUSERR | STLINK_REG_CM3_DEMCR_VC_CORERESET);
-
- // clear VCATCH in the DFSR register
- stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH);
- } else {
- stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR,
- STLINK_REG_CM3_DEMCR_TRCENA |
- STLINK_REG_CM3_DEMCR_VC_HARDERR |
- STLINK_REG_CM3_DEMCR_VC_BUSERR);
- }
-
- // clear S_RESET_ST in the DHCSR register
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
-
- // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23)
- ret = stlink_write_debug32(sl, STLINK_REG_AIRCR,
- STLINK_REG_AIRCR_VECTKEY |
- STLINK_REG_AIRCR_SYSRESETREQ);
- if (ret) {
- ELOG("Soft reset failed: error write to AIRCR\n");
- return (ret);
- }
-
- // waiting for a reset within 500ms
- // DDI0337E, p. 10-4, Debug Halting Control and Status Register
- timeout = time_ms() + 500;
- while (time_ms() < timeout) {
- // DDI0337E, p. 10-4, Debug Halting Control and Status Register
- dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- if (halt_on_reset) {
- // waiting halt by the SYSRESETREQ exception
- // DDI0403E, p. C1-699, Debug Fault Status Register
- dfsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr);
- if ((dfsr & STLINK_REG_DFSR_VCATCH) == 0) {
- continue;
- }
- }
- timeout = 0;
- break;
- }
- }
-
- // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5)
- stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR);
-
- if (timeout) {
- ELOG("Soft reset failed: timeout\n");
- return (-1);
- }
-
- return (0);
-}
-
-int stlink_reset(stlink_t *sl, enum reset_type type) {
- uint32_t dhcsr;
- unsigned timeout;
-
- DLOG("*** stlink_reset ***\n");
-
- if (type == RESET_AUTO) {
- // clear S_RESET_ST in DHCSR register for reset state detection
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- }
-
- if (type == RESET_HARD || type == RESET_AUTO) {
- // hardware target reset
- if (sl->version.stlink_v > 1) {
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW);
- // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
- usleep(100);
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH);
- }
- if (sl->backend->reset(sl)) {
- return (-1);
- }
- usleep(10000);
- }
-
- if (type == RESET_AUTO) {
- /* Check if the S_RESET_ST bit is set in DHCSR
- * This means that a reset has occurred
- * DDI0337E, p. 10-4, Debug Halting Control and Status Register */
-
- dhcsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- // reset not done yet
- // try reset through AIRCR so that NRST does not need to be connected
-
- WLOG("NRST is not connected\n");
- DLOG("Using reset through SYSRESETREQ\n");
- return stlink_soft_reset(sl, 0);
- }
-
- // waiting for reset the S_RESET_ST bit within 500ms
- timeout = time_ms() + 500;
- while (time_ms() < timeout) {
- dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0)
- return (0);
- }
-
- return (-1);
- }
-
- if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) {
- return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT));
- }
-
- return (0);
-}
-
-int stlink_run(stlink_t *sl, enum run_type type) {
- struct stlink_reg rr;
- DLOG("*** stlink_run ***\n");
-
- /* Make sure we are in Thumb mode
- * Cortex-M chips don't support ARM mode instructions
- * xPSR may be incorrect if the vector table has invalid data */
- stlink_read_reg(sl, 16, &rr);
- if ((rr.xpsr & (1 << 24)) == 0) {
- ILOG("Go to Thumb mode\n");
- stlink_write_reg(sl, rr.xpsr | (1 << 24), 16);
- }
-
- return (sl->backend->run(sl, type));
-}
-
-int stlink_set_swdclk(stlink_t *sl, int freq_khz) {
- DLOG("*** set_swdclk ***\n");
- return (sl->backend->set_swdclk(sl, freq_khz));
-}
-
-int stlink_status(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_status ***\n");
- ret = sl->backend->status(sl);
- stlink_core_stat(sl);
- return (ret);
-}
-
-/**
- * Decode the version bits, originally from -sg, verified with usb
- * @param sl stlink context, assumed to contain valid data in the buffer
- * @param slv output parsed version object
- */
-void _parse_version(stlink_t *sl, stlink_version_t *slv) {
- sl->version.flags = 0;
-
- if (sl->version.stlink_v < 3) {
- uint32_t b0 = sl->q_buf[0]; // lsb
- uint32_t b1 = sl->q_buf[1];
- uint32_t b2 = sl->q_buf[2];
- uint32_t b3 = sl->q_buf[3];
- uint32_t b4 = sl->q_buf[4];
- uint32_t b5 = sl->q_buf[5]; // msb
-
- // b0 b1 || b2 b3 | b4 b5
- // 4b | 6b | 6b || 2B | 2B
- // stlink_v | jtag_v | swim_v || st_vid | stlink_pid
-
- slv->stlink_v = (b0 & 0xf0) >> 4;
- slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6);
- slv->swim_v = b1 & 0x3f;
- slv->st_vid = (b3 << 8) | b2;
- slv->stlink_pid = (b5 << 8) | b4;
-
- // ST-LINK/V1 from J11 switch to api-v2 (and support SWD)
- if (slv->stlink_v == 1) {
- slv->jtag_api =
- slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1;
- } else {
- slv->jtag_api = STLINK_JTAG_API_V2;
-
- // preferred API to get last R/W status from J15
- if (sl->version.jtag_v >= 15) {
- sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
- }
-
- if (sl->version.jtag_v >= 13) {
- sl->version.flags |= STLINK_F_HAS_TRACE;
- sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY;
- }
- }
- } else {
- // V3 uses different version format, for reference see OpenOCD source
- // (that was written from docs available from ST under NDA):
- // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965
- slv->stlink_v = sl->q_buf[0];
- slv->swim_v = sl->q_buf[1];
- slv->jtag_v = sl->q_buf[2];
- slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]);
- slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]);
- slv->jtag_api = STLINK_JTAG_API_V3;
- /* preferred API to get last R/W status */
- sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
- sl->version.flags |= STLINK_F_HAS_TRACE;
- sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY;
- }
-
- return;
-}
-
-int stlink_version(stlink_t *sl) {
- DLOG("*** looking up stlink version\n");
-
- if (sl->backend->version(sl)) {
- return (-1);
- }
-
- _parse_version(sl, &sl->version);
-
- DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid,
- STLINK_USB_VID_ST);
- DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid);
- DLOG("stlink version = 0x%x\n", sl->version.stlink_v);
- DLOG("jtag version = 0x%x\n", sl->version.jtag_v);
- DLOG("swim version = 0x%x\n", sl->version.swim_v);
-
- if (sl->version.jtag_v == 0) {
- DLOG(" notice: the firmware doesn't support a jtag/swd interface\n");
- }
-
- if (sl->version.swim_v == 0) {
- DLOG(" notice: the firmware doesn't support a swim interface\n");
- }
-
- return (0);
-}
-
-int stlink_target_voltage(stlink_t *sl) {
- int voltage = -1;
- DLOG("*** reading target voltage\n");
-
- if (sl->backend->target_voltage != NULL) {
- voltage = sl->backend->target_voltage(sl);
-
- if (voltage != -1) {
- DLOG("target voltage = %imV\n", voltage);
- } else {
- DLOG("error reading target voltage\n");
- }
- } else {
- DLOG("reading voltage not supported by backend\n");
- }
-
- return (voltage);
-}
-
-int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- int ret;
-
- ret = sl->backend->read_debug32(sl, addr, data);
- if (!ret)
- DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr);
-
- return (ret);
-}
-
-int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
- DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr);
- return sl->backend->write_debug32(sl, addr, data);
-}
-
-int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
-
- if (len % 4 != 0) {
- ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
- return (-1);
- }
-
- return (sl->backend->write_mem32(sl, addr, len));
-}
-
-int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_read_mem32 ***\n");
-
- if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
- ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
- return (-1);
- }
-
- return (sl->backend->read_mem32(sl, addr, len));
-}
-
-int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem8 ***\n");
-
- if (len > 0x40) { // !!! never ever: Writing more then 0x40 bytes gives
- // unexpected behaviour
- ELOG("Data length > 64: +%d byte.\n", len);
- return (-1);
- }
-
- return (sl->backend->write_mem8(sl, addr, len));
-}
-
-int stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
- DLOG("*** stlink_read_all_regs ***\n");
- return (sl->backend->read_all_regs(sl, regp));
-}
-
-int stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) {
- DLOG("*** stlink_read_all_unsupported_regs ***\n");
- return (sl->backend->read_all_unsupported_regs(sl, regp));
-}
-
-int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) {
- DLOG("*** stlink_write_reg\n");
- return (sl->backend->write_reg(sl, reg, idx));
-}
-
-int stlink_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
- DLOG("*** stlink_read_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- if (r_idx > 20 || r_idx < 0) {
- fprintf(stderr, "Error: register index must be in [0..20]\n");
- return (-1);
- }
-
- return (sl->backend->read_reg(sl, r_idx, regp));
-}
-
-int stlink_read_unsupported_reg(stlink_t *sl, int r_idx,
- struct stlink_reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_read_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by STLINK_REG_DCRSR */
- if (r_idx >= 0x1C &&
- r_idx <= 0x1F) { // primask, basepri, faultmask, or control
- r_convert = 0x14;
- } else if (r_idx == 0x40) { // FPSCR
- r_convert = 0x21;
- } else if (r_idx >= 0x20 && r_idx < 0x40) {
- r_convert = 0x40 + (r_idx - 0x20);
- } else {
- fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
- return (-1);
- }
-
- return (sl->backend->read_unsupported_reg(sl, r_convert, regp));
-}
-
-int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx,
- struct stlink_reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_write_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by STLINK_REG_DCRSR */
- if (r_idx >= 0x1C &&
- r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
- r_convert = r_idx; // the backend function handles this
- } else if (r_idx == 0x40) { // FPSCR
- r_convert = 0x21;
- } else if (r_idx >= 0x20 && r_idx < 0x40) {
- r_convert = 0x40 + (r_idx - 0x20);
- } else {
- fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
- return (-1);
- }
-
- return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp));
-}
-
-bool stlink_is_core_halted(stlink_t *sl) {
- stlink_status(sl);
- return (sl->core_stat == TARGET_HALTED);
-}
-
-int stlink_step(stlink_t *sl) {
- DLOG("*** stlink_step ***\n");
- return (sl->backend->step(sl));
-}
-
-int stlink_current_mode(stlink_t *sl) {
- int mode = sl->backend->current_mode(sl);
-
- switch (mode) {
- case STLINK_DEV_DFU_MODE:
- DLOG("stlink current mode: dfu\n");
- return (mode);
- case STLINK_DEV_DEBUG_MODE:
- DLOG("stlink current mode: debug (jtag or swd)\n");
- return (mode);
- case STLINK_DEV_MASS_MODE:
- DLOG("stlink current mode: mass\n");
- return (mode);
- }
-
- DLOG("stlink mode: unknown!\n");
- return (STLINK_DEV_UNKNOWN_MODE);
-}
-
-int stlink_trace_enable(stlink_t *sl, uint32_t frequency) {
- DLOG("*** stlink_trace_enable ***\n");
- return (sl->backend->trace_enable(sl, frequency));
-}
-
-int stlink_trace_disable(stlink_t *sl) {
- DLOG("*** stlink_trace_disable ***\n");
- return (sl->backend->trace_disable(sl));
-}
-
-int stlink_trace_read(stlink_t *sl, uint8_t *buf, size_t size) {
- return (sl->backend->trace_read(sl, buf, size));
-}
-
-// End of delegates.... Common code below here...
-
-// same as above with entrypoint.
-
-void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
- stlink_write_reg(sl, addr, 15); /* pc register */
- stlink_run(sl, RUN_NORMAL);
-
- while (stlink_is_core_halted(sl)) {
- usleep(3000000);
- }
-}
-
-// this function is called by stlink_status()
-// do not call stlink_core_stat() directly, always use stlink_status()
-void stlink_core_stat(stlink_t *sl) {
- switch (sl->core_stat) {
- case TARGET_RUNNING:
- DLOG(" core status: running\n");
- return;
- case TARGET_HALTED:
- DLOG(" core status: halted\n");
- return;
- case TARGET_RESET:
- DLOG(" core status: reset\n");
- return;
- case TARGET_DEBUG_RUNNING:
- DLOG(" core status: debug running\n");
- return;
- default:
- DLOG(" core status: unknown\n");
- }
-}
-
-void stlink_print_data(stlink_t *sl) {
- if (sl->q_len <= 0 || sl->verbose < UDEBUG) {
- return;
- }
-
- if (sl->verbose > 2) {
- DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len);
- }
-
- for (int i = 0; i < sl->q_len; i++) {
- if (i % 16 == 0) {
- /*
- if (sl->q_data_dir == Q_DATA_OUT) {
- fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
- } else {
- fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
- }
- */
- }
- // DLOG(" %02x", (unsigned int) sl->q_buf[i]);
- fprintf(stderr, " %02x", (unsigned int)sl->q_buf[i]);
- }
- // DLOG("\n\n");
- fprintf(stderr, "\n");
-}
-
-/* Memory mapped file */
-typedef struct mapped_file {
- uint8_t *base;
- size_t len;
-} mapped_file_t;
-
-#define MAPPED_FILE_INITIALIZER \
- { NULL, 0 }
-
-static int map_file(mapped_file_t *mf, const char *path) {
- int error = -1;
- struct stat st;
-
- const int fd = open(path, O_RDONLY | O_BINARY);
-
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return (-1);
- }
-
- if (fstat(fd, &st) == -1) {
- fprintf(stderr, "fstat(%s) == -1\n", path);
- goto on_error;
- }
-
- if (sizeof(st.st_size) != sizeof(size_t)) {
- // on 32 bit systems, check if there is an overflow
- if (st.st_size > (off_t)INT32_MAX) {
- fprintf(stderr, "mmap() size_t overflow for file %s\n", path);
- goto on_error;
- }
- }
-
- mf->base =
- (uint8_t *)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
-
- if (mf->base == MAP_FAILED) {
- fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path);
- goto on_error;
- }
-
- mf->len = st.st_size;
- error = 0; // success
-
-on_error:
- close(fd);
- return (error);
-}
-
-static void unmap_file(mapped_file_t *mf) {
- munmap((void *)mf->base, mf->len);
- mf->base = (unsigned char *)MAP_FAILED;
- mf->len = 0;
-}
-
-/* Limit the block size to compare to 0x1800 as anything larger will stall the
- * STLINK2 Maybe STLINK V1 needs smaller value!
- */
-static int check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) {
- size_t off;
- size_t n_cmp = sl->flash_pgsz;
-
- if (n_cmp > 0x1800) {
- n_cmp = 0x1800;
- }
-
- for (off = 0; off < mf->len; off += n_cmp) {
- size_t aligned_size;
-
- size_t cmp_size = n_cmp; // adjust last page size
-
- if ((off + n_cmp) > mf->len) {
- cmp_size = mf->len - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size);
-
- if (memcmp(sl->q_buf, mf->base + off, cmp_size)) {
- return (-1);
- }
- }
-
- return (0);
-}
-
-static void md5_calculate(mapped_file_t *mf) {
- // calculate md5 checksum of given binary file
- Md5Context md5Context;
- MD5_HASH md5Hash;
- Md5Initialise(&md5Context);
- Md5Update(&md5Context, mf->base, (uint32_t)mf->len);
- Md5Finalise(&md5Context, &md5Hash);
- printf("md5 checksum: ");
-
- for (int i = 0; i < (int)sizeof(md5Hash); i++) {
- printf("%x", md5Hash.bytes[i]);
- }
-
- printf(", ");
-}
-
-static void stlink_checksum(mapped_file_t *mp) {
- /* checksum that backward compatible with official ST tools */
- uint32_t sum = 0;
- uint8_t *mp_byte = (uint8_t *)mp->base;
-
- for (size_t i = 0; i < mp->len; ++i) {
- sum += mp_byte[i];
- }
-
- printf("stlink checksum: 0x%08x\n", sum);
-}
-
-static void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) {
- unsigned int val;
- // set stack
- stlink_read_debug32(sl, addr, &val);
- stlink_write_reg(sl, val, 13);
- // set PC to the reset routine
- stlink_read_debug32(sl, addr + 4, &val);
- stlink_write_reg(sl, val, 15);
- stlink_run(sl, RUN_NORMAL);
-}
-
-int stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length,
- stm32_addr_t addr) {
- // write the file in sram at addr
-
- int error = -1;
- size_t off;
- size_t len;
-
- // check addr range is inside the sram
- if (addr < sl->sram_base) {
- fprintf(stderr, "addr too low\n");
- goto on_error;
- } else if ((addr + length) < addr) {
- fprintf(stderr, "addr overruns\n");
- goto on_error;
- } else if ((addr + length) > (sl->sram_base + sl->sram_size)) {
- fprintf(stderr, "addr too high\n");
- goto on_error;
- } else if (addr & 3) {
- fprintf(stderr, "unaligned addr\n");
- goto on_error;
- }
-
- len = length;
-
- if (len & 3) {
- len -= len & 3;
- }
-
- // do the copy by 1kB blocks
- for (off = 0; off < len; off += 1024) {
- size_t size = 1024;
-
- if ((off + size) > len) {
- size = len - off;
- }
-
- memcpy(sl->q_buf, data + off, size);
-
- if (size & 3) {
- size += 2;
- } // round size if needed
-
- stlink_write_mem32(sl, addr + (uint32_t)off, size);
- }
-
- if (length > len) {
- memcpy(sl->q_buf, data + len, length - len);
- stlink_write_mem8(sl, addr + (uint32_t)len, length - len);
- }
-
- error = 0; // success
- stlink_fwrite_finalize(sl, addr);
-
-on_error:
- return (error);
-}
-
-int stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) {
- // write the file in sram at addr
-
- int error = -1;
- size_t off;
- size_t len;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- fprintf(stderr, "map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- // check if addr range is inside the SRAM
- if (addr < sl->sram_base) {
- fprintf(stderr, "addr too low\n");
- goto on_error;
- } else if ((addr + mf.len) < addr) {
- fprintf(stderr, "addr overruns\n");
- goto on_error;
- } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) {
- fprintf(stderr, "addr too high\n");
- goto on_error;
- } else if (addr & 3) {
- fprintf(stderr, "unaligned addr\n");
- goto on_error;
- }
-
- len = mf.len;
-
- if (len & 3) {
- len -= len & 3;
- }
-
- // do the copy by 1kB blocks
- for (off = 0; off < len; off += 1024) {
- size_t size = 1024;
-
- if ((off + size) > len) {
- size = len - off;
- }
-
- memcpy(sl->q_buf, mf.base + off, size);
-
- if (size & 3) {
- size += 2;
- } // round size if needed
-
- stlink_write_mem32(sl, addr + (uint32_t)off, size);
- }
-
- if (mf.len > len) {
- memcpy(sl->q_buf, mf.base + len, mf.len - len);
- stlink_write_mem8(sl, addr + (uint32_t)len, mf.len - len);
- }
-
- // check the file has been written
- if (check_file(sl, &mf, addr) == -1) {
- fprintf(stderr, "check_file() == -1\n");
- goto on_error;
- }
-
- error = 0; // success
- stlink_fwrite_finalize(sl, addr);
-
-on_error:
- unmap_file(&mf);
- return (error);
-}
-
-typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len);
-
-static int stlink_read(stlink_t *sl, stm32_addr_t addr, size_t size,
- save_block_fn fn, void *fn_arg) {
-
- int error = -1;
-
- if (size < 1) {
- size = sl->flash_size;
- }
-
- if (size > sl->flash_size) {
- size = sl->flash_size;
- }
-
- size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
-
- for (size_t off = 0; off < size; off += cmp_size) {
- size_t aligned_size;
-
- // adjust last page size
- if ((off + cmp_size) > size) {
- cmp_size = size - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size);
-
- if (!fn(fn_arg, sl->q_buf, aligned_size)) {
- goto on_error;
- }
- }
-
- error = 0; // success
-
-on_error:
- return (error);
-}
-
-struct stlink_fread_worker_arg {
- int fd;
-};
-
-static bool stlink_fread_worker(void *arg, uint8_t *block, ssize_t len) {
- struct stlink_fread_worker_arg *the_arg =
- (struct stlink_fread_worker_arg *)arg;
-
- if (write(the_arg->fd, block, len) != len) {
- fprintf(stderr, "write() != aligned_size\n");
- return (false);
- } else {
- return (true);
- }
-}
-
-struct stlink_fread_ihex_worker_arg {
- FILE *file;
- uint32_t addr;
- uint32_t lba;
- uint8_t buf[16];
- uint8_t buf_pos;
-};
-
-static bool
-stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg) {
- uint32_t addr = the_arg->addr;
- uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) +
- (uint8_t)((addr & 0x00FF0000) >> 16);
-
- if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n",
- (addr & 0xFFFF0000) >> 16, (uint8_t)(0x100 - sum))) {
- return (false);
- }
-
- the_arg->lba = (addr & 0xFFFF0000);
- return (true);
-}
-
-static bool
-stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg) {
- uint8_t count = the_arg->buf_pos;
-
- if (count == 0) {
- return (true);
- }
-
- uint32_t addr = the_arg->addr;
-
- if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed
- if (!stlink_fread_ihex_newsegment(the_arg)) {
- return (false);
- }
- }
-
- uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) +
- (uint8_t)(addr & 0x000000FF);
-
- if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) {
- return (false);
- }
-
- for (uint8_t i = 0; i < count; ++i) {
- uint8_t b = the_arg->buf[i];
- sum += b;
-
- if (2 != fprintf(the_arg->file, "%02X", b)) {
- return (false);
- }
- }
-
- if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) {
- return (false);
- }
-
- the_arg->addr += count;
- the_arg->buf_pos = 0;
-
- return (true);
-}
-
-static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg,
- int fd, stm32_addr_t addr) {
- the_arg->file = fdopen(fd, "w");
- the_arg->addr = addr;
- the_arg->lba = 0;
- the_arg->buf_pos = 0;
-
- return (the_arg->file != NULL);
-}
-
-static bool stlink_fread_ihex_worker(void *arg, uint8_t *block, ssize_t len) {
- struct stlink_fread_ihex_worker_arg *the_arg =
- (struct stlink_fread_ihex_worker_arg *)arg;
-
- for (ssize_t i = 0; i < len; ++i) {
- if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full
- if (!stlink_fread_ihex_writeline(the_arg)) {
- return (false);
- }
- }
-
- the_arg->buf[the_arg->buf_pos++] = block[i];
- }
-
- return (true);
-}
-
-static bool
-stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *the_arg) {
- if (!stlink_fread_ihex_writeline(the_arg)) {
- return (false);
- }
-
- // FIXME: do we need the Start Linear Address?
-
- if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF
- return (false);
- }
-
- return (0 == fclose(the_arg->file));
-}
-
-int stlink_fread(stlink_t *sl, const char *path, bool is_ihex,
- stm32_addr_t addr, size_t size) {
- // read size bytes from addr to file
- ILOG("read from address %#010x size %u\n", addr, (unsigned)size);
-
- int error;
- int fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700);
-
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return (-1);
- }
-
- if (is_ihex) {
- struct stlink_fread_ihex_worker_arg arg;
-
- if (stlink_fread_ihex_init(&arg, fd, addr)) {
- error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg);
-
- if (!stlink_fread_ihex_finalize(&arg)) {
- error = -1;
- }
- } else {
- error = -1;
- }
- } else {
- struct stlink_fread_worker_arg arg = {fd};
- error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg);
- }
-
- close(fd);
- return (error);
-}
-
-int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf,
- size_t size) {
- // write the buffer right after the loader
- size_t chunk = size & ~0x3;
- size_t rem = size & 0x3;
-
- if (chunk) {
- memcpy(sl->q_buf, buf, chunk);
- stlink_write_mem32(sl, fl->buf_addr, chunk);
- }
-
- if (rem) {
- memcpy(sl->q_buf, buf + chunk, rem);
- stlink_write_mem8(sl, (fl->buf_addr) + (uint32_t)chunk, rem);
- }
-
- return (0);
-}
-
-uint32_t calculate_F4_sectornum(uint32_t flashaddr) {
- uint32_t offset = 0;
- flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address
-
- if (flashaddr >= 0x100000) {
- offset = 12;
- flashaddr -= 0x100000;
- }
-
- if (flashaddr < 0x4000) {
- return (offset + 0);
- } else if (flashaddr < 0x8000) {
- return (offset + 1);
- } else if (flashaddr < 0xc000) {
- return (offset + 2);
- } else if (flashaddr < 0x10000) {
- return (offset + 3);
- } else if (flashaddr < 0x20000) {
- return (offset + 4);
- } else {
- return (offset + (flashaddr / 0x20000) + 4);
- }
-}
-
-uint32_t calculate_F7_sectornum(uint32_t flashaddr) {
- flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address
-
- if (flashaddr < 0x20000) {
- return (flashaddr / 0x8000);
- } else if (flashaddr < 0x40000) {
- return (4);
- } else {
- return ((flashaddr / 0x40000) + 4);
- }
-}
-
-uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr,
- unsigned bank) {
- flashaddr &=
- ~((bank == BANK_1)
- ? STM32_FLASH_BASE
- : STM32_H7_FLASH_BANK2_BASE); // sector holding the flash address
- return (flashaddr / sl->flash_pgsz);
-}
-
-// returns BKER:PNB for the given page address
-uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
- uint32_t bker = 0;
- uint32_t flashopt;
- stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt);
- flashaddr -= STM32_FLASH_BASE;
-
- if (sl->chip_id == STLINK_CHIPID_STM32_L4 ||
- sl->chip_id == STLINK_CHIPID_STM32_L496X ||
- sl->chip_id == STLINK_CHIPID_STM32_L4RX) {
- // this chip use dual banked flash
- if (flashopt & (uint32_t)(1lu << STM32L4_FLASH_OPTR_DUALBANK)) {
- uint32_t banksize = (uint32_t)sl->flash_size / 2;
-
- if (flashaddr >= banksize) {
- flashaddr -= banksize;
- bker = 0x100;
- }
- }
- }
-
- // For 1MB chips without the dual-bank option set, the page address will
- // overflow into the BKER bit, which gives us the correct bank:page value.
- return (bker | flashaddr / (uint32_t)sl->flash_pgsz);
-}
-
-uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) {
- if ((sl->chip_id == STLINK_CHIPID_STM32_F2) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_DE) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_LP) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_HD) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F411RE) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F446) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_DSI) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F72XXX) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F412)) {
- uint32_t sector = calculate_F4_sectornum(flashaddr);
-
- if (sector >= 12) {
- sector -= 12;
- }
-
- if (sector < 4) {
- sl->flash_pgsz = 0x4000;
- } else if (sector < 5) {
- sl->flash_pgsz = 0x10000;
- } else {
- sl->flash_pgsz = 0x20000;
- }
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 ||
- sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) {
- uint32_t sector = calculate_F7_sectornum(flashaddr);
-
- if (sector < 4) {
- sl->flash_pgsz = 0x8000;
- } else if (sector < 5) {
- sl->flash_pgsz = 0x20000;
- } else {
- sl->flash_pgsz = 0x40000;
- }
- }
-
- return ((uint32_t)sl->flash_pgsz);
-}
-
-/**
- * Erase a page of flash, assumes sl is fully populated with things like
- * chip/core ids
- * @param sl stlink context
- * @param flashaddr an address in the flash page to erase
- * @return 0 on success -ve on failure
- */
-int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) {
- // wait for ongoing op to finish
- wait_flash_busy(sl);
- // clear flash IO errors
- clear_flash_error(sl);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4 ||
- sl->flash_type == STLINK_FLASH_TYPE_F7 ||
- sl->flash_type == STLINK_FLASH_TYPE_L4) {
- // unlock if locked
- unlock_flash_if(sl);
-
- // select the page to erase
- if ((sl->chip_id == STLINK_CHIPID_STM32_L4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L43X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L46X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L496X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L4RX)) {
- // calculate the actual bank+page from the address
- uint32_t page = calculate_L4_page(sl, flashaddr);
-
- fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page,
- stlink_calculate_pagesize(sl, flashaddr));
-
- write_flash_cr_bker_pnb(sl, page);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 ||
- sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) {
- // calculate the actual page from the address
- uint32_t sector = calculate_F7_sectornum(flashaddr);
-
- fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
- stlink_calculate_pagesize(sl, flashaddr));
- write_flash_cr_snb(sl, sector, BANK_1);
- } else {
- // calculate the actual page from the address
- uint32_t sector = calculate_F4_sectornum(flashaddr);
-
- fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
- stlink_calculate_pagesize(sl, flashaddr));
-
- // the SNB values for flash sectors in the second bank do not directly
- // follow the values for the first bank on 2mb devices...
- if (sector >= 12) {
- sector += 4;
- }
-
- write_flash_cr_snb(sl, sector, BANK_1);
- }
-
- set_flash_cr_strt(sl, BANK_1); // start erase operation
- wait_flash_busy(sl); // wait for completion
- lock_flash(sl); // TODO: fails to program if this is in
-#if DEBUG_FLASH
- fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1));
-#endif
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
-
- uint32_t val;
- uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
-
- // check if the locks are set
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if ((val & (1 << 0)) || (val & (1 << 1))) {
- // disable pecr protection
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY2);
-
- // check pecr.pelock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if (val & (1 << 0)) {
- WLOG("pecr.pelock not clear (%#x)\n", val);
- return (-1);
- }
-
- // unlock program memory
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY2);
-
- // check pecr.prglock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if (val & (1 << 1)) {
- WLOG("pecr.prglock not clear (%#x)\n", val);
- return (-1);
- }
- }
-
- // set pecr.{erase,prog}
- val |= (1 << 9) | (1 << 3);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- // write 0 to the first word of the page to be erased
- stlink_write_debug32(sl, flashaddr, 0);
-
- /* MP: It is better to wait for clearing the busy bit after issuing page
- * erase command, even though PM0062 recommends to wait before it.
- * Test shows that a few iterations is performed in the following loop
- * before busy bit is cleared.
- */
- wait_flash_busy(sl);
-
- // reset lock bits
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << 0) | (1 << 1) | (1 << 2);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- uint32_t val;
- unlock_flash_if(sl);
- set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit
-
- // set the page to erase
- if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32WB_FLASH_CR, &val);
-
- // sec 3.10.5 - PNB[7:0] is offset by 3.
- val &= ~(0xFF << 3); // Clear previously set page number (if any)
- val |= ((flash_page & 0xFF) << 3);
-
- stlink_write_debug32(sl, STM32WB_FLASH_CR, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2.
- val &= ~(0x3F << 3);
- val |= ((flash_page & 0x3F) << 3) | (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G4) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- // sec 3.7.5 - PNB[6:0] is offset by 3. PER is 0x2.
- val &= ~(0x7F << 3);
- val |= ((flash_page & 0x7F) << 3) | (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
- }
-
- set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit
- wait_flash_busy(sl); // wait for the 'busy' bit to clear
- clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F0 ||
- sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- unsigned bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
- unlock_flash_if(sl);
- clear_flash_cr_pg(sl, bank); // clear the pg bit
- set_flash_cr_per(sl, bank); // set the page erase bit
- write_flash_ar(sl, flashaddr, bank); // select the page to erase
- set_flash_cr_strt(sl,
- bank); // start erase operation, reset by hw with busy bit
- wait_flash_busy(sl);
- clear_flash_cr_per(sl, bank); // clear the page erase bit
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- unsigned bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
- unlock_flash_if(sl); // unlock if locked
- uint32_t sector = calculate_H7_sectornum(
- sl, flashaddr, bank); // calculate the actual page from the address
- write_flash_cr_snb(sl, sector, bank); // select the page to erase
- set_flash_cr_strt(sl, bank); // start erase operation
- wait_flash_busy(sl); // wait for completion
- lock_flash(sl);
- } else {
- WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
- return (-1);
- }
-
- return check_flash_error(sl);
-}
-
-int stlink_erase_flash_mass(stlink_t *sl) {
- int err = 0;
-
- // TODO: User MER bit to mass-erase WB series.
- if (sl->flash_type == STLINK_FLASH_TYPE_L0 ||
- sl->flash_type == STLINK_FLASH_TYPE_WB) {
- // erase each page
- int i = 0, num_pages = (int)(sl->flash_size / sl->flash_pgsz);
-
- for (i = 0; i < num_pages; i++) {
- // addr must be an addr inside the page
- stm32_addr_t addr =
- (stm32_addr_t)sl->flash_base + i * (stm32_addr_t)sl->flash_pgsz;
-
- if (stlink_erase_flash_page(sl, addr)) {
- WLOG("Failed to erase_flash_page(%#x) == -1\n", addr);
- return (-1);
- }
-
- fprintf(stdout, "-> Flash page at %5d/%5d erased\n", i, num_pages);
- fflush(stdout);
- }
-
- fprintf(stdout, "\n");
- } else {
- wait_flash_busy(sl);
- clear_flash_error(sl);
- unlock_flash_if(sl);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_id != STLINK_CHIPID_STM32_H7AX) {
- // set parallelism
- write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2);
- }
- }
-
- set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit
- set_flash_cr_strt(
- sl, BANK_1); // start erase operation, reset by hw with busy bit
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2
- set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2
- }
-
- wait_flash_busy_progress(sl);
- lock_flash(sl);
-
- // reset the mass erase bit
- set_flash_cr_mer(sl, 0, BANK_1);
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- set_flash_cr_mer(sl, 0, BANK_2);
- }
-
- err = check_flash_error(sl);
- }
-
- return (err);
-}
-
-int stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
- // check the contents of path are at addr
-
- int res;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- return (-1);
- }
-
- res = check_file(sl, &mf, addr);
- unmap_file(&mf);
- return (res);
-}
-
-/**
- * Verify addr..addr+len is binary identical to base...base+len
- * @param sl stlink context
- * @param address stm device address
- * @param data host side buffer to check against
- * @param length how much
- * @return 0 for success, -ve for failure
- */
-int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
- unsigned length) {
- size_t off;
- size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
- ILOG("Starting verification of write complete\n");
-
- for (off = 0; off < length; off += cmp_size) {
- size_t aligned_size;
-
- // adjust last page size
- if ((off + cmp_size) > length) {
- cmp_size = length - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, address + (uint32_t)off, aligned_size);
-
- if (memcmp(sl->q_buf, data + off, cmp_size)) {
- ELOG("Verification of flash failed at offset: %u\n", (unsigned int)off);
- return (-1);
- }
- }
-
- ILOG("Flash written and verified! jolly good!\n");
- return (0);
-}
-
-int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len, uint32_t pagesize) {
- unsigned int count;
- unsigned int num_half_pages = len / pagesize;
- uint32_t val;
- uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
- flash_loader_t fl;
-
- ILOG("Starting Half page flash write for STM32L core id\n");
-
- /* Flash loader initialisation */
- if (stlink_flash_loader_init(sl, &fl) == -1) {
- WLOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
-
- // unlock already done
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- val |= (1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- wait_flash_busy(sl);
-
- for (count = 0; count < num_half_pages; count++) {
- if (stlink_flash_loader_run(sl, &fl, addr + count * pagesize,
- base + count * pagesize, pagesize) == -1) {
- WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n",
- addr + count * pagesize);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG));
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- return (-1);
- }
-
- // wait for sr.busy to be cleared
- if (sl->verbose >= 1) {
- // show progress; writing procedure is slow and previous errors are
- // misleading
- fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages);
- fflush(stdout);
- }
-
- wait_flash_busy(sl);
- }
-
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- return (0);
-}
-
-int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {
-
- // According to DDI0419C, Table C1-7 firstly force halt
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- STLINK_REG_DHCSR_C_HALT);
- // and only then disable interrupts
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- STLINK_REG_DHCSR_C_HALT |
- STLINK_REG_DHCSR_C_MASKINTS);
-
- // disable DMA
- set_dma_state(sl, fl, 0);
-
- // wait for ongoing op to finish
- wait_flash_busy(sl);
- // Clear errors
- clear_flash_error(sl);
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4)) {
- ILOG("Starting Flash write for F2/F4/F7/L4\n");
-
- // Flash loader initialisation
- if (stlink_flash_loader_init(sl, fl) == -1) {
- ELOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
-
- unlock_flash_if(sl); // first unlock the cr
-
- int voltage;
- if (sl->version.stlink_v == 1) {
- WLOG("STLINK V1 cannot read voltage, use default voltage 3.2V\n");
- voltage = 3200;
- } else {
- voltage = stlink_target_voltage(sl);
- }
-
- if (voltage == -1) {
- ELOG("Failed to read Target voltage\n");
- return (-1);
- }
-
- if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- // L4 does not have a byte-write mode
- if (voltage < 1710) {
- ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage);
- return (-1);
- }
- } else {
- if (voltage > 2700) {
- ILOG("enabling 32-bit flash writes\n");
- write_flash_cr_psiz(sl, 2, BANK_1);
- } else {
- ILOG("Target voltage (%d mV) too low for 32-bit flash, "
- "using 8-bit flash writes\n",
- voltage);
- write_flash_cr_psiz(sl, 0, BANK_1);
- }
- }
-
- // set programming mode
- set_flash_cr_pg(sl, BANK_1);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- ILOG("Starting Flash write for WB/G0/G4\n");
-
- unlock_flash_if(sl); // unlock flash if necessary
- set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- ILOG("Starting Flash write for L0\n");
-
- uint32_t val;
- uint32_t flash_regs_base;
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
-
- // disable pecr protection
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY2);
-
- // check pecr.pelock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 0)) {
- ELOG("pecr.pelock not clear\n");
- return (-1);
- }
-
- // unlock program memory
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY2);
-
- // check pecr.prglock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 1)) {
- ELOG("pecr.prglock not clear\n");
- return (-1);
- }
- } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- ILOG("Starting Flash write for VL/F0/F3/F1_XL\n");
-
- // flash loader initialisation
- if (stlink_flash_loader_init(sl, fl) == -1) {
- ELOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- ILOG("Starting Flash write for H7\n");
-
- unlock_flash_if(sl); // unlock the cr
- set_flash_cr_pg(sl, BANK_1); // set programming mode
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- set_flash_cr_pg(sl, BANK_2);
- }
- if (sl->chip_id != STLINK_CHIPID_STM32_H7AX) {
- // set parallelism
- write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2);
- }
- }
- } else {
- ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
- return (-1);
- }
-
- return (0);
-}
-
-int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl,
- stm32_addr_t addr, uint8_t *base, uint32_t len) {
- size_t off;
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4)) {
- size_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000;
- for (off = 0; off < len;) {
- size_t size = len - off > buf_size ? buf_size : len - off;
- if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off,
- size) == -1) {
- ELOG("stlink_flash_loader_run(%#x) failed! == -1\n",
- (unsigned)(addr + off));
- check_flash_error(sl);
- return (-1);
- }
-
- off += size;
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz));
- for (off = 0; off < len; off += sizeof(uint32_t)) {
- uint32_t data;
-
- if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
- fprintf(stdout, "\r%3u/%3u pages written",
- (unsigned int)(off / sl->flash_pgsz),
- (unsigned int)(len / sl->flash_pgsz));
- fflush(stdout);
- }
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
- stlink_write_debug32(sl, addr + (uint32_t)off, data);
- wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
- }
- fprintf(stdout, "\n");
-
- // flash writes happen as 2 words at a time
- if ((off / sizeof(uint32_t)) % 2 != 0) {
- stlink_write_debug32(sl, addr + (uint32_t)off,
- 0); // write a single word of zeros
- wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- uint32_t val;
- uint32_t flash_regs_base;
- uint32_t pagesize;
-
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- pagesize = L0_WRITE_BLOCK_SIZE;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- pagesize = L1_WRITE_BLOCK_SIZE;
- }
-
- off = 0;
-
- if (len > pagesize) {
- if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) {
- // this may happen on a blank device!
- WLOG("\nwrite_half_pages failed == -1\n");
- } else {
- off = (size_t)(len / pagesize) * pagesize;
- }
- }
-
- // write remaining word in program memory
- for (; off < len; off += sizeof(uint32_t)) {
- uint32_t data;
-
- if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
- fprintf(stdout, "\r%3u/%3u pages written",
- (unsigned int)(off / sl->flash_pgsz),
- (unsigned int)(len / sl->flash_pgsz));
- fflush(stdout);
- }
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
- stlink_write_debug32(sl, addr + (uint32_t)off, data);
-
- // wait for sr.busy to be cleared
- do {
- stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
- } while ((val & (1 << 0)) != 0);
-
- // TODO: check redo write operation
- }
- fprintf(stdout, "\n");
- } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- int write_block_count = 0;
- for (off = 0; off < len; off += sl->flash_pgsz) {
- // adjust last write size
- size_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off;
-
- // unlock and set programming mode
- unlock_flash_if(sl);
-
- DLOG("Finished unlocking flash, running loader!\n");
-
- if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off,
- size) == -1) {
- ELOG("stlink_flash_loader_run(%#x) failed! == -1\n",
- (unsigned)(addr + off));
- check_flash_error(sl);
- return (-1);
- }
-
- lock_flash(sl);
-
- if (sl->verbose >= 1) {
- // show progress; writing procedure is slow and previous errors are
- // misleading
- fprintf(stdout, "\r%3u/%3u pages written", ++write_block_count,
- (unsigned int)((len + sl->flash_pgsz - 1) / sl->flash_pgsz));
- fflush(stdout);
- }
- }
- if (sl->verbose >= 1) {
- fprintf(stdout, "\n");
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- for (off = 0; off < len;) {
- // Program STM32H7x with 64-byte Flash words
- size_t chunk = (len - off > 64) ? 64 : len - off;
- memcpy(sl->q_buf, base + off, chunk);
- stlink_write_mem32(sl, addr + (uint32_t)off, 64);
- wait_flash_busy(sl);
-
- off += chunk;
-
- if (sl->verbose >= 1) {
- // show progress
- fprintf(stdout, "\r%u/%u bytes written", (unsigned int)off,
- (unsigned int)len);
- fflush(stdout);
- }
- }
- if (sl->verbose >= 1) {
- fprintf(stdout, "\n");
- }
- } else {
- return (-1);
- }
-
- return check_flash_error(sl);
-}
-
-int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
- uint32_t dhcsr;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_WB) ||
- (sl->flash_type == STLINK_FLASH_TYPE_G0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_G4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7)) {
-
- clear_flash_cr_pg(sl, BANK_1);
- if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- clear_flash_cr_pg(sl, BANK_2);
- }
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- uint32_t val;
- uint32_t flash_regs_base;
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
- // reset lock bits
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << 0) | (1 << 1) | (1 << 2);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- }
-
- // enable interrupt
- if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) {
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- (dhcsr & (~STLINK_REG_DHCSR_C_MASKINTS)));
- }
-
- // restore DMA state
- set_dma_state(sl, fl, 1);
-
- return (0);
-}
-
-int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len, uint8_t eraseonly) {
- size_t off;
- int ret;
- flash_loader_t fl;
- ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len,
- len, addr, addr);
- // check addr range is inside the flash
- stlink_calculate_pagesize(sl, addr);
-
- if (addr < sl->flash_base) {
- ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
- return (-1);
- } else if ((addr + len) < addr) {
- ELOG("addr overruns\n");
- return (-1);
- } else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
- ELOG("addr too high\n");
- return (-1);
- } else if (addr & 1) {
- ELOG("unaligned addr 0x%x\n", addr);
- return (-1);
- } else if (len & 1) {
- WLOG("unaligned len 0x%x -- padding with zero\n", len);
- len += 1;
- } else if (addr & (sl->flash_pgsz - 1)) {
- ELOG("addr not a multiple of current pagesize (%u bytes), not supported, "
- "check page start address and compare with flash module organisation "
- "in related ST reference manual of your device.\n",
- (unsigned)(sl->flash_pgsz));
- return (-1);
- }
-
- // make sure we've loaded the context with the chip details
- stlink_core_id(sl);
-
- // Erase each page
- int page_count = 0;
-
- for (off = 0; off < len;
- off += stlink_calculate_pagesize(sl, addr + (uint32_t)off)) {
- // addr must be an addr inside the page
- if (stlink_erase_flash_page(sl, addr + (uint32_t)off) == -1) {
- ELOG("Failed to erase_flash_page(%#x) == -1\n", (unsigned)(addr + off));
- return (-1);
- }
-
- ILOG("Flash page at addr: 0x%08lx erased\n", (unsigned long)(addr + off));
- page_count++;
- }
-
- ILOG("Finished erasing %d pages of %u (%#x) bytes\n", page_count,
- (unsigned)(sl->flash_pgsz), (unsigned)(sl->flash_pgsz));
-
- if (eraseonly) {
- return (0);
- }
-
- ret = stlink_flashloader_start(sl, &fl);
- if (ret)
- return ret;
- ret = stlink_flashloader_write(sl, &fl, addr, base, len);
- if (ret)
- return ret;
- ret = stlink_flashloader_stop(sl, &fl);
- if (ret)
- return ret;
-
- return (stlink_verify_write_flash(sl, addr, base, len));
-}
-
-// TODO: length not checked
-static uint8_t stlink_parse_hex(const char *hex) {
- uint8_t d[2];
-
- for (int i = 0; i < 2; ++i) {
- char c = *(hex + i);
-
- if (c >= '0' && c <= '9') {
- d[i] = c - '0';
- } else if (c >= 'A' && c <= 'F') {
- d[i] = c - 'A' + 10;
- } else if (c >= 'a' && c <= 'f') {
- d[i] = c - 'a' + 10;
- } else {
- return (0); // error
- }
- }
-
- return ((d[0] << 4) | (d[1]));
-}
-
-int stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem,
- size_t *size, uint32_t *begin) {
- int res = 0;
- *begin = UINT32_MAX;
- uint8_t *data = NULL;
- uint32_t end = 0;
- bool eof_found = false;
-
- for (int scan = 0; (res == 0) && (scan < 2); ++scan) {
- // parse file two times - first to find memory range, second - to fill it
- if (scan == 1) {
- if (!eof_found) {
- ELOG("No EoF recond\n");
- res = -1;
- break;
- }
-
- if (*begin >= end) {
- ELOG("No data found in file\n");
- res = -1;
- break;
- }
-
- *size = (end - *begin) + 1;
- data = calloc(*size, 1); // use calloc to get NULL if out of memory
-
- if (!data) {
- ELOG("Cannot allocate %u bytes\n", (unsigned)(*size));
- res = -1;
- break;
- }
-
- memset(data, erased_pattern, *size);
- }
-
- FILE *file = fopen(path, "r");
-
- if (!file) {
- ELOG("Cannot open file\n");
- res = -1;
- break;
- }
-
- uint32_t lba = 0;
- char line[1 + 5 * 2 + 255 * 2 + 2];
-
- while (fgets(line, sizeof(line), file)) {
- if (line[0] == '\n' || line[0] == '\r') {
- continue;
- } // skip empty lines
-
- if (line[0] != ':') { // no marker - wrong file format
- ELOG("Wrong file format - no marker\n");
- res = -1;
- break;
- }
-
- size_t l = strlen(line);
-
- while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) {
- --l;
- } // trim EoL
-
- if ((l < 11) ||
- (l ==
- (sizeof(line) - 1))) { // line too short or long - wrong file format
- ELOG("Wrong file format - wrong line length\n");
- res = -1;
- break;
- }
-
- uint8_t chksum = 0; // check sum
-
- for (size_t i = 1; i < l; i += 2) {
- chksum += stlink_parse_hex(line + i);
- }
-
- if (chksum != 0) {
- ELOG("Wrong file format - checksum mismatch\n");
- res = -1;
- break;
- }
-
- uint8_t reclen = stlink_parse_hex(line + 1);
-
- if (((uint32_t)reclen + 5) * 2 + 1 != l) {
- ELOG("Wrong file format - record length mismatch\n");
- res = -1;
- break;
- }
-
- uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) |
- ((uint16_t)stlink_parse_hex(line + 5));
- uint8_t rectype = stlink_parse_hex(line + 7);
-
- switch (rectype) {
- case 0: /* Data */
- if (scan == 0) {
- uint32_t b = lba + offset;
- uint32_t e = b + reclen - 1;
-
- if (b < *begin) {
- *begin = b;
- }
-
- if (e > end) {
- end = e;
- }
- } else {
- for (uint8_t i = 0; i < reclen; ++i) {
- uint8_t b = stlink_parse_hex(line + 9 + i * 2);
- uint32_t addr = lba + offset + i;
-
- if (addr >= *begin && addr <= end) {
- data[addr - *begin] = b;
- }
- }
- }
- break;
- case 1: /* EoF */
- eof_found = true;
- break;
- case 2: /* Extended Segment Address, unexpected */
- res = -1;
- break;
- case 3: /* Start Segment Address, unexpected */
- res = -1;
- break;
- case 4: /* Extended Linear Address */
- if (reclen == 2) {
- lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) |
- ((uint32_t)stlink_parse_hex(line + 11) << 16);
- } else {
- ELOG("Wrong file format - wrong LBA length\n");
- res = -1;
- }
- break;
- case 5: /* Start Linear Address - expected, but ignore */
- break;
- default:
- ELOG("Wrong file format - unexpected record type %d\n", rectype);
- res = -1;
- }
-
- if (res != 0) {
- break;
- }
- }
-
- fclose(file);
- }
-
- if (res == 0) {
- *mem = data;
- } else {
- free(data);
- }
-
- return (res);
-}
-
-uint8_t stlink_get_erased_pattern(stlink_t *sl) {
- if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- return (0x00);
- } else {
- return (0xff);
- }
-}
-
-int stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length,
- stm32_addr_t addr) {
- /* Write the block in flash at addr */
- int err;
- unsigned int num_empty, idx;
- uint8_t erased_pattern = stlink_get_erased_pattern(sl);
-
- /*
- * This optimisation may cause unexpected garbage data remaining.
- * Therfore it is turned off by default.
- */
- if (sl->opt) {
- idx = (unsigned int)length;
-
- for (num_empty = 0; num_empty != length; ++num_empty)
- if (data[--idx] != erased_pattern) {
- break;
- }
-
- num_empty -= (num_empty & 3); // Round down to words
-
- if (num_empty != 0) {
- ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty,
- erased_pattern);
- }
- } else {
- num_empty = 0;
- }
-
- /*
- * TODO: investigate a kind of weird behaviour here:
- * If the file is identified to be all-empty and four-bytes aligned,
- * still flash the whole file even if ignoring message is printed.
- */
- err = stlink_write_flash(sl, addr, data,
- (num_empty == length) ? (uint32_t)length
- : (uint32_t)length - num_empty,
- num_empty == length);
- stlink_fwrite_finalize(sl, addr);
- return (err);
-}
-
-/**
- * Write the given binary file into flash at address "addr"
- * @param sl
- * @param path readable file path, should be binary image
- * @param addr where to start writing
- * @return 0 on success, -ve on failure.
- */
-int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
- /* Write the file in flash at addr */
- int err;
- unsigned int num_empty, idx;
- uint8_t erased_pattern = stlink_get_erased_pattern(sl);
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- ELOG("map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- if (sl->opt) {
- idx = (unsigned int)mf.len;
-
- for (num_empty = 0; num_empty != mf.len; ++num_empty) {
- if (mf.base[--idx] != erased_pattern) {
- break;
- }
- }
-
- num_empty -= (num_empty & 3); // round down to words
-
- if (num_empty != 0) {
- ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty,
- erased_pattern);
- }
- } else {
- num_empty = 0;
- }
-
- /*
- * TODO: investigate a kind of weird behaviour here:
- * If the file is identified to be all-empty and four-bytes aligned,
- * still flash the whole file even if ignoring message is printed.
- */
- err = stlink_write_flash(sl, addr, mf.base,
- (num_empty == mf.len) ? (uint32_t)mf.len
- : (uint32_t)mf.len - num_empty,
- num_empty == mf.len);
- stlink_fwrite_finalize(sl, addr);
- unmap_file(&mf);
- return (err);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_gx(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- /* Write options bytes */
- uint32_t val;
- int ret = 0;
- (void)len;
- uint32_t data;
-
- clear_flash_error(sl);
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base));
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
- stlink_write_debug32(sl, STM32Gx_FLASH_OPTR, data);
-
- // Set Options Start bit
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- val |= (1 << STM32Gx_FLASH_CR_OPTSTRT);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
-
- // Reload options
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- val |= (1 << STM32Gx_FLASH_CR_OBL_LAUNCH);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_l0(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t flash_base = get_stm32l0_flash_base(sl);
- uint32_t val;
- uint32_t data;
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- while (len != 0) {
- write_uint32((unsigned char *)&data,
- *(uint32_t *)(base)); // write options bytes
-
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
- stlink_write_debug32(sl, addr, data);
- wait_flash_busy(sl);
-
- if ((ret = check_flash_error(sl))) {
- break;
- }
-
- len -= 4;
- addr += 4;
- base += 4;
- }
-
- // Reload options
- stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val);
- val |= (1 << STM32L0_FLASH_OBL_LAUNCH);
- stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_l4(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
-
- uint32_t val;
- int ret = 0;
- (void)addr;
- (void)len;
-
- // Clear errors
- clear_flash_error(sl);
-
- // write options bytes
- uint32_t data;
- write_uint32((unsigned char *)&data, *(uint32_t *)(base));
- WLOG("Writing option bytes 0x%04x\n", data);
- stlink_write_debug32(sl, STM32L4_FLASH_OPTR, data);
-
- // set options start bit
- stlink_read_debug32(sl, STM32L4_FLASH_CR, &val);
- val |= (1 << STM32L4_FLASH_CR_OPTSTRT);
- stlink_write_debug32(sl, STM32L4_FLASH_CR, val);
-
- wait_flash_busy(sl);
- ret = check_flash_error(sl);
-
- // apply options bytes immediate
- stlink_read_debug32(sl, STM32L4_FLASH_CR, &val);
- val |= (1 << STM32L4_FLASH_CR_OBL_LAUNCH);
- stlink_write_debug32(sl, STM32L4_FLASH_CR, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_f4(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t option_byte;
- int ret = 0;
- (void)addr;
- (void)len;
-
- // Clear errors
- clear_flash_error(sl);
-
- write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
-
- // write option byte, ensuring we dont lock opt, and set strt bit
- stlink_write_debug32(sl, FLASH_F4_OPTCR,
- (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) |
- (1 << FLASH_F4_OPTCR_START));
-
- wait_flash_busy(sl);
- ret = check_flash_error(sl);
-
- // option bytes are reloaded at reset only, no obl. */
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_f7(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t option_byte;
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base),
- addr);
- write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
- ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr);
-
- if (addr == 0) {
- addr = FLASH_F7_OPTCR;
- ILOG("No address provided, using %#10x\n", addr);
- }
-
- if (addr == FLASH_F7_OPTCR) {
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
- } else if (addr == FLASH_F7_OPTCR1) {
- // Read FLASH_F7_OPTCR
- uint32_t oldvalue;
- stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue);
- /* write option byte */
- stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte);
- // Write FLASH_F7_OPTCR lock and start address
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
- } else {
- WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr);
- stlink_write_debug32(sl, addr, option_byte);
- }
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base,
- addr);
-
- /* option bytes are reloaded at reset only, no obl. */
-
- return ret;
-}
-
-/**
- * Write STM32H7xx option bytes
- * @param sl
- * @param base option bytes to write
- * @param addr of the memory mapped option bytes
- * @param len number of bytes to write (must be multiple of 4)
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_h7(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t val;
- uint32_t data;
-
- // Wait until previous flash option has completed
- wait_flash_busy(sl);
-
- // Clear previous error
- stlink_write_debug32(sl, FLASH_H7_OPTCCR,
- 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
-
- while (len != 0) {
- switch (addr) {
- case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG
- case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1
- case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1
- case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1
- case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG
- /* Write to FLASH_xxx_PRG registers */
- write_uint32((unsigned char *)&data,
- *(uint32_t *)(base)); // write options bytes
-
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
-
- /* Skip if the value in the CUR register is identical */
- stlink_read_debug32(sl, addr - 4, &val);
- if (val == data) {
- break;
- }
-
- /* Write new option byte values and start modification */
- stlink_write_debug32(sl, addr, data);
- stlink_read_debug32(sl, FLASH_H7_OPTCR, &val);
- val |= (1 << FLASH_H7_OPTCR_OPTSTART);
- stlink_write_debug32(sl, FLASH_H7_OPTCR, val);
-
- /* Wait for the option bytes modification to complete */
- do {
- stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val);
- } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0);
-
- /* Check for errors */
- if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) {
- stlink_write_debug32(sl, FLASH_H7_OPTCCR,
- 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
- return -1;
- }
- break;
-
- default:
- /* Skip non-programmable registers */
- break;
- }
-
- len -= 4;
- addr += 4;
- base += 4;
- }
-
- return 0;
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_Gx(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_Gx(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_Gx(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f2(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_f2(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f4(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_f4(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f7(stlink_t *sl,
- uint32_t *option_byte) {
- DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR);
- return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register1_f7(stlink_t *sl,
- uint32_t *option_byte) {
- DLOG("@@@@ Read option control register 1 byte from %#10x\n",
- FLASH_F7_OPTCR1);
- return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) {
- DLOG("@@@@ Read option byte boot address\n");
- return stlink_read_option_control_register1_f7(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- *
- * Since multiple bytes can be read, we read and print all but one here
- * and then return the last one just like other devices
- */
-int stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) {
- int err = -1;
- for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) {
- err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t),
- option_byte);
- if (err == -1) {
- return err;
- } else {
- printf("%08x\n", *option_byte);
- }
- }
-
- return stlink_read_debug32(
- sl,
- sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t),
- option_byte);
-}
-
-/**
- * Read first option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) {
- DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
- return stlink_read_debug32(sl, sl->option_base, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_bytes_boot_add_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
-// return stlink_read_debug32(sl, sl->option_base, option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_control_register_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option control register byte from %#10x\n",
-// sl->option_base); return stlink_read_debug32(sl, sl->option_base,
-// option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_control_register1_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option control register 1 byte from %#10x\n",
-// sl->option_base); return stlink_read_debug32(sl, sl->option_base,
-// option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return (-1);
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F2:
- return stlink_read_option_bytes_f2(sl, option_byte);
- case STLINK_CHIPID_STM32_F4:
- case STLINK_CHIPID_STM32_F446:
- return stlink_read_option_bytes_f4(sl, option_byte);
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_bytes_f7(sl, option_byte);
- case STLINK_CHIPID_STM32_G0_CAT1:
- case STLINK_CHIPID_STM32_G0_CAT2:
- case STLINK_CHIPID_STM32_G4_CAT2:
- case STLINK_CHIPID_STM32_G4_CAT3:
- return stlink_read_option_bytes_Gx(sl, option_byte);
- default:
- return stlink_read_option_bytes_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes boot address read is currently not supported for "
- "connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_bytes_boot_add_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_control_register_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_control_register_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register1_32(stlink_t *sl,
- uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_control_register1_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_control_register1_generic(sl, option_byte);
- }
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) {
- WLOG("About to write option byte %#10x to %#10x.\n", option_byte,
- sl->option_base);
- return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte,
- 4);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len) {
- int ret = -1;
-
- if (sl->option_base == 0) {
- ELOG(
- "Option bytes writing is currently not supported for connected chip\n");
- return (-1);
- }
-
- if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) {
- ELOG("Option bytes start address out of Option bytes range\n");
- return (-1);
- }
-
- if (addr + len > sl->option_base + sl->option_size) {
- ELOG("Option bytes data too long\n");
- return (-1);
- }
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return (-1);
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return (-1);
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F4:
- ret = stlink_write_option_bytes_f4(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_bytes_f7(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_L0:
- ret = stlink_write_option_bytes_l0(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_L4:
- ret = stlink_write_option_bytes_l4(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- ret = stlink_write_option_bytes_gx(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_H7:
- ret = stlink_write_option_bytes_h7(sl, base, addr, len);
- break;
- default:
- ELOG("Option bytes writing is currently not implemented for connected "
- "chip\n");
- break;
- }
-
- if (ret) {
- ELOG("Flash option write failed!\n");
- } else {
- ILOG("Wrote %d option bytes to %#010x!\n", len, addr);
- }
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_control_register_f7(stlink_t *sl,
- uint32_t option_control_register) {
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
- option_control_register, FLASH_F7_OPTCR);
-
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (option_control_register & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register,
- FLASH_F7_OPTCR);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_control_register1_f7(stlink_t *sl,
- uint32_t option_control_register1) {
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option control register 1 %#010x to %#010x.\n",
- option_control_register1, FLASH_F7_OPTCR1);
-
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- uint32_t current_control_register_value;
- stlink_read_debug32(sl, FLASH_F7_OPTCR, &current_control_register_value);
-
- /* write option byte */
- stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_control_register1);
- stlink_write_debug32(
- sl, FLASH_F7_OPTCR,
- (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register1,
- FLASH_F7_OPTCR1);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_bytes_boot_add_f7(stlink_t *sl,
- uint32_t option_byte_boot_add) {
- ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add);
- return stlink_write_option_control_register1_f7(sl, option_byte_boot_add);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes_boot_add32(stlink_t *sl,
- uint32_t option_bytes_boot_add) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add);
- break;
- default:
- ELOG("Option bytes boot address writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add);
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_control_register32(stlink_t *sl,
- uint32_t option_control_register) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_control_register_f7(sl, option_control_register);
- break;
- default:
- ELOG("Option control register writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option control register %#010x!\n", option_control_register);
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_control_register1_32(
- stlink_t *sl, uint32_t option_control_register1) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret =
- stlink_write_option_control_register1_f7(sl, option_control_register1);
- break;
- default:
- ELOG("Option control register 1 writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option control register 1 %#010x!\n", option_control_register1);
-
- lock_flash_option(sl);
- lock_flash(sl);
-
- return (ret);
-}
-
-/**
- * Write the given binary file with option bytes
- * @param sl
- * @param path readable file path, should be binary image
- * @param addr of the memory mapped option bytes
- * @return 0 on success, -ve on failure.
- */
-int stlink_fwrite_option_bytes(stlink_t *sl, const char *path,
- stm32_addr_t addr) {
- /* Write the file in flash at addr */
- int err;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- ELOG("map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len);
- stlink_fwrite_finalize(sl, addr);
- unmap_file(&mf);
-
- return (err);
-}
-
-int stlink_target_connect(stlink_t *sl, enum connect_type connect) {
- uint32_t dhcsr;
-
- if (connect == CONNECT_UNDER_RESET) {
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW);
-
- // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
- usleep(20);
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
- stlink_force_debug(sl);
-
- // clear S_RESET_ST in DHCSR register
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
-
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH);
- usleep(10000);
-
- // check NRST connection
- dhcsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- WLOG("NRST is not connected\n");
- }
-
- // addition soft reset for halt before the first instruction
- stlink_soft_reset(sl, 1 /* halt on reset */);
- }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
-
- if (connect == CONNECT_NORMAL) {
- stlink_reset(sl, RESET_AUTO);
- }
-
- return stlink_load_device_params(sl);
-}