riscv-openocd/tcl/target/bl602_common.cfg

144 lines
4.6 KiB
INI

# 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} ]
}
}