# By default, esp32 config assumes that FreeRTOS is used. This can be disabled:
#set ESP32_RTOS none        # Disable RTOS support

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

if { [info exists CPUTAPID] } {
	set _CPUTAPID $CPUTAPID
} else {
	set _CPUTAPID 0x120034e5
}

if { [info exists ESP32_RTOS] } {
	set _RTOS "$ESP32_RTOS"
} else {
	set _RTOS "FreeRTOS"
}

if { [info exists ESP32_ONLYCPU] } {
	set _ONLYCPU $ESP32_ONLYCPU
} else {
	set _ONLYCPU 3
}

if { [info exists ESP32_FLASH_VOLTAGE] } {
	set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE
} else {
	set _FLASH_VOLTAGE 3.3
}

# by default autodetect flash size using flash chip ID, can be overriden by user via OpenOCD command line
if { [info exists ESP32_FLASH_SIZE] } {
	set _FLASH_SIZE $ESP32_FLASH_SIZE
} else {
	set _FLASH_SIZE 0x0
}

proc esp_core_halt { tgt } {
	#We need to disable the watchdogs here.
	#TIMG1 WDT
	$tgt mww 0x3FF5F064 0x50D83AA1
	$tgt mww 0x3FF5F048 0x0
	#TIMG2 WDT
	$tgt mww 0x3FF60064 0x50D83AA1
	$tgt mww 0x3FF60048 0x0
	#RTC WDT
	$tgt mww 0x3FF480A4 0x50D83AA1
	$tgt mww 0x3FF4808C 0x0
}

proc configure_esp32_core { TGT } {
	$TGT configure -event halted [list esp_core_halt $TGT]
}

proc configure_esp32_workarea { TGT } {
	#WARNING: be careful when selecting working ares for code and data, they should not overlap due to ESP32 physical memory mappings
	$TGT configure -work-area-phys 0x40090000 -work-area-virt 0x40090000 -work-area-size 0x3400 -work-area-backup 1
	# since ESP32 cannot use single address space for code and data we need additional working area to keep data
	$TGT configure -alt-work-area-phys 0x3FFC0000 -alt-work-area-virt 0x3FFC0000 -alt-work-area-size 0x6000 -alt-work-area-backup 1
}

proc configure_esp32_flash_bank { TGT } {
	# whole flash for programming purposes
	# TODO: remove it when support for GDB's 'load' comand is implemented
	flash bank $TGT.flash esp32 0x0 0 0 0 $TGT
	# So define mapped flash regions as separate flashes
	# OOCD creates memory map using registered flash banks
	flash bank irom esp32 0x0 0 0 0 $TGT
	flash bank drom esp32 0x0 0 0 0 $TGT
	# necessary to auto-probe flash bank when GDB is connected
	$TGT configure -event gdb-attach { halt }
}

# Dual core mode, FreeRTOS support enabled: use the new "esp32" target
jtag newtap $_CHIPNAME cpu0 -irlen 5 -expected-id $_CPUTAPID

set _TARGETNAME $_CHIPNAME
set _TAPNAME $_CHIPNAME.cpu0

if { $_RTOS == "none" } {
	target create $_TARGETNAME esp32 -endian little -chain-position $_TAPNAME
} else {
	target create $_TARGETNAME esp32 -endian little -chain-position $_TAPNAME -rtos $_RTOS
}

configure_esp32_core $_TARGETNAME
esp32 flashbootstrap $_FLASH_VOLTAGE
esp32 maskisr on

configure_esp32_workarea $_TARGETNAME
configure_esp32_flash_bank $_TARGETNAME


# special function to program ESP32, it differs from the original 'program' that
# it verifies written image by reading flash directly, instead of reading memory mapped flash regions
proc program_esp32 {filename args} {
	set exit 0

	foreach arg $args {
		if {[string equal $arg "verify"]} {
			set verify 1
		} elseif {[string equal $arg "reset"]} {
			set reset 1
		} elseif {[string equal $arg "exit"]} {
			set exit 1
		} else {
			set address $arg
		}
	}

	# make sure init is called
	if {[catch {init}] != 0} {
		program_error "** OpenOCD init failed **" 1
	}

	# reset target and call any init scripts
	if {[catch {reset init}] != 0} {
		program_error "** Unable to reset target **" $exit
	}

	# start programming phase
	echo "** Programming Started **"
	if {[info exists address]} {
		set flash_args "$filename $address"
	} else {
		set flash_args "$filename"
	}

	if {[catch {eval flash write_image erase $flash_args}] == 0} {
		echo "** Programming Finished **"
		if {[info exists verify]} {
			# verify phase
			echo "** Verify Started **"
			if {[catch {eval flash verify_bank 0 $flash_args}] == 0} {
				echo "** Verified OK **"
			} else {
				program_error "** Verify Failed **" $exit
			}
		}

		if {[info exists reset]} {
			# reset target if requested
			# also disable target polling, we are shutting down anyway
			poll off
			echo "** Resetting Target **"
			reset run
		}
	} else {
		program_error "** Programming Failed **" $exit
	}

	if {$exit == 1} {
		shutdown
	}
	return
}

add_help_text program_esp32 "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
add_usage_text program_esp32 "<filename> \[address\] \[verify\] \[reset\] \[exit\]"
