Merge git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini
2016-07-15 08:06:22 -04:00
71 changed files with 2495 additions and 130 deletions

View File

@@ -107,6 +107,20 @@ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
# Build a libfdt Python module if swig is available
# Use 'sudo apt-get install swig libpython-dev' to enable this
hostprogs-$(CONFIG_SPL_OF_PLATDATA) += \
$(if $(shell which swig),_libfdt.so)
_libfdt.so-sharedobjs += $(LIBFDT_OBJS)
libfdt:
tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c
python $(srctree)/lib/libfdt/setup.py "$(_hostc_flags)" $^
mv _libfdt.so $@
tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig
swig -python -o $@ $<
# TODO(sjg@chromium.org): Is this correct on Mac OS?
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)

1
tools/dtoc/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.pyc

1
tools/dtoc/dtoc Symbolic link
View File

@@ -0,0 +1 @@
dtoc.py

394
tools/dtoc/dtoc.py Executable file
View File

@@ -0,0 +1,394 @@
#!/usr/bin/python
#
# Copyright (C) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
#
import copy
from optparse import OptionError, OptionParser
import os
import sys
import fdt_util
# Bring in the patman libraries
our_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(our_path, '../patman'))
# Bring in either the normal fdt library (which relies on libfdt) or the
# fallback one (which uses fdtget and is slower). Both provide the same
# interfface for this file to use.
try:
from fdt import Fdt
import fdt
have_libfdt = True
except ImportError:
have_libfdt = False
from fdt_fallback import Fdt
import fdt_fallback as fdt
import struct
# When we see these properties we ignore them - i.e. do not create a structure member
PROP_IGNORE_LIST = [
'#address-cells',
'#gpio-cells',
'#size-cells',
'compatible',
'linux,phandle',
"status",
'phandle',
'u-boot,dm-pre-reloc',
]
# C type declarations for the tyues we support
TYPE_NAMES = {
fdt_util.TYPE_INT: 'fdt32_t',
fdt_util.TYPE_BYTE: 'unsigned char',
fdt_util.TYPE_STRING: 'const char *',
fdt_util.TYPE_BOOL: 'bool',
};
STRUCT_PREFIX = 'dtd_'
VAL_PREFIX = 'dtv_'
def Conv_name_to_c(name):
"""Convert a device-tree name to a C identifier
Args:
name: Name to convert
Return:
String containing the C version of this name
"""
str = name.replace('@', '_at_')
str = str.replace('-', '_')
str = str.replace(',', '_')
str = str.replace('/', '__')
return str
def TabTo(num_tabs, str):
if len(str) >= num_tabs * 8:
return str + ' '
return str + '\t' * (num_tabs - len(str) / 8)
class DtbPlatdata:
"""Provide a means to convert device tree binary data to platform data
The output of this process is C structures which can be used in space-
constrained encvironments where the ~3KB code overhead of device tree
code is not affordable.
Properties:
fdt: Fdt object, referencing the device tree
_dtb_fname: Filename of the input device tree binary file
_valid_nodes: A list of Node object with compatible strings
_options: Command-line options
_phandle_node: A dict of nodes indexed by phandle number (1, 2...)
_outfile: The current output file (sys.stdout or a real file)
_lines: Stashed list of output lines for outputting in the future
_phandle_node: A dict of Nodes indexed by phandle (an integer)
"""
def __init__(self, dtb_fname, options):
self._dtb_fname = dtb_fname
self._valid_nodes = None
self._options = options
self._phandle_node = {}
self._outfile = None
self._lines = []
def SetupOutput(self, fname):
"""Set up the output destination
Once this is done, future calls to self.Out() will output to this
file.
Args:
fname: Filename to send output to, or '-' for stdout
"""
if fname == '-':
self._outfile = sys.stdout
else:
self._outfile = open(fname, 'w')
def Out(self, str):
"""Output a string to the output file
Args:
str: String to output
"""
self._outfile.write(str)
def Buf(self, str):
"""Buffer up a string to send later
Args:
str: String to add to our 'buffer' list
"""
self._lines.append(str)
def GetBuf(self):
"""Get the contents of the output buffer, and clear it
Returns:
The output buffer, which is then cleared for future use
"""
lines = self._lines
self._lines = []
return lines
def GetValue(self, type, value):
"""Get a value as a C expression
For integers this returns a byte-swapped (little-endian) hex string
For bytes this returns a hex string, e.g. 0x12
For strings this returns a literal string enclosed in quotes
For booleans this return 'true'
Args:
type: Data type (fdt_util)
value: Data value, as a string of bytes
"""
if type == fdt_util.TYPE_INT:
return '%#x' % fdt_util.fdt32_to_cpu(value)
elif type == fdt_util.TYPE_BYTE:
return '%#x' % ord(value[0])
elif type == fdt_util.TYPE_STRING:
return '"%s"' % value
elif type == fdt_util.TYPE_BOOL:
return 'true'
def GetCompatName(self, node):
"""Get a node's first compatible string as a C identifier
Args:
node: Node object to check
Return:
C identifier for the first compatible string
"""
compat = node.props['compatible'].value
if type(compat) == list:
compat = compat[0]
return Conv_name_to_c(compat)
def ScanDtb(self):
"""Scan the device tree to obtain a tree of notes and properties
Once this is done, self.fdt.GetRoot() can be called to obtain the
device tree root node, and progress from there.
"""
self.fdt = Fdt(self._dtb_fname)
self.fdt.Scan()
def ScanTree(self):
"""Scan the device tree for useful information
This fills in the following properties:
_phandle_node: A dict of Nodes indexed by phandle (an integer)
_valid_nodes: A list of nodes we wish to consider include in the
platform data
"""
node_list = []
self._phandle_node = {}
for node in self.fdt.GetRoot().subnodes:
if 'compatible' in node.props:
status = node.props.get('status')
if (not options.include_disabled and not status or
status.value != 'disabled'):
node_list.append(node)
phandle_prop = node.props.get('phandle')
if phandle_prop:
phandle = phandle_prop.GetPhandle()
self._phandle_node[phandle] = node
self._valid_nodes = node_list
def IsPhandle(self, prop):
"""Check if a node contains phandles
We have no reliable way of detecting whether a node uses a phandle
or not. As an interim measure, use a list of known property names.
Args:
prop: Prop object to check
Return:
True if the object value contains phandles, else False
"""
if prop.name in ['clocks']:
return True
return False
def ScanStructs(self):
"""Scan the device tree building up the C structures we will use.
Build a dict keyed by C struct name containing a dict of Prop
object for each struct field (keyed by property name). Where the
same struct appears multiple times, try to use the 'widest'
property, i.e. the one with a type which can express all others.
Once the widest property is determined, all other properties are
updated to match that width.
"""
structs = {}
for node in self._valid_nodes:
node_name = self.GetCompatName(node)
fields = {}
# Get a list of all the valid properties in this node.
for name, prop in node.props.iteritems():
if name not in PROP_IGNORE_LIST and name[0] != '#':
fields[name] = copy.deepcopy(prop)
# If we've seen this node_name before, update the existing struct.
if node_name in structs:
struct = structs[node_name]
for name, prop in fields.iteritems():
oldprop = struct.get(name)
if oldprop:
oldprop.Widen(prop)
else:
struct[name] = prop
# Otherwise store this as a new struct.
else:
structs[node_name] = fields
upto = 0
for node in self._valid_nodes:
node_name = self.GetCompatName(node)
struct = structs[node_name]
for name, prop in node.props.iteritems():
if name not in PROP_IGNORE_LIST and name[0] != '#':
prop.Widen(struct[name])
upto += 1
return structs
def GenerateStructs(self, structs):
"""Generate struct defintions for the platform data
This writes out the body of a header file consisting of structure
definitions for node in self._valid_nodes. See the documentation in
README.of-plat for more information.
"""
self.Out('#include <stdbool.h>\n')
self.Out('#include <libfdt.h>\n')
# Output the struct definition
for name in sorted(structs):
self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name));
for pname in sorted(structs[name]):
prop = structs[name][pname]
if self.IsPhandle(prop):
# For phandles, include a reference to the target
self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'),
Conv_name_to_c(prop.name),
len(prop.value) / 2))
else:
ptype = TYPE_NAMES[prop.type]
self.Out('\t%s%s' % (TabTo(2, ptype),
Conv_name_to_c(prop.name)))
if type(prop.value) == list:
self.Out('[%d]' % len(prop.value))
self.Out(';\n')
self.Out('};\n')
def GenerateTables(self):
"""Generate device defintions for the platform data
This writes out C platform data initialisation data and
U_BOOT_DEVICE() declarations for each valid node. See the
documentation in README.of-plat for more information.
"""
self.Out('#include <common.h>\n')
self.Out('#include <dm.h>\n')
self.Out('#include <dt-structs.h>\n')
self.Out('\n')
node_txt_list = []
for node in self._valid_nodes:
struct_name = self.GetCompatName(node)
var_name = Conv_name_to_c(node.name)
self.Buf('static struct %s%s %s%s = {\n' %
(STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
for pname, prop in node.props.iteritems():
if pname in PROP_IGNORE_LIST or pname[0] == '#':
continue
ptype = TYPE_NAMES[prop.type]
member_name = Conv_name_to_c(prop.name)
self.Buf('\t%s= ' % TabTo(3, '.' + member_name))
# Special handling for lists
if type(prop.value) == list:
self.Buf('{')
vals = []
# For phandles, output a reference to the platform data
# of the target node.
if self.IsPhandle(prop):
# Process the list as pairs of (phandle, id)
it = iter(prop.value)
for phandle_cell, id_cell in zip(it, it):
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
id = fdt_util.fdt32_to_cpu(id_cell)
target_node = self._phandle_node[phandle]
name = Conv_name_to_c(target_node.name)
vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id))
else:
for val in prop.value:
vals.append(self.GetValue(prop.type, val))
self.Buf(', '.join(vals))
self.Buf('}')
else:
self.Buf(self.GetValue(prop.type, prop.value))
self.Buf(',\n')
self.Buf('};\n')
# Add a device declaration
self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
self.Buf('\t.name\t\t= "%s",\n' % struct_name)
self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' %
(VAL_PREFIX, var_name))
self.Buf('};\n')
self.Buf('\n')
# Output phandle target nodes first, since they may be referenced
# by others
if 'phandle' in node.props:
self.Out(''.join(self.GetBuf()))
else:
node_txt_list.append(self.GetBuf())
# Output all the nodes which are not phandle targets themselves, but
# may reference them. This avoids the need for forward declarations.
for node_txt in node_txt_list:
self.Out(''.join(node_txt))
if __name__ != "__main__":
pass
parser = OptionParser()
parser.add_option('-d', '--dtb-file', action='store',
help='Specify the .dtb input file')
parser.add_option('--include-disabled', action='store_true',
help='Include disabled nodes')
parser.add_option('-o', '--output', action='store', default='-',
help='Select output filename')
(options, args) = parser.parse_args()
if not args:
raise ValueError('Please specify a command: struct, platdata')
plat = DtbPlatdata(options.dtb_file, options)
plat.ScanDtb()
plat.ScanTree()
plat.SetupOutput(options.output)
structs = plat.ScanStructs()
for cmd in args[0].split(','):
if cmd == 'struct':
plat.GenerateStructs(structs)
elif cmd == 'platdata':
plat.GenerateTables()
else:
raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd)

180
tools/dtoc/fdt.py Normal file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/python
#
# Copyright (C) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
#
import fdt_util
import libfdt
import sys
# This deals with a device tree, presenting it as a list of Node and Prop
# objects, representing nodes and properties, respectively.
#
# This implementation uses a libfdt Python library to access the device tree,
# so it is fairly efficient.
class Prop:
"""A device tree property
Properties:
name: Property name (as per the device tree)
value: Property value as a string of bytes, or a list of strings of
bytes
type: Value type
"""
def __init__(self, name, bytes):
self.name = name
self.value = None
if not bytes:
self.type = fdt_util.TYPE_BOOL
self.value = True
return
self.type, self.value = fdt_util.BytesToValue(bytes)
def GetPhandle(self):
"""Get a (single) phandle value from a property
Gets the phandle valuie from a property and returns it as an integer
"""
return fdt_util.fdt32_to_cpu(self.value[:4])
def Widen(self, newprop):
"""Figure out which property type is more general
Given a current property and a new property, this function returns the
one that is less specific as to type. The less specific property will
be ble to represent the data in the more specific property. This is
used for things like:
node1 {
compatible = "fred";
value = <1>;
};
node1 {
compatible = "fred";
value = <1 2>;
};
He we want to use an int array for 'value'. The first property
suggests that a single int is enough, but the second one shows that
it is not. Calling this function with these two propertes would
update the current property to be like the second, since it is less
specific.
"""
if newprop.type < self.type:
self.type = newprop.type
if type(newprop.value) == list and type(self.value) != list:
self.value = [self.value]
if type(self.value) == list and len(newprop.value) > len(self.value):
val = fdt_util.GetEmpty(self.type)
while len(self.value) < len(newprop.value):
self.value.append(val)
class Node:
"""A device tree node
Properties:
offset: Integer offset in the device tree
name: Device tree node tname
path: Full path to node, along with the node name itself
_fdt: Device tree object
subnodes: A list of subnodes for this node, each a Node object
props: A dict of properties for this node, each a Prop object.
Keyed by property name
"""
def __init__(self, fdt, offset, name, path):
self.offset = offset
self.name = name
self.path = path
self._fdt = fdt
self.subnodes = []
self.props = {}
def Scan(self):
"""Scan a node's properties and subnodes
This fills in the props and subnodes properties, recursively
searching into subnodes so that the entire tree is built.
"""
self.props = self._fdt.GetProps(self.path)
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset)
while offset >= 0:
sep = '' if self.path[-1] == '/' else '/'
name = libfdt.Name(self._fdt.GetFdt(), offset)
path = self.path + sep + name
node = Node(self._fdt, offset, name, path)
self.subnodes.append(node)
node.Scan()
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
class Fdt:
"""Provides simple access to a flat device tree blob.
Properties:
fname: Filename of fdt
_root: Root of device tree (a Node object)
"""
def __init__(self, fname):
self.fname = fname
with open(fname) as fd:
self._fdt = fd.read()
def GetFdt(self):
"""Get the contents of the FDT
Returns:
The FDT contents as a string of bytes
"""
return self._fdt
def Scan(self):
"""Scan a device tree, building up a tree of Node objects
This fills in the self._root property
"""
self._root = Node(self, 0, '/', '/')
self._root.Scan()
def GetRoot(self):
"""Get the root Node of the device tree
Returns:
The root Node object
"""
return self._root
def GetProps(self, node):
"""Get all properties from a node.
Args:
node: Full path to node name to look in.
Returns:
A dictionary containing all the properties, indexed by node name.
The entries are Prop objects.
Raises:
ValueError: if the node does not exist.
"""
offset = libfdt.fdt_path_offset(self._fdt, node)
if offset < 0:
libfdt.Raise(offset)
props_dict = {}
poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
while poffset >= 0:
dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop))
props_dict[prop.name] = prop
poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
return props_dict

207
tools/dtoc/fdt_fallback.py Normal file
View File

@@ -0,0 +1,207 @@
#!/usr/bin/python
#
# Copyright (C) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
#
import command
import fdt_util
import sys
# This deals with a device tree, presenting it as a list of Node and Prop
# objects, representing nodes and properties, respectively.
#
# This implementation uses the fdtget tool to access the device tree, so it
# is not very efficient for larger trees. The tool is called once for each
# node and property in the tree.
class Prop:
"""A device tree property
Properties:
name: Property name (as per the device tree)
value: Property value as a string of bytes, or a list of strings of
bytes
type: Value type
"""
def __init__(self, name, byte_list_str):
self.name = name
self.value = None
if not byte_list_str.strip():
self.type = fdt_util.TYPE_BOOL
return
bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')]
self.type, self.value = fdt_util.BytesToValue(''.join(bytes))
def GetPhandle(self):
"""Get a (single) phandle value from a property
Gets the phandle valuie from a property and returns it as an integer
"""
return fdt_util.fdt32_to_cpu(self.value[:4])
def Widen(self, newprop):
"""Figure out which property type is more general
Given a current property and a new property, this function returns the
one that is less specific as to type. The less specific property will
be ble to represent the data in the more specific property. This is
used for things like:
node1 {
compatible = "fred";
value = <1>;
};
node1 {
compatible = "fred";
value = <1 2>;
};
He we want to use an int array for 'value'. The first property
suggests that a single int is enough, but the second one shows that
it is not. Calling this function with these two propertes would
update the current property to be like the second, since it is less
specific.
"""
if newprop.type < self.type:
self.type = newprop.type
if type(newprop.value) == list and type(self.value) != list:
self.value = newprop.value
class Node:
"""A device tree node
Properties:
name: Device tree node tname
path: Full path to node, along with the node name itself
_fdt: Device tree object
subnodes: A list of subnodes for this node, each a Node object
props: A dict of properties for this node, each a Prop object.
Keyed by property name
"""
def __init__(self, fdt, name, path):
self.name = name
self.path = path
self._fdt = fdt
self.subnodes = []
self.props = {}
def Scan(self):
"""Scan a node's properties and subnodes
This fills in the props and subnodes properties, recursively
searching into subnodes so that the entire tree is built.
"""
for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
prop = Prop(name, byte_list_str)
self.props[name] = prop
for name in self._fdt.GetSubNodes(self.path):
sep = '' if self.path[-1] == '/' else '/'
path = self.path + sep + name
node = Node(self._fdt, name, path)
self.subnodes.append(node)
node.Scan()
class Fdt:
"""Provides simple access to a flat device tree blob.
Properties:
fname: Filename of fdt
_root: Root of device tree (a Node object)
"""
def __init__(self, fname):
self.fname = fname
def Scan(self):
"""Scan a device tree, building up a tree of Node objects
This fills in the self._root property
"""
self._root = Node(self, '/', '/')
self._root.Scan()
def GetRoot(self):
"""Get the root Node of the device tree
Returns:
The root Node object
"""
return self._root
def GetSubNodes(self, node):
"""Returns a list of sub-nodes of a given node
Args:
node: Node name to return children from
Returns:
List of children in the node (each a string node name)
Raises:
CmdError: if the node does not exist.
"""
out = command.Output('fdtget', self.fname, '-l', node)
return out.strip().splitlines()
def GetProps(self, node, convert_dashes=False):
"""Get all properties from a node
Args:
node: full path to node name to look in
convert_dashes: True to convert - to _ in node names
Returns:
A dictionary containing all the properties, indexed by node name.
The entries are simply strings - no decoding of lists or numbers
is done.
Raises:
CmdError: if the node does not exist.
"""
out = command.Output('fdtget', self.fname, node, '-p')
props = out.strip().splitlines()
props_dict = {}
for prop in props:
name = prop
if convert_dashes:
prop = re.sub('-', '_', prop)
props_dict[prop] = self.GetProp(node, name)
return props_dict
def GetProp(self, node, prop, default=None, typespec=None):
"""Get a property from a device tree.
This looks up the given node and property, and returns the value as a
string,
If the node or property does not exist, this will return the default
value.
Args:
node: Full path to node to look up.
prop: Property name to look up.
default: Default value to return if nothing is present in the fdt,
or None to raise in this case. This will be converted to a
string.
typespec: Type character to use (None for default, 's' for string)
Returns:
string containing the property value.
Raises:
CmdError: if the property does not exist and no default is provided.
"""
args = [self.fname, node, prop, '-t', 'bx']
if default is not None:
args += ['-d', str(default)]
if typespec is not None:
args += ['-t%s' % typespec]
out = command.Output('fdtget', *args)
return out.strip()

86
tools/dtoc/fdt_util.py Normal file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/python
#
# Copyright (C) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
#
import struct
# A list of types we support
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
def BytesToValue(bytes):
"""Converts a string of bytes into a type and value
Args:
A string containing bytes
Return:
A tuple:
Type of data
Data, either a single element or a list of elements. Each element
is one of:
TYPE_STRING: string value from the property
TYPE_INT: a byte-swapped integer stored as a 4-byte string
TYPE_BYTE: a byte stored as a single-byte string
"""
size = len(bytes)
strings = bytes.split('\0')
is_string = True
count = len(strings) - 1
if count > 0 and not strings[-1]:
for string in strings[:-1]:
if not string:
is_string = False
break
for ch in string:
if ch < ' ' or ch > '~':
is_string = False
break
else:
is_string = False
if is_string:
if count == 1:
return TYPE_STRING, strings[0]
else:
return TYPE_STRING, strings[:-1]
if size % 4:
if size == 1:
return TYPE_BYTE, bytes[0]
else:
return TYPE_BYTE, list(bytes)
val = []
for i in range(0, size, 4):
val.append(bytes[i:i + 4])
if size == 4:
return TYPE_INT, val[0]
else:
return TYPE_INT, val
def GetEmpty(type):
"""Get an empty / zero value of the given type
Returns:
A single value of the given type
"""
if type == TYPE_BYTE:
return chr(0)
elif type == TYPE_INT:
return struct.pack('<I', 0);
elif type == TYPE_STRING:
return ''
else:
return True
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]