This is an automated email from Gerrit. "Tomas Vanek <van...@fbl.cz>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7686
-- gerrit commit 921a20b0df622f51dc09634a11bdb32cfa163e2f Author: Tomas Vanek <van...@fbl.cz> Date: Sat May 13 11:59:16 2023 +0200 tcl: add device tree address translation helper [WIP] Use dt_reg_translate_to_cpu /proc/device-tree /soc/gpio@7e200000/reg Traverses all 'ranges' in the DT path from the parent of the peripheral node back to the DT root and translates 'reg' address to phys memory address of the peripheral. Signed-off-by: Tomas Vanek <van...@fbl.cz> Change-Id: If1a4104f8008271b8f0f0135628a19b08a75f5eb diff --git a/tcl/devicetree.tcl b/tcl/devicetree.tcl index e22c636ced..54db94bcf1 100644 --- a/tcl/devicetree.tcl +++ b/tcl/devicetree.tcl @@ -41,14 +41,78 @@ proc dt_get_u32 { fname } { close $fd set len [string length $data] - if { $len == 0 || [expr { $len % 4 }] != 0 } { + if { [expr { $len % 4 }] != 0 } { error "property is not a list of u32: '$fname'" } - unset -nocomplain result + set result {} for { set i 0 } { $i < $len } { incr i 4 } { scan [string range $data $i [expr { $i + 3 }]] "%c%c%c%c" x3 x2 x1 x0 lappend result [format "0x%02x%02x%02x%02x" $x3 $x2 $x1 $x0] } return $result } + +proc dt_translate_addr_level_up { dt_root child_node addr } { + set parent_node [file dirname $child_node] + set child_address_cells [dt_get_u32 "${dt_root}${child_node}/#address-cells"] + set child_size_cells [dt_get_u32 "${dt_root}${child_node}/#size-cells"] + set parent_address_cells [dt_get_u32 "${dt_root}${parent_node}/#address-cells"] + set ranges [dt_get_u32 "${dt_root}${child_node}/ranges"] + if { [llength $ranges] == 0 } { + # empty ranges -> no translation + return $addr + } + while { [llength $ranges] } { + if { $child_address_cells == 1 } { + set child_range [lindex $ranges 0] + } elseif { $child_address_cells == 2 } { + set child_range [expr {([lindex $ranges 0] << 32) + [lindex $ranges 1]}] + } else { + error "mapping with child #address-cells $child_address_cells not implemented: '$child_node'" + } + set ranges [lreplace $ranges 0 [expr { $child_address_cells - 1 }]] + + if { $parent_address_cells == 1 } { + set parent_range [lindex $ranges 0] + } elseif { $parent_address_cells == 2 } { + set parent_range [expr {([lindex $ranges 0] << 32) + [lindex $ranges 1]}] + } else { + error "mapping with parent #address-cells $parent_address_cells not implemented: '$child_node'" + } + set ranges [lreplace $ranges 0 [expr { $parent_address_cells - 1 }]] + + if { $child_size_cells == 1 } { + set size_range [lindex $ranges 0] + } else { + error "mapping with child #size-cells $child_size_cells not implemented: '$child_node'" + } + set ranges [lreplace $ranges 0 0] + + if { $addr >= $child_range && $addr < [expr { $child_range + $size_range }] } { + echo "$child_node: addr $addr, child $child_range $size_range, parent $parent_range" + return [format "0x%08x" [expr { $addr - $child_range + $parent_range }]] + } + } + error "mapping not found: '$node'" +} + +proc dt_reg_translate_to_cpu { dt_root property } { + set node [file dirname $property] + set parent_node [file dirname $node] + set address_cells [dt_get_u32 "${dt_root}${parent_node}/#address-cells"] + set reg [dt_get_u32 ${dt_root}${property}] + if { $address_cells == 1 } { + set reg_addr [lindex $reg 0] + } elseif { $address_cells == 2 } { + set reg_addr [expr {([lindex $reg 0] << 32) + [lindex $reg 1]}] + } else { + error "mapping with #address-cells $address_cells not implemented: '$node'" + } + + while { [string compare $parent_node "/"] != 0 } { + set reg_addr [dt_translate_addr_level_up $dt_root $parent_node $reg_addr] + set parent_node [file dirname $parent_node] + } + return $reg_addr +} --