# script for stm32f7x family

#
# stm32f7 devices support both JTAG and SWD transports.
#
source [find target/stm32_common.cfg]

if { [info exists CHIPNAME] } {
   set _CHIPNAME $CHIPNAME
} else {
   set _CHIPNAME stm32f7x
}

if { [info exists BOARDNAME] } {
   set _BOARDNAME $BOARDNAME
} else {
   set _BOARDNAME stm32f7x_board
}

if { [info exists CORE_RESET] } {
	set _CORE_RESET $CORE_RESET
} else {
	set _CORE_RESET 0
}

if { [info exists CONNECT_UNDER_RESET] } {
   set _CONNECT_UNDER_RESET $CONNECT_UNDER_RESET
} else {
   set _CONNECT_UNDER_RESET 0
}

if { [info exists ENABLE_LOW_POWER] } {
   set _ENABLE_LOW_POWER $ENABLE_LOW_POWER
} else {
   set _ENABLE_LOW_POWER 0
}

if { [info exists STOP_WATCHDOG] } {
   set _STOP_WATCHDOG $STOP_WATCHDOG
} else {
   set _STOP_WATCHDOG 0
}

set _ENDIAN little

# Work-area is a space in RAM used for flash programming
# By default use 64kB
if { [info exists WORKAREASIZE] } {
   set _WORKAREASIZE $WORKAREASIZE
} else {
   set _WORKAREASIZE 0x10000
}

#jtag scan chain
if { [info exists CPUTAPID] } {
   set _CPUTAPID $CPUTAPID
} else {
   if { [using_jtag] } {
      # See STM Document RM0385
      # Section 40.6.3 - corresponds to Cortex-M7 with FPU r0p0
      set _CPUTAPID 0x5ba00477
   } else {
      set _CPUTAPID 0x5ba02477
   }
}

swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
set _TARGETNAME $_CHIPNAME.cpu

dap create $_CHIPNAME.dap -chain-position $_TARGETNAME
target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 -gdb-max-connections 2
tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000

$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash

flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME
#flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME
# On the STM32F7, the Flash is mapped at address 0x08000000 via the AXI and
# also address 0x00200000 via the ITCM. The former mapping is read-write in
# hardware, while the latter is read-only. By presenting an alias, we
# accomplish two things:
# (1) We allow writing at 0x00200000 (because the alias acts identically to the
#     original bank), which allows code intended to run from that address to
#     also be linked for loading at that address, simplifying linking.
# (2) We allow the proper memory map to be delivered to GDB, which will cause
#     it to use hardware breakpoints at the 0x00200000 mapping (correctly
#     identifying it as Flash), which it would otherwise not do. Configuring
#     the Flash via ITCM alias as virtual
flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME

if { [regexp -nocase {STM32F723E-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7308-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7.6G-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7508-DISCO} $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL}   $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL2}  $_BOARDNAME] || [regexp -nocase {STM32F7.9I.EVAL}  $_BOARDNAME] || [regexp -nocase {STM32F769I-DISC.} $_BOARDNAME] } {
	set _QSPINAME $_CHIPNAME.qspi
	flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
}

if { [info exists CLOCK_FREQ] } {
	set _CLOCK_FREQ $CLOCK_FREQ
} else {
	set _CLOCK_FREQ 4000
}
adapter speed $_CLOCK_FREQ

adapter srst delay 100
if {[using_jtag]} {
	jtag_ntrst_delay 100
}

if {![using_hla]} {
	global _CORE_RESET

	if { $_CORE_RESET == 1 } {
		# Only resetting Core
		cortex_m reset_config vectreset
	} else {
		# if srst is not fitted use SYSRESETREQ to
		# perform a soft reset
		cortex_m reset_config sysresetreq
	}
}

$_TARGETNAME configure -event examine-end {
global _ENABLE_LOW_POWER
global _STOP_WATCHDOG

	if { $_ENABLE_LOW_POWER == 1 } {
		# Enable debug during low power modes (uses more power)
		# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
		mmw 0xE0042004 0x00000007 0
	} else {
		# Disable debug during low power modes
		# DBGMCU_CR |= ~(DBG_STANDBY | DBG_STOP | DBG_SLEEP)
		mmw 0xE0042004 0 0x00000007
	}
	if { $_STOP_WATCHDOG == 1 } {
		# Stop watchdog counters during halt
		# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP
		mmw 0xE0042008 0x00001800 0
	} else {
		# Don't stop watchdog counters during halt
		# DBGMCU_APB1_FZ |= ~(DBG_IWDG_STOP | DBG_WWDG_STOP)
		mmw 0xE0042008 0 0x00001800
	}
}

proc first_gdb_attach_hook {} {
global _CONNECT_UNDER_RESET

	# Needed to be able to use the connect_assert_srst in reset_config
	# otherwise, can't read device flash size register
	if { $_CONNECT_UNDER_RESET == 1 } {
		reset init
	}
}

$_CHIPNAME.tpiu configure -event post-enable {
	# Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
	# change this value accordingly to configure trace pins
	# assignment
	mmw 0xE0042004 0x00000020 0
}

# QUADSPI initialization
proc qspi_init { } {
global _BOARDNAME

	mmw 0x40023830 0x000007FF 0				;# RCC_AHB1ENR |= GPIOA-GPIOK (enable clocks)
	mmw 0x40023838 0x00000002 0				;# RCC_AHB3ENR |= QSPIEN (enable clock)
	sleep 1									;# Wait for clock startup

	# All boards:              PB02: CLK,     PB06: BK1_NCS
	# F7[4|5]6 & F750 Disco    PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0
	# F723 & F730 & F769 Disco PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0
	# F7[4|5]6 & F7[6|7]9 Eval PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0

	# Port B: PB06:AF10, PB02:AF09
	mmw 0x40020400 0x00002020 0x00001010	;# MODER
	mmw 0x40020408 0x00003030 0x00000000	;# OSPEEDR
	mmw 0x40020420 0x0A000900 0x05000600	;# AFRL

	# F7[4|5]6 & F750 Disco
	if { [regexp -nocase {STM32F7.6G-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7508-DISCO} $_BOARDNAME] } {
		# Port D: PD11:AF09 PD12:AF09 PD13:AF09
		mmw 0x40020C00 0x0A800000 0x05400000	;# MODER
		mmw 0x40020C08 0x0FC00000 0x00000000	;# OSPEEDR
		mmw 0x40020C24 0x00999000 0x00666000	;# AFRH

		# Port E: PE02:AF09
		mmw 0x40021000 0x00000020 0x00000010	;# MODER
		mmw 0x40021008 0x00000030 0x00000000	;# OSPEEDR
		mmw 0x40021020 0x00000900 0x00000600	;# AFRL
	}

	# F7[4|5]6 & F7[6|7]9 Eval
	if { [regexp -nocase {STM327.6G-EVAL}   $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL2}  $_BOARDNAME] || [regexp -nocase {STM32F7.9I.EVAL}  $_BOARDNAME] } {
		# Port F: PF06 & PF07:AF09, PF08 & PF09:AF10
		mmw 0x40021400 0x000AA000 0x00055000	;# MODER
		mmw 0x40021408 0x000FF000 0x00000000	;# OSPEEDR
		mmw 0x40021420 0x99000000 0x66000000	;# AFRL
		mmw 0x40021424 0x000000AA 0x00000055	;# AFRH
	}

	# F723 & F730 & F769 Disco
	if { [regexp -nocase {STM32F723E-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7308-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F769I-DISC.} $_BOARDNAME] } {
		# Port C: PC10:AF09, PC09:AF09
		mmw 0x40020800 0x00280000 0x00140000	;# MODER
		mmw 0x40020808 0x003C0000 0x00000000	;# OSPEEDR
		mmw 0x40020824 0x00000990 0x00000660	;# AFRH

		# Port D: PD13:AF09
		mmw 0x40020C00 0x08000000 0x04000000	;# MODER
		mmw 0x40020C08 0x0C000000 0x00000000	;# OSPEEDR
		mmw 0x40020C24 0x00900000 0x00600000	;# AFRH

		# Port E: PE02:AF09
		mmw 0x40021000 0x00000020 0x00000010	;# MODER
		mmw 0x40021008 0x00000030 0x00000000	;# OSPEEDR
		mmw 0x40021020 0x00000900 0x00000600	;# AFRL
	}

	mww 0xA0001000 0x03500008				;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
	if { [regexp -nocase {STM32F7.6G-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7508-DISCO} $_BOARDNAME] } {
		mww 0xA0001004 0x00170100			;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
	}
	if { [regexp -nocase {STM32F723E-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7308-DISCO} $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL}   $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL2}  $_BOARDNAME] || [regexp -nocase {STM32F7.9I.EVAL}  $_BOARDNAME] || [regexp -nocase {STM32F769I-DISC.} $_BOARDNAME] } {
		mww 0xA0001004 0x00190100			;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0
	}
	mmw 0xA0001000 0x00000001 0				;# QUADSPI_CR: EN=1

	# 1-line spi mode
	mww 0xA0001014 0x000003F5				;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
	sleep 1

	if { [regexp -nocase {STM32F7.6G-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7508-DISCO} $_BOARDNAME] } {
		# memory-mapped read mode with 3-byte addresses
		mww 0xA0001014 0x0D002503			;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
	}
	if { [regexp -nocase {STM32F723E-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7308-DISCO} $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL}   $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL2}  $_BOARDNAME] || [regexp -nocase {STM32F7.9I.EVAL}  $_BOARDNAME] || [regexp -nocase {STM32F769I-DISC.} $_BOARDNAME] } {
		# memory-mapped read mode with 4-byte addresses
		mww 0xA0001014 0x0D003513			;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ
	}
}

$_TARGETNAME configure -event reset-init {
global _BOARDNAME
global _CLOCK_FREQ
global _CHIPNAME

	mww 0x40023C00 0x00000006				;# 6 WS for 192 MHz HCLK
	mww 0x40023804 0x24003008				;# 192 MHz: PLLM=8, PLLN=192, PLLP=2
	mww 0x40023808 0x00009400				;# APB1: /4, APB2: /2
	mmw 0x40023800 0x01000000 0x00000000	;# PLL on
	sleep 10
	mmw 0x40023808 0x00000002 0x00000000	;# switch to PLL

	if { [regexp -nocase {STM32F723E-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7308-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7.6G-DISCO} $_BOARDNAME] || [regexp -nocase {STM32F7508-DISCO} $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL}   $_BOARDNAME] || [regexp -nocase {STM327.6G-EVAL2}  $_BOARDNAME] || [regexp -nocase {STM32F7.9I.EVAL}  $_BOARDNAME] || [regexp -nocase {STM32F769I-DISC.} $_BOARDNAME] } {
		qspi_init
	}

	adapter speed $_CLOCK_FREQ

	if {![using_hla]} {
		# STM32F74x/F75x have CM7 r0p1 with silicon issue (workaround it by disabling interrupts during single-stepping)
		if { [regexp -nocase {STM32F74.....} $_CHIPNAME] || [regexp -nocase {STM32F75.....} $_CHIPNAME] } {
			cortex_m maskisr steponly
		}
	}
}

$_TARGETNAME configure -event gdb-attach { gdb_attach_hook }
$_TARGETNAME configure -event gdb-detach { gdb_detach_hook }
