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
+}

-- 

Reply via email to