diff options
Diffstat (limited to 'tools/dtoc/fdt_util.py')
-rw-r--r-- | tools/dtoc/fdt_util.py | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py new file mode 100644 index 00000000000..d5ecc4207d8 --- /dev/null +++ b/tools/dtoc/fdt_util.py @@ -0,0 +1,334 @@ +#!/usr/bin/python +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# + +# Utility functions for reading from a device tree. Once the upstream pylibfdt +# implementation advances far enough, we should be able to drop these. + +import os +import struct +import sys +import tempfile + +from u_boot_pylib import command +from u_boot_pylib import tools + +def fdt32_to_cpu(val): + """Convert a device tree cell to an integer + + Args: + Value to convert (4-character string representing the cell value) + + Return: + A native-endian integer value + """ + return struct.unpack('>I', val)[0] + +def fdt64_to_cpu(val): + """Convert a device tree cell to an integer + + Args: + val (list): Value to convert (list of 2 4-character strings representing + the cell value) + + Return: + int: A native-endian integer value + """ + return fdt32_to_cpu(val[0]) << 32 | fdt32_to_cpu(val[1]) + +def fdt_cells_to_cpu(val, cells): + """Convert one or two cells to a long integer + + Args: + Value to convert (array of one or more 4-character strings) + + Return: + A native-endian integer value + """ + if not cells: + return 0 + out = int(fdt32_to_cpu(val[0])) + if cells == 2: + out = out << 32 | fdt32_to_cpu(val[1]) + return out + +def EnsureCompiled(fname, tmpdir=None, capture_stderr=False, indir=None): + """Compile an fdt .dts source file into a .dtb binary blob if needed. + + Args: + fname: Filename (if .dts it will be compiled). It not it will be + left alone + tmpdir: Temporary directory for output files, or None to use the + tools-module output directory + indir: List of directories where input files can be found + + Returns: + Filename of resulting .dtb file + """ + _, ext = os.path.splitext(fname) + if ext != '.dts': + return fname + + if tmpdir: + dts_input = os.path.join(tmpdir, 'source.dts') + dtb_output = os.path.join(tmpdir, 'source.dtb') + else: + dts_input = tools.get_output_filename('source.dts') + dtb_output = tools.get_output_filename('source.dtb') + + search_paths = [os.path.join(os.getcwd(), 'include')] + if indir is not None: + search_paths += indir + root, _ = os.path.splitext(fname) + cc, args = tools.get_target_compile_tool('cc') + args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] + args += ['-Ulinux'] + for path in search_paths: + args.extend(['-I', path]) + args += ['-o', dts_input, fname] + command.run(cc, *args) + + # If we don't have a directory, put it in the tools tempdir + search_list = [] + for path in search_paths: + search_list.extend(['-i', path]) + dtc, args = tools.get_target_compile_tool('dtc') + args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb', + '-W', 'no-unit_address_vs_reg'] + args.extend(search_list) + args.append(dts_input) + command.run(dtc, *args, capture_stderr=capture_stderr) + return dtb_output + +def GetInt(node, propname, default=None): + """Get an integer from a property + + Args: + node: Node object to read from + propname: property name to read + default: Default value to use if the node/property do not exist + + Returns: + Integer value read, or default if none + """ + prop = node.props.get(propname) + if not prop: + return default + if isinstance(prop.value, list): + raise ValueError("Node '%s' property '%s' has list value: expecting " + "a single integer" % (node.name, propname)) + value = fdt32_to_cpu(prop.value) + return value + +def GetInt64(node, propname, default=None): + """Get a 64-bit integer from a property + + Args: + node (Node): Node object to read from + propname (str): property name to read + default (int): Default value to use if the node/property do not exist + + Returns: + int: value read, or default if none + + Raises: + ValueError: Property is not of the correct size + """ + prop = node.props.get(propname) + if not prop: + return default + if not isinstance(prop.value, list) or len(prop.value) != 2: + raise ValueError("Node '%s' property '%s' should be a list with 2 items for 64-bit values" % + (node.name, propname)) + value = fdt64_to_cpu(prop.value) + return value + +def GetString(node, propname, default=None): + """Get a string from a property + + Args: + node: Node object to read from + propname: property name to read + default: Default value to use if the node/property do not exist + + Returns: + String value read, or default if none + """ + prop = node.props.get(propname) + if not prop: + return default + value = prop.value + if not prop.bytes: + return '' + if isinstance(value, list): + raise ValueError("Node '%s' property '%s' has list value: expecting " + "a single string" % (node.name, propname)) + return value + +def GetStringList(node, propname, default=None): + """Get a string list from a property + + Args: + node (Node): Node object to read from + propname (str): property name to read + default (list of str): Default value to use if the node/property do not + exist, or None + + Returns: + String value read, or default if none + """ + prop = node.props.get(propname) + if not prop: + return default + value = prop.value + if not prop.bytes: + return [] + if not isinstance(value, list): + strval = GetString(node, propname) + return [strval] + return value + +def GetArgs(node, propname): + prop = node.props.get(propname) + if not prop: + raise ValueError(f"Node '{node.path}': Expected property '{propname}'") + if prop.bytes: + value = GetStringList(node, propname) + else: + value = [] + if not value: + args = [] + elif len(value) == 1: + args = value[0].split() + else: + args = value + return args + +def GetBool(node, propname, default=False): + """Get an boolean from a property + + Args: + node: Node object to read from + propname: property name to read + default: Default value to use if the node/property do not exist + + Returns: + Boolean value read, or default if none (if you set this to True the + function will always return True) + """ + if propname in node.props: + return True + return default + +def GetByte(node, propname, default=None): + """Get an byte from a property + + Args: + node: Node object to read from + propname: property name to read + default: Default value to use if the node/property do not exist + + Returns: + Byte value read, or default if none + """ + prop = node.props.get(propname) + if not prop: + return default + value = prop.value + if isinstance(value, list): + raise ValueError("Node '%s' property '%s' has list value: expecting " + "a single byte" % (node.name, propname)) + if len(value) != 1: + raise ValueError("Node '%s' property '%s' has length %d, expecting %d" % + (node.name, propname, len(value), 1)) + return ord(value[0]) + +def GetBytes(node, propname, size, default=None): + """Get a set of bytes from a property + + Args: + node (Node): Node object to read from + propname (str): property name to read + size (int): Number of bytes to expect + default (bytes): Default value or None + + Returns: + bytes: Bytes value read, or default if none + """ + prop = node.props.get(propname) + if not prop: + return default + if len(prop.bytes) != size: + raise ValueError("Node '%s' property '%s' has length %d, expecting %d" % + (node.name, propname, len(prop.bytes), size)) + return prop.bytes + +def GetPhandleList(node, propname): + """Get a list of phandles from a property + + Args: + node: Node object to read from + propname: property name to read + + Returns: + List of phandles read, each an integer + """ + prop = node.props.get(propname) + if not prop: + return None + value = prop.value + if not isinstance(value, list): + value = [value] + return [fdt32_to_cpu(v) for v in value] + +def GetPhandleNameOffset(node, propname): + """Get a <&phandle>, "string", <offset> value from a property + + Args: + node: Node object to read from + propname: property name to read + + Returns: + tuple: + Node object + str + int + or None if the property does not exist + """ + prop = node.props.get(propname) + if not prop: + return None + value = prop.bytes + phandle = fdt32_to_cpu(value[:4]) + node = node.GetFdt().LookupPhandle(phandle) + name = '' + for byte in value[4:]: + if not byte: + break + name += chr(byte) + val = fdt32_to_cpu(value[4 + len(name) + 1:]) + return node, name, val + +def GetDatatype(node, propname, datatype): + """Get a value of a given type from a property + + Args: + node: Node object to read from + propname: property name to read + datatype: Type to read (str or int) + + Returns: + value read, or None if none + + Raises: + ValueError if datatype is not str or int + """ + if datatype == str: + return GetString(node, propname) + elif datatype == int: + return GetInt(node, propname) + raise ValueError("fdt_util internal error: Unknown data type '%s'" % + datatype) |