# SPDX-License-Identifier: GPL-2.0-or-later # Script for Bouffalo chips with similar architecture used in BL602 # based on SiFive E21 core source [find mem_helper.tcl] transport select jtag if { [info exists CPUTAPID ] } { set _CPUTAPID $CPUTAPID } else { error "you must specify a tap id" } if { [info exists BL602_CHIPNAME] } { set _CHIPNAME $BL602_CHIPNAME } else { error "you must specify a chip name" } if { [info exists WORKAREAADDR] } { set _WORKAREAADDR $WORKAREAADDR } else { error "you must specify a work area address" } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { error "you must specify a work area size" } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME riscv set_mem_access sysbus riscv set_enable_virt2phys off $_TARGETNAME configure -work-area-phys $_WORKAREAADDR -work-area-size $_WORKAREASIZE -work-area-backup 1 # Internal RC ticks on 32 MHz, so this speed should be safe to use. adapter speed 8000 # Useful functions set dmcontrol 0x10 set dmcontrol_dmactive [expr {1 << 0}] set dmcontrol_ndmreset [expr {1 << 1}] set dmcontrol_resumereq [expr {1 << 30}] set dmcontrol_haltreq [expr {1 << 31}] proc bl602_restore_clock_defaults { } { # Switch clock to internal RC32M # In HBN_GLB, set ROOT_CLK_SEL = 0 mmw 0x4000f030 0x0 0x00000003 # Wait for clock switch sleep 10 # GLB_REG_BCLK_DIS_FALSE mww 0x40000ffc 0x0 # HCLK is RC32M, so BCLK/HCLK doesn't need divider # In GLB_CLK_CFG0, set BCLK_DIV = 0 and HCLK_DIV = 0 mmw 0x40000000 0x0 0x00FFFF00 # Wait for clock to stabilize sleep 10 } # By spec, ndmreset should reset whole chip. This implementation resets only few parts of the chip. # CTRL_PWRON_RESET register in GLB core triggers full "power-on like" reset, so we use it instead # for full software reset. proc bl602_sw_reset { } { # In GLB_SWRST_CFG2, clear CTRL_SYS_RESET, CTRL_CPU_RESET and CTRL_PWRON_RESET mmw 0x40000018 0x0 0x00000007 # This Software reset method resets everything, so CPU as well. # It does that in not much good way, resulting in Debug Module being reset as well. # This also means, that right after CPU and Debug Module are turned on, we need to # enable Debug Module and halt CPU if needed. Additionally, we trigger this SW reset # through system bus access directly with DMI commands, to avoid errors printed by # OpenOCD about unsuccessful register write. # In GLB_SWRST_CFG2, set CTRL_SYS_RESET, CTRL_CPU_RESET and CTRL_PWRON_RESET to 1 riscv dmi_write 0x39 0x40000018 riscv dmi_write 0x3c 0x7 # We need to wait for chip to finish reset and execute BootROM sleep 1 # JTAG Debug Transport Module is reset as well, so we need to get into RUN/IDLE state runtest 10 # We need to enable Debug Module and halt the CPU, so we can reset Program Counter # and to do additional clean-ups. If reset was called without halt, resume is handled # by reset-deassert-post event handler. # In Debug Module Control (dmcontrol), set dmactive to 1 and then haltreq to 1 riscv dmi_write $::dmcontrol $::dmcontrol_dmactive riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_haltreq} ] # Set Program Counter to start of BootROM set_reg {pc 0x21000000} } # On BL602 and BL702, the only way to force chip stay in BootROM (until JTAG attaches) # is by putting infinity loop into HBN RAM (which is not reset by sw reset), and then # configure HBN registers, which will cause BootROM to jump into our code early in BootROM. proc bl602_sw_reset_hbn_wait {} { # Restore clocks to defaults bl602_restore_clock_defaults # In HBN RAM, write infinity loop instruction # beq zero, zero, 0 mww 0x40010000 0x00000063 # In HNB, set HBN_RSV0 (Status Flag) to "EHBN" (as uint32_t) mww 0x4000f100 0x4e424845 # In HBN, set HBN_RSV1 (WakeUp Address) to HBN RAM address mww 0x4000f104 0x40010000 # Perform software reset bl602_sw_reset # Clear HBN RAM, HBN_RSV0 and HBN_RSV1 mww 0x40010000 0x00000000 mww 0x4000f100 0x00000000 mww 0x4000f104 0x00000000 # This early jump method locks up BootROM through Trust Zone Controller. # That means any read of BootROM returns 0xDEADBEEF. # Only way to reset it, is through JTAG Reset, thus toggling ndmreset in dmcontrol. riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_ndmreset} ] riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive} ] } $_TARGETNAME configure -event reset-deassert-post { # Resume the processor if reset was triggered without halt request if {$halt == 0} { riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_resumereq} ] } }