fdthelper.py revision 13719
112800Sgiacomo.travaglini@arm.com# Copyright (c) 2016 ARM Limited 212800Sgiacomo.travaglini@arm.com# All rights reserved. 312800Sgiacomo.travaglini@arm.com# 412800Sgiacomo.travaglini@arm.com# The license below extends only to copyright in the software and shall 512800Sgiacomo.travaglini@arm.com# not be construed as granting a license to any other intellectual 612800Sgiacomo.travaglini@arm.com# property including but not limited to intellectual property relating 712800Sgiacomo.travaglini@arm.com# to a hardware implementation of the functionality of the software 812800Sgiacomo.travaglini@arm.com# licensed hereunder. You may use the software subject to the license 912800Sgiacomo.travaglini@arm.com# terms below provided that you ensure that this notice is replicated 1012800Sgiacomo.travaglini@arm.com# unmodified and in its entirety in all distributions of the software, 1112800Sgiacomo.travaglini@arm.com# modified or unmodified, in source code or in binary form. 1212800Sgiacomo.travaglini@arm.com# 1312800Sgiacomo.travaglini@arm.com# Redistribution and use in source and binary forms, with or without 1412800Sgiacomo.travaglini@arm.com# modification, are permitted provided that the following conditions are 1512800Sgiacomo.travaglini@arm.com# met: redistributions of source code must retain the above copyright 1612800Sgiacomo.travaglini@arm.com# notice, this list of conditions and the following disclaimer; 1712800Sgiacomo.travaglini@arm.com# redistributions in binary form must reproduce the above copyright 1812800Sgiacomo.travaglini@arm.com# notice, this list of conditions and the following disclaimer in the 1912800Sgiacomo.travaglini@arm.com# documentation and/or other materials provided with the distribution; 2012800Sgiacomo.travaglini@arm.com# neither the name of the copyright holders nor the names of its 2112800Sgiacomo.travaglini@arm.com# contributors may be used to endorse or promote products derived from 2212800Sgiacomo.travaglini@arm.com# this software without specific prior written permission. 2312800Sgiacomo.travaglini@arm.com# 2412800Sgiacomo.travaglini@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2512800Sgiacomo.travaglini@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2612800Sgiacomo.travaglini@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2712800Sgiacomo.travaglini@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2812800Sgiacomo.travaglini@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2912800Sgiacomo.travaglini@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3012800Sgiacomo.travaglini@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3112800Sgiacomo.travaglini@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3212800Sgiacomo.travaglini@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3312800Sgiacomo.travaglini@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3412800Sgiacomo.travaglini@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3512800Sgiacomo.travaglini@arm.com# 3612800Sgiacomo.travaglini@arm.com# Author: Glenn Bergmans 3712800Sgiacomo.travaglini@arm.com 3812800Sgiacomo.travaglini@arm.comimport six 3912800Sgiacomo.travaglini@arm.comif six.PY3: 4012800Sgiacomo.travaglini@arm.com long = int 4112800Sgiacomo.travaglini@arm.com 4212800Sgiacomo.travaglini@arm.comfrom m5.ext.pyfdt import pyfdt 4312800Sgiacomo.travaglini@arm.comimport re 4412800Sgiacomo.travaglini@arm.comimport os 4512800Sgiacomo.travaglini@arm.comfrom m5.SimObject import SimObject 4612800Sgiacomo.travaglini@arm.com 4712800Sgiacomo.travaglini@arm.comclass FdtProperty(pyfdt.FdtProperty): 4812800Sgiacomo.travaglini@arm.com """Create a property without values.""" 4912800Sgiacomo.travaglini@arm.com pass 5012800Sgiacomo.travaglini@arm.com 5112800Sgiacomo.travaglini@arm.comclass FdtPropertyWords(pyfdt.FdtPropertyWords): 5212800Sgiacomo.travaglini@arm.com """Create a property with word (32-bit unsigned) values.""" 5312800Sgiacomo.travaglini@arm.com def __init__(self, name, words): 5412800Sgiacomo.travaglini@arm.com if type(words) != list: 5512800Sgiacomo.travaglini@arm.com words = [words] 5612800Sgiacomo.travaglini@arm.com # Make sure all values are ints (use automatic base detection if the 5712800Sgiacomo.travaglini@arm.com # type is str) 5812800Sgiacomo.travaglini@arm.com words = [long(w, base=0) if type(w) == str else long(w) for w in words] 5912800Sgiacomo.travaglini@arm.com super(FdtPropertyWords, self).__init__(name, words) 6012800Sgiacomo.travaglini@arm.com 6112800Sgiacomo.travaglini@arm.comclass FdtPropertyStrings(pyfdt.FdtPropertyStrings): 6212800Sgiacomo.travaglini@arm.com """Create a property with string values.""" 6312800Sgiacomo.travaglini@arm.com 6412800Sgiacomo.travaglini@arm.com def __init__(self, name, strings): 6512800Sgiacomo.travaglini@arm.com if type(strings) == str: 6612800Sgiacomo.travaglini@arm.com strings = [strings] 6712800Sgiacomo.travaglini@arm.com strings = [str(string) for string in strings] # Make all values strings 6812800Sgiacomo.travaglini@arm.com super(FdtPropertyStrings, self).__init__(name, strings) 6912800Sgiacomo.travaglini@arm.com 7012800Sgiacomo.travaglini@arm.comclass FdtPropertyBytes(pyfdt.FdtPropertyBytes): 7112800Sgiacomo.travaglini@arm.com """Create a property with integer (8-bit signed) values.""" 7212800Sgiacomo.travaglini@arm.com 7312800Sgiacomo.travaglini@arm.com def __init__(self, name, values): 7412800Sgiacomo.travaglini@arm.com if type(values) != list: 7512800Sgiacomo.travaglini@arm.com values = [values] 7612800Sgiacomo.travaglini@arm.com # Make sure all values are ints (use automatic base detection if the 7712800Sgiacomo.travaglini@arm.com # type is str) 7812800Sgiacomo.travaglini@arm.com values = [int(v, base=0) 7912800Sgiacomo.travaglini@arm.com if isinstance(v, str) else int(v) for v in values] 8012800Sgiacomo.travaglini@arm.com super(FdtPropertyBytes, self).__init__(name, values) 8112800Sgiacomo.travaglini@arm.com 8212800Sgiacomo.travaglini@arm.comclass FdtState(object): 8312800Sgiacomo.travaglini@arm.com """Class for maintaining state while recursively generating a flattened 8412800Sgiacomo.travaglini@arm.com device tree. The state tracks address, size and CPU address cell sizes, and 8512800Sgiacomo.travaglini@arm.com maintains a dictionary of allocated phandles.""" 8612800Sgiacomo.travaglini@arm.com 8712800Sgiacomo.travaglini@arm.com phandle_counter = 0 8812800Sgiacomo.travaglini@arm.com phandles = dict() 8912800Sgiacomo.travaglini@arm.com 9012800Sgiacomo.travaglini@arm.com def __init__(self, addr_cells, size_cells, cpu_cells): 9112800Sgiacomo.travaglini@arm.com """Instantiate values of this state. The state can only be initialized 9212800Sgiacomo.travaglini@arm.com once.""" 9312800Sgiacomo.travaglini@arm.com 9412800Sgiacomo.travaglini@arm.com self.addr_cells = addr_cells 9512800Sgiacomo.travaglini@arm.com self.size_cells = size_cells 9612800Sgiacomo.travaglini@arm.com self.cpu_cells = cpu_cells 9712800Sgiacomo.travaglini@arm.com 9812800Sgiacomo.travaglini@arm.com def phandle(self, obj): 9912800Sgiacomo.travaglini@arm.com """Return a unique phandle number for a key. The key can be a SimObject 10012800Sgiacomo.travaglini@arm.com or any value that is castable to a string. If the phandle doesn't exist 10112800Sgiacomo.travaglini@arm.com a new one is created, otherwise the existing one is returned.""" 10212800Sgiacomo.travaglini@arm.com 10312800Sgiacomo.travaglini@arm.com if isinstance(obj, SimObject): 10412800Sgiacomo.travaglini@arm.com key = str(id(obj)) 10512800Sgiacomo.travaglini@arm.com else: 10612800Sgiacomo.travaglini@arm.com try: 10712800Sgiacomo.travaglini@arm.com key = str(obj) 10812800Sgiacomo.travaglini@arm.com except ValueError: 10912800Sgiacomo.travaglini@arm.com raise ValueError('Phandle keys must be castable to str') 11012800Sgiacomo.travaglini@arm.com 11112800Sgiacomo.travaglini@arm.com if not key in FdtState.phandles: 11212800Sgiacomo.travaglini@arm.com FdtState.phandle_counter += 1 11312800Sgiacomo.travaglini@arm.com 11412800Sgiacomo.travaglini@arm.com return FdtState.phandles.setdefault(key, FdtState.phandle_counter) 11512800Sgiacomo.travaglini@arm.com 11612800Sgiacomo.travaglini@arm.com def resetPhandles(self): 11712800Sgiacomo.travaglini@arm.com FdtState.phandle_counter = 0 11812800Sgiacomo.travaglini@arm.com FdtState.phandles = dict() 11912800Sgiacomo.travaglini@arm.com 12012800Sgiacomo.travaglini@arm.com def int_to_cells(self, value, cells): 12112800Sgiacomo.travaglini@arm.com """Helper function for: generates a list of 32 bit cells from an int, 12212800Sgiacomo.travaglini@arm.com used to split up addresses in appropriate 32 bit chunks.""" 12312800Sgiacomo.travaglini@arm.com value = long(value) 12412800Sgiacomo.travaglini@arm.com 12512800Sgiacomo.travaglini@arm.com if (value >> (32 * cells)) != 0: 12612800Sgiacomo.travaglini@arm.com fatal("Value %d doesn't fit in %d cells" % (value, cells)) 12712800Sgiacomo.travaglini@arm.com 12812800Sgiacomo.travaglini@arm.com return [(value >> 32*(x-1)) & 0xFFFFFFFF for x in range(cells, 0, -1)] 12912800Sgiacomo.travaglini@arm.com 13012800Sgiacomo.travaglini@arm.com def addrCells(self, addr): 13112800Sgiacomo.travaglini@arm.com """Format an integer type according to the address_cells value of this 13212800Sgiacomo.travaglini@arm.com state.""" 13312800Sgiacomo.travaglini@arm.com return self.int_to_cells(addr, self.addr_cells) 13412800Sgiacomo.travaglini@arm.com 13512800Sgiacomo.travaglini@arm.com def CPUAddrCells(self, addr): 13612800Sgiacomo.travaglini@arm.com """Format an integer type according to the cpu_cells value of this 13712800Sgiacomo.travaglini@arm.com state.""" 13812800Sgiacomo.travaglini@arm.com return self.int_to_cells(addr, self.cpu_cells) 13912800Sgiacomo.travaglini@arm.com 14012800Sgiacomo.travaglini@arm.com def sizeCells(self, size): 14112800Sgiacomo.travaglini@arm.com """Format an integer type according to the size_cells value of this 14212800Sgiacomo.travaglini@arm.com state.""" 14312800Sgiacomo.travaglini@arm.com return self.int_to_cells(size, self.size_cells) 14412800Sgiacomo.travaglini@arm.com 14512800Sgiacomo.travaglini@arm.com def addrCellsProperty(self): 14612800Sgiacomo.travaglini@arm.com """Return an #address-cells property with the value of this state.""" 14712800Sgiacomo.travaglini@arm.com return FdtPropertyWords("#address-cells", self.addr_cells) 14812800Sgiacomo.travaglini@arm.com 14912800Sgiacomo.travaglini@arm.com def sizeCellsProperty(self): 15012800Sgiacomo.travaglini@arm.com """Return an #size-cells property with the value of this state.""" 15112800Sgiacomo.travaglini@arm.com return FdtPropertyWords("#size-cells", self.size_cells) 15212800Sgiacomo.travaglini@arm.com 15312800Sgiacomo.travaglini@arm.com def CPUCellsProperty(self): 15412800Sgiacomo.travaglini@arm.com """Return an #address-cells property for cpu nodes with the value 15512800Sgiacomo.travaglini@arm.com of this state.""" 15612800Sgiacomo.travaglini@arm.com return FdtPropertyWords("#address-cells", self.cpu_cells) 15712800Sgiacomo.travaglini@arm.com 15812800Sgiacomo.travaglini@arm.comclass FdtNop(pyfdt.FdtNop): 15912800Sgiacomo.travaglini@arm.com """Create an empty node.""" 16012800Sgiacomo.travaglini@arm.com pass 16112800Sgiacomo.travaglini@arm.com 16212800Sgiacomo.travaglini@arm.comclass FdtNode(pyfdt.FdtNode): 16312800Sgiacomo.travaglini@arm.com def __init__(self, name, obj=None): 16414067SMichiel.VanTol@arm.com """Create a new node and immediately set the phandle property, if obj 16514067SMichiel.VanTol@arm.com is supplied""" 16614067SMichiel.VanTol@arm.com super(FdtNode, self).__init__(name) 16714067SMichiel.VanTol@arm.com if obj != None: 16812800Sgiacomo.travaglini@arm.com self.appendPhandle(obj) 16912800Sgiacomo.travaglini@arm.com 17014067SMichiel.VanTol@arm.com def append(self, subnodes): 17114067SMichiel.VanTol@arm.com """Change the behavior of the normal append to override if a node with 17212800Sgiacomo.travaglini@arm.com the same name already exists or merge if the name exists and is a node 17314067SMichiel.VanTol@arm.com type. Can also take a list of subnodes, that each get appended.""" 17412800Sgiacomo.travaglini@arm.com if not hasattr(subnodes, '__iter__'): 17512800Sgiacomo.travaglini@arm.com subnodes = [subnodes] 17614067SMichiel.VanTol@arm.com 17714067SMichiel.VanTol@arm.com for subnode in subnodes: 17814067SMichiel.VanTol@arm.com try: 17912800Sgiacomo.travaglini@arm.com if not issubclass(type(subnode), pyfdt.FdtNop): 18012800Sgiacomo.travaglini@arm.com index = self.index(subnode.name) 18112800Sgiacomo.travaglini@arm.com item = self.pop(index) 18212800Sgiacomo.travaglini@arm.com else: 18312800Sgiacomo.travaglini@arm.com item = None 18412800Sgiacomo.travaglini@arm.com except ValueError: 18512800Sgiacomo.travaglini@arm.com item = None 18612800Sgiacomo.travaglini@arm.com 18712800Sgiacomo.travaglini@arm.com if isinstance(item, pyfdt.FdtNode) and \ 18812800Sgiacomo.travaglini@arm.com isinstance(subnode, pyfdt.FdtNode): 18912800Sgiacomo.travaglini@arm.com item.merge(subnode) 19012800Sgiacomo.travaglini@arm.com subnode = item 19112800Sgiacomo.travaglini@arm.com 19212800Sgiacomo.travaglini@arm.com super(FdtNode, self).append(subnode) 19312800Sgiacomo.travaglini@arm.com 19412800Sgiacomo.travaglini@arm.com def appendList(self, subnode_list): 19512800Sgiacomo.travaglini@arm.com """Append all properties/nodes in the iterable.""" 19612800Sgiacomo.travaglini@arm.com for subnode in subnode_list: 19712800Sgiacomo.travaglini@arm.com self.append(subnode) 19812800Sgiacomo.travaglini@arm.com 19912800Sgiacomo.travaglini@arm.com def appendCompatible(self, compatible): 20012800Sgiacomo.travaglini@arm.com """Append a compatible property with the supplied compatibility 20112800Sgiacomo.travaglini@arm.com strings.""" 20212800Sgiacomo.travaglini@arm.com if isinstance(compatible, str): 20312800Sgiacomo.travaglini@arm.com compatible = [compatible] 20412800Sgiacomo.travaglini@arm.com self.append(FdtPropertyStrings('compatible', compatible)) 20512800Sgiacomo.travaglini@arm.com 20612800Sgiacomo.travaglini@arm.com def appendPhandle(self, obj): 20712800Sgiacomo.travaglini@arm.com """Append a phandle property to this node with the phandle of the 20812800Sgiacomo.travaglini@arm.com supplied object.""" 20912800Sgiacomo.travaglini@arm.com # Create a bogus state because we only need the Phandle dictionary 21012800Sgiacomo.travaglini@arm.com state = FdtState(addr_cells=1, size_cells=1, cpu_cells=1) 21112800Sgiacomo.travaglini@arm.com 21212800Sgiacomo.travaglini@arm.com phandle = state.phandle(obj) 21312800Sgiacomo.travaglini@arm.com self.append(FdtPropertyWords("phandle", [phandle])) 21412800Sgiacomo.travaglini@arm.com 21512800Sgiacomo.travaglini@arm.comclass Fdt(pyfdt.Fdt): 21612800Sgiacomo.travaglini@arm.com def sortNodes(self, node): 21712800Sgiacomo.travaglini@arm.com """Move all properties to the beginning and subnodes to the end 21812800Sgiacomo.travaglini@arm.com while maintaining the order of the subnodes. DTB files require the 21912800Sgiacomo.travaglini@arm.com properties to go before the nodes, but the PyFdt doesn't account for 22012800Sgiacomo.travaglini@arm.com defining nodes and properties in a random order.""" 22112800Sgiacomo.travaglini@arm.com properties = FdtNode(node.name) 22212800Sgiacomo.travaglini@arm.com subnodes = FdtNode(node.name) 22312800Sgiacomo.travaglini@arm.com 22412800Sgiacomo.travaglini@arm.com while len(node): 22512800Sgiacomo.travaglini@arm.com subnode = node.pop(0) 22612800Sgiacomo.travaglini@arm.com if issubclass(type(subnode), pyfdt.FdtNode): 22712800Sgiacomo.travaglini@arm.com subnode = self.sortNodes(subnode) 22812800Sgiacomo.travaglini@arm.com subnodes.append(subnode) 22912800Sgiacomo.travaglini@arm.com else: 23012800Sgiacomo.travaglini@arm.com properties.append(subnode) 23112800Sgiacomo.travaglini@arm.com 23212800Sgiacomo.travaglini@arm.com properties.merge(subnodes) 23312800Sgiacomo.travaglini@arm.com 23412800Sgiacomo.travaglini@arm.com return properties 23512800Sgiacomo.travaglini@arm.com 23612800Sgiacomo.travaglini@arm.com def add_rootnode(self, rootnode, prenops=None, postnops=None): 23712800Sgiacomo.travaglini@arm.com """First sort the device tree, so that properties are before nodes.""" 23812800Sgiacomo.travaglini@arm.com rootnode = self.sortNodes(rootnode) 23912800Sgiacomo.travaglini@arm.com super(Fdt, self).add_rootnode(rootnode, prenops, postnops) 24012800Sgiacomo.travaglini@arm.com 24112800Sgiacomo.travaglini@arm.com def writeDtbFile(self, filename): 24212800Sgiacomo.travaglini@arm.com """Convert the device tree to DTB and write to a file.""" 24312800Sgiacomo.travaglini@arm.com filename = os.path.realpath(filename) 24412800Sgiacomo.travaglini@arm.com try: 24512800Sgiacomo.travaglini@arm.com with open(filename, 'wb') as f: 24612800Sgiacomo.travaglini@arm.com f.write(self.to_dtb()) 24712800Sgiacomo.travaglini@arm.com return filename 24812800Sgiacomo.travaglini@arm.com except IOError: 24912800Sgiacomo.travaglini@arm.com raise RuntimeError("Failed to open DTB output file") 25012800Sgiacomo.travaglini@arm.com 25112800Sgiacomo.travaglini@arm.com def writeDtsFile(self, filename): 25212800Sgiacomo.travaglini@arm.com """Convert the device tree to DTS and write to a file.""" 25312800Sgiacomo.travaglini@arm.com filename = os.path.realpath(filename) 25412800Sgiacomo.travaglini@arm.com try: 25512800Sgiacomo.travaglini@arm.com with open(filename, 'w') as f: 25612800Sgiacomo.travaglini@arm.com f.write(self.to_dts()) 25712800Sgiacomo.travaglini@arm.com return filename 25812800Sgiacomo.travaglini@arm.com except IOError: 25912800Sgiacomo.travaglini@arm.com raise RuntimeError("Failed to open DTS output file") 26012800Sgiacomo.travaglini@arm.com