| #!/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 | |
| import command | |
| 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 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): | |
| """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 | |
| 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.GetOutputFilename('source.dts') | |
| dtb_output = tools.GetOutputFilename('source.dtb') | |
| search_paths = [os.path.join(os.getcwd(), 'include')] | |
| root, _ = os.path.splitext(fname) | |
| 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]) | |
| args = ['-I', 'dts', '-o', dtb_output, '-O', 'dtb', | |
| '-W', 'no-unit_address_vs_reg'] | |
| args.extend(search_list) | |
| args.append(dts_input) | |
| dtc = os.environ.get('DTC') or 'dtc' | |
| 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 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 isinstance(value, list): | |
| raise ValueError("Node '%s' property '%s' has list value: expecting " | |
| "a single string" % (node.name, propname)) | |
| return value | |
| 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 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 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) |