144 lines
4.6 KiB
INI
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} ]
|
|
}
|
|
}
|