u-boot/tools/dtoc/fdt_util.py
Simon Glass 4583c00236 patman: Move library functions into a library directory
The patman directory has a number of modules which are used by other tools
in U-Boot. This makes it hard to package the tools using pypi since the
common files must be copied along with the tool that uses them.

To address this, move these files into a new u_boot_pylib library. This
can be packaged separately and listed as a dependency of each tool.

Signed-off-by: Simon Glass <sjg@chromium.org>
2023-03-08 11:40:49 -08:00

331 lines
9.4 KiB
Python

#!/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):
"""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.get_output_filename('source.dts')
dtb_output = tools.get_output_filename('source.dtb')
search_paths = [os.path.join(os.getcwd(), 'include')]
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)