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 167*f7a2aeeeSSimon Glass def _FindNode(self, name): 168*f7a2aeeeSSimon Glass """Find a node given its name 169*f7a2aeeeSSimon Glass 170*f7a2aeeeSSimon Glass Args: 171*f7a2aeeeSSimon Glass name: Node name to look for 172*f7a2aeeeSSimon Glass Returns: 173*f7a2aeeeSSimon Glass Node object if found, else None 174*f7a2aeeeSSimon Glass """ 175*f7a2aeeeSSimon Glass for subnode in self.subnodes: 176*f7a2aeeeSSimon Glass if subnode.name == name: 177*f7a2aeeeSSimon Glass return subnode 178*f7a2aeeeSSimon Glass return None 179*f7a2aeeeSSimon Glass 180*f7a2aeeeSSimon Glass def Scan(self): 181*f7a2aeeeSSimon Glass """Scan the subnodes of a node 182*f7a2aeeeSSimon Glass 183*f7a2aeeeSSimon Glass This should be implemented by subclasses 184*f7a2aeeeSSimon Glass """ 185*f7a2aeeeSSimon Glass raise NotImplementedError() 186*f7a2aeeeSSimon Glass 187a06a34b2SSimon Glassclass Fdt: 188a06a34b2SSimon Glass """Provides simple access to a flat device tree blob. 189a06a34b2SSimon Glass 190a06a34b2SSimon Glass Properties: 191a06a34b2SSimon Glass fname: Filename of fdt 192a06a34b2SSimon Glass _root: Root of device tree (a Node object) 193a06a34b2SSimon Glass """ 194a06a34b2SSimon Glass def __init__(self, fname): 195a06a34b2SSimon Glass self._fname = fname 196*f7a2aeeeSSimon Glass 197*f7a2aeeeSSimon Glass def Scan(self, root='/'): 198*f7a2aeeeSSimon Glass """Scan a device tree, building up a tree of Node objects 199*f7a2aeeeSSimon Glass 200*f7a2aeeeSSimon Glass This fills in the self._root property 201*f7a2aeeeSSimon Glass 202*f7a2aeeeSSimon Glass Args: 203*f7a2aeeeSSimon Glass root: Ignored 204*f7a2aeeeSSimon Glass 205*f7a2aeeeSSimon Glass TODO(sjg@chromium.org): Implement the 'root' parameter 206*f7a2aeeeSSimon Glass """ 207*f7a2aeeeSSimon Glass self._root = self.Node(self, 0, '/', '/') 208*f7a2aeeeSSimon Glass self._root.Scan() 209*f7a2aeeeSSimon Glass 210*f7a2aeeeSSimon Glass def GetRoot(self): 211*f7a2aeeeSSimon Glass """Get the root Node of the device tree 212*f7a2aeeeSSimon Glass 213*f7a2aeeeSSimon Glass Returns: 214*f7a2aeeeSSimon Glass The root Node object 215*f7a2aeeeSSimon Glass """ 216*f7a2aeeeSSimon Glass return self._root 217*f7a2aeeeSSimon Glass 218*f7a2aeeeSSimon Glass def GetNode(self, path): 219*f7a2aeeeSSimon Glass """Look up a node from its path 220*f7a2aeeeSSimon Glass 221*f7a2aeeeSSimon Glass Args: 222*f7a2aeeeSSimon Glass path: Path to look up, e.g. '/microcode/update@0' 223*f7a2aeeeSSimon Glass Returns: 224*f7a2aeeeSSimon Glass Node object, or None if not found 225*f7a2aeeeSSimon Glass """ 226*f7a2aeeeSSimon Glass node = self._root 227*f7a2aeeeSSimon Glass for part in path.split('/')[1:]: 228*f7a2aeeeSSimon Glass node = node._FindNode(part) 229*f7a2aeeeSSimon Glass if not node: 230*f7a2aeeeSSimon Glass return None 231*f7a2aeeeSSimon Glass return node 232*f7a2aeeeSSimon Glass 233