1a06a34b2SSimon Glass#!/usr/bin/python 2a06a34b2SSimon Glass# 3a06a34b2SSimon Glass# Copyright (C) 2016 Google, Inc 4a06a34b2SSimon Glass# Written by Simon Glass <sjg@chromium.org> 5a06a34b2SSimon Glass# 6a06a34b2SSimon Glass# SPDX-License-Identifier: GPL-2.0+ 7a06a34b2SSimon Glass# 8a06a34b2SSimon Glass 9a06a34b2SSimon Glassimport struct 10a06a34b2SSimon Glassimport sys 11a06a34b2SSimon Glass 12a06a34b2SSimon Glassimport fdt_util 13a06a34b2SSimon Glass 14a06a34b2SSimon Glass# This deals with a device tree, presenting it as an assortment of Node and 15a06a34b2SSimon Glass# Prop objects, representing nodes and properties, respectively. This file 16a06a34b2SSimon Glass# contains the base classes and defines the high-level API. Most of the 17a06a34b2SSimon Glass# implementation is in the FdtFallback and FdtNormal subclasses. See 18a06a34b2SSimon Glass# fdt_select.py for how to create an Fdt object. 19a06a34b2SSimon Glass 20bc1dea36SSimon Glass# A list of types we support 21bc1dea36SSimon Glass(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) 22bc1dea36SSimon Glass 23a06a34b2SSimon Glassdef CheckErr(errnum, msg): 24a06a34b2SSimon Glass if errnum: 25a06a34b2SSimon Glass raise ValueError('Error %d: %s: %s' % 26a06a34b2SSimon Glass (errnum, libfdt.fdt_strerror(errnum), msg)) 27a06a34b2SSimon Glass 28a06a34b2SSimon Glassclass PropBase: 29a06a34b2SSimon Glass """A device tree property 30a06a34b2SSimon Glass 31a06a34b2SSimon Glass Properties: 32a06a34b2SSimon Glass name: Property name (as per the device tree) 33a06a34b2SSimon Glass value: Property value as a string of bytes, or a list of strings of 34a06a34b2SSimon Glass bytes 35a06a34b2SSimon Glass type: Value type 36a06a34b2SSimon Glass """ 37a06a34b2SSimon Glass def __init__(self, node, offset, name): 38a06a34b2SSimon Glass self._node = node 39a06a34b2SSimon Glass self._offset = offset 40a06a34b2SSimon Glass self.name = name 41a06a34b2SSimon Glass self.value = None 42a06a34b2SSimon Glass 43c322a850SSimon Glass def GetPhandle(self): 44c322a850SSimon Glass """Get a (single) phandle value from a property 45c322a850SSimon Glass 46c322a850SSimon Glass Gets the phandle valuie from a property and returns it as an integer 47c322a850SSimon Glass """ 48c322a850SSimon Glass return fdt_util.fdt32_to_cpu(self.value[:4]) 49c322a850SSimon Glass 50c322a850SSimon Glass def Widen(self, newprop): 51c322a850SSimon Glass """Figure out which property type is more general 52c322a850SSimon Glass 53c322a850SSimon Glass Given a current property and a new property, this function returns the 54c322a850SSimon Glass one that is less specific as to type. The less specific property will 55c322a850SSimon Glass be ble to represent the data in the more specific property. This is 56c322a850SSimon Glass used for things like: 57c322a850SSimon Glass 58c322a850SSimon Glass node1 { 59c322a850SSimon Glass compatible = "fred"; 60c322a850SSimon Glass value = <1>; 61c322a850SSimon Glass }; 62c322a850SSimon Glass node1 { 63c322a850SSimon Glass compatible = "fred"; 64c322a850SSimon Glass value = <1 2>; 65c322a850SSimon Glass }; 66c322a850SSimon Glass 67c322a850SSimon Glass He we want to use an int array for 'value'. The first property 68c322a850SSimon Glass suggests that a single int is enough, but the second one shows that 69c322a850SSimon Glass it is not. Calling this function with these two propertes would 70c322a850SSimon Glass update the current property to be like the second, since it is less 71c322a850SSimon Glass specific. 72c322a850SSimon Glass """ 73c322a850SSimon Glass if newprop.type < self.type: 74c322a850SSimon Glass self.type = newprop.type 75c322a850SSimon Glass 76c322a850SSimon Glass if type(newprop.value) == list and type(self.value) != list: 77c322a850SSimon Glass self.value = [self.value] 78c322a850SSimon Glass 79c322a850SSimon Glass if type(self.value) == list and len(newprop.value) > len(self.value): 80c322a850SSimon Glass val = self.GetEmpty(self.type) 81c322a850SSimon Glass while len(self.value) < len(newprop.value): 82c322a850SSimon Glass self.value.append(val) 83c322a850SSimon Glass 84bc1dea36SSimon Glass def BytesToValue(self, bytes): 85bc1dea36SSimon Glass """Converts a string of bytes into a type and value 86bc1dea36SSimon Glass 87bc1dea36SSimon Glass Args: 88bc1dea36SSimon Glass A string containing bytes 89bc1dea36SSimon Glass 90bc1dea36SSimon Glass Return: 91bc1dea36SSimon Glass A tuple: 92bc1dea36SSimon Glass Type of data 93bc1dea36SSimon Glass Data, either a single element or a list of elements. Each element 94bc1dea36SSimon Glass is one of: 95bc1dea36SSimon Glass TYPE_STRING: string value from the property 96bc1dea36SSimon Glass TYPE_INT: a byte-swapped integer stored as a 4-byte string 97bc1dea36SSimon Glass TYPE_BYTE: a byte stored as a single-byte string 98bc1dea36SSimon Glass """ 99bc1dea36SSimon Glass size = len(bytes) 100bc1dea36SSimon Glass strings = bytes.split('\0') 101bc1dea36SSimon Glass is_string = True 102bc1dea36SSimon Glass count = len(strings) - 1 103bc1dea36SSimon Glass if count > 0 and not strings[-1]: 104bc1dea36SSimon Glass for string in strings[:-1]: 105bc1dea36SSimon Glass if not string: 106bc1dea36SSimon Glass is_string = False 107bc1dea36SSimon Glass break 108bc1dea36SSimon Glass for ch in string: 109bc1dea36SSimon Glass if ch < ' ' or ch > '~': 110bc1dea36SSimon Glass is_string = False 111bc1dea36SSimon Glass break 112bc1dea36SSimon Glass else: 113bc1dea36SSimon Glass is_string = False 114bc1dea36SSimon Glass if is_string: 115bc1dea36SSimon Glass if count == 1: 116bc1dea36SSimon Glass return TYPE_STRING, strings[0] 117bc1dea36SSimon Glass else: 118bc1dea36SSimon Glass return TYPE_STRING, strings[:-1] 119bc1dea36SSimon Glass if size % 4: 120bc1dea36SSimon Glass if size == 1: 121bc1dea36SSimon Glass return TYPE_BYTE, bytes[0] 122bc1dea36SSimon Glass else: 123bc1dea36SSimon Glass return TYPE_BYTE, list(bytes) 124bc1dea36SSimon Glass val = [] 125bc1dea36SSimon Glass for i in range(0, size, 4): 126bc1dea36SSimon Glass val.append(bytes[i:i + 4]) 127bc1dea36SSimon Glass if size == 4: 128bc1dea36SSimon Glass return TYPE_INT, val[0] 129bc1dea36SSimon Glass else: 130bc1dea36SSimon Glass return TYPE_INT, val 131bc1dea36SSimon Glass 132bc1dea36SSimon Glass def GetEmpty(self, type): 133bc1dea36SSimon Glass """Get an empty / zero value of the given type 134bc1dea36SSimon Glass 135bc1dea36SSimon Glass Returns: 136bc1dea36SSimon Glass A single value of the given type 137bc1dea36SSimon Glass """ 138bc1dea36SSimon Glass if type == TYPE_BYTE: 139bc1dea36SSimon Glass return chr(0) 140bc1dea36SSimon Glass elif type == TYPE_INT: 141bc1dea36SSimon Glass return struct.pack('<I', 0); 142bc1dea36SSimon Glass elif type == TYPE_STRING: 143bc1dea36SSimon Glass return '' 144bc1dea36SSimon Glass else: 145bc1dea36SSimon Glass return True 146bc1dea36SSimon Glass 147a06a34b2SSimon Glassclass NodeBase: 148a06a34b2SSimon Glass """A device tree node 149a06a34b2SSimon Glass 150a06a34b2SSimon Glass Properties: 151a06a34b2SSimon Glass offset: Integer offset in the device tree 152a06a34b2SSimon Glass name: Device tree node tname 153a06a34b2SSimon Glass path: Full path to node, along with the node name itself 154a06a34b2SSimon Glass _fdt: Device tree object 155a06a34b2SSimon Glass subnodes: A list of subnodes for this node, each a Node object 156a06a34b2SSimon Glass props: A dict of properties for this node, each a Prop object. 157a06a34b2SSimon Glass Keyed by property name 158a06a34b2SSimon Glass """ 159a06a34b2SSimon Glass def __init__(self, fdt, offset, name, path): 160a06a34b2SSimon Glass self._fdt = fdt 161a06a34b2SSimon Glass self._offset = offset 162a06a34b2SSimon Glass self.name = name 163a06a34b2SSimon Glass self.path = path 164a06a34b2SSimon Glass self.subnodes = [] 165a06a34b2SSimon Glass self.props = {} 166a06a34b2SSimon Glass 167f7a2aeeeSSimon Glass def _FindNode(self, name): 168f7a2aeeeSSimon Glass """Find a node given its name 169f7a2aeeeSSimon Glass 170f7a2aeeeSSimon Glass Args: 171f7a2aeeeSSimon Glass name: Node name to look for 172f7a2aeeeSSimon Glass Returns: 173f7a2aeeeSSimon Glass Node object if found, else None 174f7a2aeeeSSimon Glass """ 175f7a2aeeeSSimon Glass for subnode in self.subnodes: 176f7a2aeeeSSimon Glass if subnode.name == name: 177f7a2aeeeSSimon Glass return subnode 178f7a2aeeeSSimon Glass return None 179f7a2aeeeSSimon Glass 180f7a2aeeeSSimon Glass def Scan(self): 181f7a2aeeeSSimon Glass """Scan the subnodes of a node 182f7a2aeeeSSimon Glass 183f7a2aeeeSSimon Glass This should be implemented by subclasses 184f7a2aeeeSSimon Glass """ 185f7a2aeeeSSimon Glass raise NotImplementedError() 186f7a2aeeeSSimon Glass 187*2a70d897SSimon Glass def DeleteProp(self, prop_name): 188*2a70d897SSimon Glass """Delete a property of a node 189*2a70d897SSimon Glass 190*2a70d897SSimon Glass This should be implemented by subclasses 191*2a70d897SSimon Glass 192*2a70d897SSimon Glass Args: 193*2a70d897SSimon Glass prop_name: Name of the property to delete 194*2a70d897SSimon Glass """ 195*2a70d897SSimon Glass raise NotImplementedError() 196*2a70d897SSimon Glass 197a06a34b2SSimon Glassclass Fdt: 198a06a34b2SSimon Glass """Provides simple access to a flat device tree blob. 199a06a34b2SSimon Glass 200a06a34b2SSimon Glass Properties: 201a06a34b2SSimon Glass fname: Filename of fdt 202a06a34b2SSimon Glass _root: Root of device tree (a Node object) 203a06a34b2SSimon Glass """ 204a06a34b2SSimon Glass def __init__(self, fname): 205a06a34b2SSimon Glass self._fname = fname 206f7a2aeeeSSimon Glass 207f7a2aeeeSSimon Glass def Scan(self, root='/'): 208f7a2aeeeSSimon Glass """Scan a device tree, building up a tree of Node objects 209f7a2aeeeSSimon Glass 210f7a2aeeeSSimon Glass This fills in the self._root property 211f7a2aeeeSSimon Glass 212f7a2aeeeSSimon Glass Args: 213f7a2aeeeSSimon Glass root: Ignored 214f7a2aeeeSSimon Glass 215f7a2aeeeSSimon Glass TODO(sjg@chromium.org): Implement the 'root' parameter 216f7a2aeeeSSimon Glass """ 217f7a2aeeeSSimon Glass self._root = self.Node(self, 0, '/', '/') 218f7a2aeeeSSimon Glass self._root.Scan() 219f7a2aeeeSSimon Glass 220f7a2aeeeSSimon Glass def GetRoot(self): 221f7a2aeeeSSimon Glass """Get the root Node of the device tree 222f7a2aeeeSSimon Glass 223f7a2aeeeSSimon Glass Returns: 224f7a2aeeeSSimon Glass The root Node object 225f7a2aeeeSSimon Glass """ 226f7a2aeeeSSimon Glass return self._root 227f7a2aeeeSSimon Glass 228f7a2aeeeSSimon Glass def GetNode(self, path): 229f7a2aeeeSSimon Glass """Look up a node from its path 230f7a2aeeeSSimon Glass 231f7a2aeeeSSimon Glass Args: 232f7a2aeeeSSimon Glass path: Path to look up, e.g. '/microcode/update@0' 233f7a2aeeeSSimon Glass Returns: 234f7a2aeeeSSimon Glass Node object, or None if not found 235f7a2aeeeSSimon Glass """ 236f7a2aeeeSSimon Glass node = self._root 237f7a2aeeeSSimon Glass for part in path.split('/')[1:]: 238f7a2aeeeSSimon Glass node = node._FindNode(part) 239f7a2aeeeSSimon Glass if not node: 240f7a2aeeeSSimon Glass return None 241f7a2aeeeSSimon Glass return node 242f7a2aeeeSSimon Glass 243