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