set _command "$_command -defer-examine"
set _smp_command "$_smp_command $_TARGETNAME.$_core"
} else {
- # uncomment when "hawt" rtos is merged
- #set _command "$_command -rtos hawt"
+ set _command "$_command -rtos hwthread"
set _smp_command "target smp $_TARGETNAME.$_core"
}
$_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
+}