Initial release of Flash bank driver for Bouffalo chips. The driver currently supports BL602, BL702, BL702L series of chips. Similar SFlash core is inside of BL808, BL606P and BL616 series, so those might be supported in future as well. With adapter speed set to 8000, it can reach speed 140 KiB/s. Since chips have eXecute In Place support, and they also require boot config in Flash at offset 0x0, it's required to have properly crafted linker script, so OpenOCD knows where to write firmware through gdb. There is required flash bank parameter, which specifies the chip type. This is required because BL702 and BL702L have same TAP ID CODE, and there are no usable indicators to use for automatic chip type recognition in the chip. Change-Id: Id57336d447be3c608b39ba3ed143527bfdc0af98 Signed-off-by: Marek Kraus <gamelaster@outlook.com> Reviewed-on: https://review.openocd.org/c/openocd/+/8527 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
153 lines
4.9 KiB
INI
153 lines
4.9 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 virt2phys_mode 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
|
|
|
|
if { [info exists FLASH_CHIP_TYPE] } {
|
|
set _FLASHNAME $_CHIPNAME.flash
|
|
flash bank $_FLASHNAME bl602 0x23000000 0 0 0 $_TARGETNAME $FLASH_CHIP_TYPE
|
|
|
|
$_TARGETNAME configure -event reset-init {
|
|
# Probing of Flash is required to initialize SFlash from unknown state.
|
|
flash probe 0
|
|
}
|
|
}
|
|
|
|
# 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} ]
|
|
}
|
|
}
|