diff --git a/tcl/target/bl616.cfg b/tcl/target/bl616.cfg new file mode 100644 index 000000000..ee59f1850 --- /dev/null +++ b/tcl/target/bl616.cfg @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Author: Marek Kraus + +# +# Bouffalo Labs BL616 and BL618 target +# +# Default JTAG pins: (if not changed by eFuse configuration) +# TMS - GPIO0 +# TCK - GPIO1 +# TDO - GPIO2 +# TDI - GPIO3 +# + +source [find mem_helper.tcl] + +transport select jtag + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bl616 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000b6f + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME + +riscv set_mem_access progbuf +riscv set_enable_virt2phys off + +$_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x10000 -work-area-backup 1 + +adapter speed 4000 + +# Useful functions +set dmcontrol 0x10 +set dmcontrol_dmactive [expr {1 << 0}] +set dmcontrol_haltreq [expr {1 << 31}] + +# 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. +$_TARGETNAME configure -event reset-assert { + halt + + # To stay in BootROM until JTAG re-attaches, we are using BootROM functionality + # to force ISP mode, so BootROM looks out for external ISP communication. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 1 (ISP) + mww 0x2000f108 0x44000000 + + # Switch clock to internal RC32M + # In HBN_GLB, set ROOT_CLK_SEL = 0 + mmw 0x2000f030 0x0 0x00000002 + + # In GLB_SYS_CFG0, set REG_BCLK_DIV and REG_HCLK_DIV = 0 + mmw 0x20000090 0x0 0x00FFFF00 + + # Trigger BCLK ACT pulse + # In GLB_SYS_CFG1, set BCLK_DIV_ACT_PULSE = 1 + mmw 0x20000094 0x1 0x00000001 + # In GLB_SYS_CFG1, wait for GLB_STS_BCLK_PROT_DONE to become 1 + while { [expr {[mrw 0x20000094] & 4}] == 0 } { sleep 1 } + + # In GLB_SWRST_CFG2, clear CTRL_PWRON_RESET + mmw 0x20000548 0x0 0x00000001 + + # 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 program buffer access directly with DMI commands, to avoid errors printed by + # OpenOCD about unsuccessful register write. + + # In GLB_SWRST_CFG2, set CTRL_PWRON_RESET to 1 + set_reg {fp 0x20000548 s1 0x01} + riscv dmi_write 0x20 0x00942023 + riscv dmi_write 0x17 0x40000 + + # We need to wait for chip to finish reset and execute BootROM + sleep 10 + + # 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} ] +} + +$_TARGETNAME configure -event reset-deassert-post { + # Set Program Counter to start of BootROM and execute one instruction + step 0x90000000 + + # When using default JTAG pinout, BOOT pin is the same as JTAG TDO pin. + # Since after reset we set PC to start of the BootROM, + # BootROM will execute also check of BOOT pin, which will disable TDO pin, + # to check the BOOT pin state. This leads to temporary loss of JTAG access + # and causes (recoverable) errors in OpenOCD. We can bypass the BOOT pin check + # function, by forcing booting from Media/SPI Flash. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 2 (Media/SPI Flash) + mww 0x2000f108 0x48000000 + + # Resume the processor if reset was triggered without halt request + if {$halt == 0} { + resume + } +} + +# According to JTAG spec (IEEE 1149.1), when chip enters "Test-Logic-Reset" state, +# the IR instruction should be set to "IDCODE" or "BYPASS" (when chip does not have IDCODE). +# This is done so automatic chain scan can detect all the chips within JTAG chain without knowing IDCODE. +# JTAG Debug Transport Module (DTM) used in this chip, developed by T-Head (formerly C-Sky) +# does not implement this, so OpenOCD can't detect the chip anymore after the IR instruction is changed. +# This workaround gets chip into known state, and manually set IR instruction to IDCODE, +# which is 0x01, standardized by RISC-V Debug Specification. +proc init_reset { mode } { + if {[using_jtag]} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + jtag arp_init-reset + } +} + +proc jtag_init {} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + + if {[catch {jtag arp_init} err]!=0} { + # try resetting additionally + init_reset startup + } +}