1#!/usr/bin/python 2# 3# Copyright (C) 2016 Google, Inc 4# Written by Simon Glass <sjg@chromium.org> 5# 6# SPDX-License-Identifier: GPL-2.0+ 7# 8 9import fdt_util 10import libfdt 11import sys 12 13# This deals with a device tree, presenting it as a list of Node and Prop 14# objects, representing nodes and properties, respectively. 15# 16# This implementation uses a libfdt Python library to access the device tree, 17# so it is fairly efficient. 18 19class Prop: 20 """A device tree property 21 22 Properties: 23 name: Property name (as per the device tree) 24 value: Property value as a string of bytes, or a list of strings of 25 bytes 26 type: Value type 27 """ 28 def __init__(self, name, bytes): 29 self.name = name 30 self.value = None 31 if not bytes: 32 self.type = fdt_util.TYPE_BOOL 33 self.value = True 34 return 35 self.type, self.value = fdt_util.BytesToValue(bytes) 36 37 def GetPhandle(self): 38 """Get a (single) phandle value from a property 39 40 Gets the phandle valuie from a property and returns it as an integer 41 """ 42 return fdt_util.fdt32_to_cpu(self.value[:4]) 43 44 def Widen(self, newprop): 45 """Figure out which property type is more general 46 47 Given a current property and a new property, this function returns the 48 one that is less specific as to type. The less specific property will 49 be ble to represent the data in the more specific property. This is 50 used for things like: 51 52 node1 { 53 compatible = "fred"; 54 value = <1>; 55 }; 56 node1 { 57 compatible = "fred"; 58 value = <1 2>; 59 }; 60 61 He we want to use an int array for 'value'. The first property 62 suggests that a single int is enough, but the second one shows that 63 it is not. Calling this function with these two propertes would 64 update the current property to be like the second, since it is less 65 specific. 66 """ 67 if newprop.type < self.type: 68 self.type = newprop.type 69 70 if type(newprop.value) == list and type(self.value) != list: 71 self.value = [self.value] 72 73 if type(self.value) == list and len(newprop.value) > len(self.value): 74 val = fdt_util.GetEmpty(self.type) 75 while len(self.value) < len(newprop.value): 76 self.value.append(val) 77 78 79class Node: 80 """A device tree node 81 82 Properties: 83 offset: Integer offset in the device tree 84 name: Device tree node tname 85 path: Full path to node, along with the node name itself 86 _fdt: Device tree object 87 subnodes: A list of subnodes for this node, each a Node object 88 props: A dict of properties for this node, each a Prop object. 89 Keyed by property name 90 """ 91 def __init__(self, fdt, offset, name, path): 92 self.offset = offset 93 self.name = name 94 self.path = path 95 self._fdt = fdt 96 self.subnodes = [] 97 self.props = {} 98 99 def Scan(self): 100 """Scan a node's properties and subnodes 101 102 This fills in the props and subnodes properties, recursively 103 searching into subnodes so that the entire tree is built. 104 """ 105 self.props = self._fdt.GetProps(self.path) 106 107 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset) 108 while offset >= 0: 109 sep = '' if self.path[-1] == '/' else '/' 110 name = libfdt.Name(self._fdt.GetFdt(), offset) 111 path = self.path + sep + name 112 node = Node(self._fdt, offset, name, path) 113 self.subnodes.append(node) 114 115 node.Scan() 116 offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) 117 118 119class Fdt: 120 """Provides simple access to a flat device tree blob. 121 122 Properties: 123 fname: Filename of fdt 124 _root: Root of device tree (a Node object) 125 """ 126 127 def __init__(self, fname): 128 self.fname = fname 129 with open(fname) as fd: 130 self._fdt = fd.read() 131 132 def GetFdt(self): 133 """Get the contents of the FDT 134 135 Returns: 136 The FDT contents as a string of bytes 137 """ 138 return self._fdt 139 140 def Scan(self): 141 """Scan a device tree, building up a tree of Node objects 142 143 This fills in the self._root property 144 """ 145 self._root = Node(self, 0, '/', '/') 146 self._root.Scan() 147 148 def GetRoot(self): 149 """Get the root Node of the device tree 150 151 Returns: 152 The root Node object 153 """ 154 return self._root 155 156 def GetProps(self, node): 157 """Get all properties from a node. 158 159 Args: 160 node: Full path to node name to look in. 161 162 Returns: 163 A dictionary containing all the properties, indexed by node name. 164 The entries are Prop objects. 165 166 Raises: 167 ValueError: if the node does not exist. 168 """ 169 offset = libfdt.fdt_path_offset(self._fdt, node) 170 if offset < 0: 171 libfdt.Raise(offset) 172 props_dict = {} 173 poffset = libfdt.fdt_first_property_offset(self._fdt, offset) 174 while poffset >= 0: 175 dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) 176 prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop)) 177 props_dict[prop.name] = prop 178 179 poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) 180 return props_dict 181