241 lines
6.8 KiB
INI
241 lines
6.8 KiB
INI
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#
|
|
# target configuration for
|
|
# Xilinx ZynqMP (UltraScale+ / A53)
|
|
#
|
|
if { [info exists CHIPNAME] } {
|
|
set _CHIPNAME $CHIPNAME
|
|
} else {
|
|
set _CHIPNAME uscale
|
|
}
|
|
|
|
#
|
|
# DAP tap (Quard core A53)
|
|
#
|
|
if { [info exists DAP_TAPID] } {
|
|
set _DAP_TAPID $DAP_TAPID
|
|
} else {
|
|
set _DAP_TAPID 0x5ba00477
|
|
}
|
|
|
|
jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID
|
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap
|
|
|
|
#
|
|
# PS tap (UltraScale+)
|
|
#
|
|
if { [info exists PS_TAPID] } {
|
|
set _PS_TAPID $PS_TAPID
|
|
jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -expected-id $_PS_TAPID
|
|
} else {
|
|
# FPGA Programmable logic. Values take from Table 39-1 in UG1085:
|
|
jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -ignore-version \
|
|
-expected-id 0x04711093 \
|
|
-expected-id 0x04710093 \
|
|
-expected-id 0x04721093 \
|
|
-expected-id 0x04720093 \
|
|
-expected-id 0x04739093 \
|
|
-expected-id 0x04730093 \
|
|
-expected-id 0x04738093 \
|
|
-expected-id 0x04740093 \
|
|
-expected-id 0x04750093 \
|
|
-expected-id 0x04759093 \
|
|
-expected-id 0x04758093
|
|
}
|
|
|
|
set jtag_configured 0
|
|
|
|
jtag configure $_CHIPNAME.ps -event setup {
|
|
global _CHIPNAME
|
|
global jtag_configured
|
|
|
|
if { $jtag_configured == 0 } {
|
|
# add the DAP tap to the chain
|
|
# See https://forums.xilinx.com/t5/UltraScale-Architecture/JTAG-Chain-Configuration-for-Zynq-UltraScale-MPSoC/td-p/758924
|
|
irscan $_CHIPNAME.ps 0x824
|
|
drscan $_CHIPNAME.ps 32 0x00000003
|
|
runtest 100
|
|
|
|
# setup event will be re-entered through jtag arp_init
|
|
# break the recursion
|
|
set jtag_configured 1
|
|
# re-initialized the jtag chain
|
|
jtag arp_init
|
|
}
|
|
}
|
|
|
|
set _TARGETNAME $_CHIPNAME.a53
|
|
set _CTINAME $_CHIPNAME.cti
|
|
set _smp_command ""
|
|
|
|
set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000}
|
|
set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000}
|
|
set _cores 4
|
|
|
|
for { set _core 0 } { $_core < $_cores } { incr _core } {
|
|
|
|
cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \
|
|
-baseaddr [lindex $CTIBASE $_core]
|
|
|
|
set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \
|
|
-dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core"
|
|
|
|
if { $_core != 0 } {
|
|
# non-boot core examination may fail
|
|
set _command "$_command -defer-examine"
|
|
set _smp_command "$_smp_command $_TARGETNAME.$_core"
|
|
} else {
|
|
set _command "$_command -rtos hwthread"
|
|
set _smp_command "target smp $_TARGETNAME.$_core"
|
|
}
|
|
|
|
eval $_command
|
|
}
|
|
|
|
target create uscale.axi mem_ap -dap uscale.dap -ap-num 0
|
|
|
|
eval $_smp_command
|
|
targets $_TARGETNAME.0
|
|
|
|
proc core_up { args } {
|
|
global _TARGETNAME
|
|
foreach core $args {
|
|
$_TARGETNAME.$core arp_examine
|
|
}
|
|
}
|
|
|
|
proc BIT {n} {
|
|
return [expr {1 << $n}]
|
|
}
|
|
|
|
set IPI_BASE 0xff300000
|
|
set IPI_PMU_0_TRIG [expr {$IPI_BASE + 0x30000}]
|
|
set IPI_PMU_0_IER [expr {$IPI_BASE + 0x30018}]
|
|
set IPI_PMU_0 [BIT 16]
|
|
|
|
set CRF_APB_BASE 0xfd1a0000
|
|
set CRF_APB_RST_FPD_APU [expr {$CRF_APB_BASE + 0x104}]
|
|
set CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET [BIT 10]
|
|
set CRF_APB_RST_FPD_APU_L2_RESET [BIT 8]
|
|
set CRF_APB_RST_FPD_APU_ACPU0_RESET [BIT 0]
|
|
|
|
set APU_BASE 0xfd5c0000
|
|
set APU_RVBARADDR_BASE [expr {$APU_BASE + 0x40}]
|
|
|
|
set PMU_BASE 0xffd80000
|
|
set PMU_GLOBAL $PMU_BASE
|
|
set PMU_GLOBAL_MB_SLEEP [BIT 16]
|
|
set PMU_GLOBAL_FW_IS_PRESENT [BIT 4]
|
|
set PMU_GLOBAL_DONT_SLEEP [BIT 0]
|
|
|
|
set PMU_RAM_BASE 0xffdc0000
|
|
|
|
set OCM_RAM_BASE 0xfffc0000
|
|
|
|
rename BIT {}
|
|
|
|
add_help_text halt_pmu "Halt the PMU in preparation for loading new firmware.\
|
|
This should be matched with a call to resume_pmu."
|
|
proc halt_pmu {} {
|
|
set axi $::_CHIPNAME.axi
|
|
set val [$axi read_memory $::IPI_PMU_0_IER 32 1]
|
|
$axi write_memory $::IPI_PMU_0_IER 32 [expr {$val | $::IPI_PMU_0}]
|
|
|
|
set val [$axi read_memory $::IPI_PMU_0_TRIG 32 1]
|
|
$axi write_memory $::IPI_PMU_0_TRIG 32 [expr {$val | $::IPI_PMU_0}]
|
|
|
|
set start [ms]
|
|
while {!([$axi read_memory $::PMU_GLOBAL 32 1] & $::PMU_GLOBAL_MB_SLEEP)} {
|
|
if {[ms] - $start > 1000} {
|
|
error "Timed out waiting for PMU to halt"
|
|
}
|
|
}
|
|
}
|
|
|
|
add_help_text resume_pmu "Resume the PMU after loading new firmware. This\
|
|
should be matched with a call to halt_pmu."
|
|
proc resume_pmu {} {
|
|
set axi $::_CHIPNAME.axi
|
|
set val [$axi read_memory $::PMU_GLOBAL 32 1]
|
|
$axi write_memory $::PMU_GLOBAL 32 [expr {$val | $::PMU_GLOBAL_DONT_SLEEP}]
|
|
|
|
set start [ms]
|
|
while {!([$axi read_memory $::PMU_GLOBAL 32 1] & $::PMU_GLOBAL_FW_IS_PRESENT)} {
|
|
if {[ms] - $start > 5000} {
|
|
error "Timed out waiting for PMU firmware"
|
|
}
|
|
}
|
|
}
|
|
|
|
add_usage_text release_apu {apu}
|
|
add_help_text release_apu "Release an APU from reset. It will start executing\
|
|
at RVBARADDR. You probably want resume_apu or start_apu instead."
|
|
proc release_apu {apu} {
|
|
set axi $::_CHIPNAME.axi
|
|
set val [$axi read_memory $::CRF_APB_RST_FPD_APU 32 1]
|
|
set mask [expr {
|
|
(($::CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET | \
|
|
$::CRF_APB_RST_FPD_APU_ACPU0_RESET) << $apu) | \
|
|
$::CRF_APB_RST_FPD_APU_L2_RESET
|
|
}]
|
|
$axi write_memory $::CRF_APB_RST_FPD_APU 32 [expr {$val & ~$mask}]
|
|
|
|
core_up $apu
|
|
$::_TARGETNAME.$apu aarch64 dbginit
|
|
}
|
|
|
|
proc _rvbaraddr {apu} {
|
|
return [expr {$::APU_RVBARADDR_BASE + 8 * $apu}]
|
|
}
|
|
|
|
add_usage_text resume_apu {apu addr}
|
|
add_help_text resume_apu "Resume an APU at a given address."
|
|
proc resume_apu {apu addr} {
|
|
set addrl [expr {$addr & 0xffffffff}]
|
|
set addrh [expr {$addr >> 32}]
|
|
$::_CHIPNAME.axi write_memory [_rvbaraddr $apu] 32 [list $addrl $addrh]
|
|
|
|
release_apu $apu
|
|
}
|
|
|
|
add_usage_text start_apu {apu}
|
|
add_help_text start_apu "Start an APU and put it into an infinite loop at\
|
|
RVBARADDR. This can be convenient if you just want to halt the APU\
|
|
(since it won't execute anything unusual)."
|
|
proc start_apu {apu} {
|
|
set axi $::_CHIPNAME.axi
|
|
foreach {addrl addrh} [$axi read_memory [_rvbaraddr $apu] 32 2] {
|
|
set addr [expr {($addrh << 32) | $addrl}]
|
|
}
|
|
# write the infinite loop instruction
|
|
$axi write_memory $addr 32 0x14000000
|
|
|
|
release_apu $apu
|
|
}
|
|
|
|
add_usage_text boot_pmu {image}
|
|
add_help_text boot_pmu "Boot the PMU with a given firmware image, loading it\
|
|
to the beginning of PMU RAM. The PMU ROM will jump to this location\
|
|
after we resume it."
|
|
proc boot_pmu {image} {
|
|
halt_pmu
|
|
echo "Info : Loading PMU firmware $image to $::PMU_RAM_BASE"
|
|
load_image $image $::PMU_RAM_BASE
|
|
resume_pmu
|
|
}
|
|
|
|
add_usage_text boot_apu "image \[apu=0 \[addr=$OCM_RAM_BASE\]\]"
|
|
add_help_text boot_apu "Boot an APU with a given firmware image. The default\
|
|
address is the beginning of OCM RAM. Upon success, the default target\
|
|
will be changed to the (running) apu."
|
|
proc boot_apu [list image {apu 0} [list addr $OCM_RAM_BASE]] {
|
|
start_apu $apu
|
|
targets $::_TARGETNAME.$apu
|
|
halt
|
|
|
|
echo "Info : Loading APU$apu firmware $image to $addr"
|
|
load_image $image $addr
|
|
resume $addr
|
|
}
|