mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-25 13:14:19 +08:00
dtoc: Allow syncing of the device tree back to a file
At present we require the caller to manually update the device tree using individual calls to libfdt functions. This is not ideal. It would be better if we could make changes using the Python structure and then call a Sync() function to write them back. Add this feature to the Fdt class. Update binman and the tests to match. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
0bfa7b09ba
commit
fa80c25c09
@ -183,6 +183,7 @@ def Binman(options, args):
|
||||
image.AddMissingProperties()
|
||||
image.ProcessFdt(dtb)
|
||||
|
||||
dtb.Sync(auto_resize=True)
|
||||
dtb.Pack()
|
||||
dtb.Flush()
|
||||
|
||||
@ -199,6 +200,7 @@ def Binman(options, args):
|
||||
image.SetImagePos()
|
||||
if options.update_fdt:
|
||||
image.SetCalculatedProperties()
|
||||
dtb.Sync()
|
||||
image.ProcessEntryContents()
|
||||
image.WriteSymbols()
|
||||
image.BuildImage()
|
||||
|
@ -43,6 +43,7 @@ class Prop:
|
||||
self.name = name
|
||||
self.value = None
|
||||
self.bytes = str(bytes)
|
||||
self.dirty = False
|
||||
if not bytes:
|
||||
self.type = TYPE_BOOL
|
||||
self.value = True
|
||||
@ -160,6 +161,45 @@ class Prop:
|
||||
self._node._fdt.CheckCache()
|
||||
return self._node._fdt.GetStructOffset(self._offset)
|
||||
|
||||
def SetInt(self, val):
|
||||
"""Set the integer value of the property
|
||||
|
||||
The device tree is marked dirty so that the value will be written to
|
||||
the block on the next sync.
|
||||
|
||||
Args:
|
||||
val: Integer value (32-bit, single cell)
|
||||
"""
|
||||
self.bytes = struct.pack('>I', val);
|
||||
self.value = val
|
||||
self.type = TYPE_INT
|
||||
self.dirty = True
|
||||
|
||||
def Sync(self, auto_resize=False):
|
||||
"""Sync property changes back to the device tree
|
||||
|
||||
This updates the device tree blob with any changes to this property
|
||||
since the last sync.
|
||||
|
||||
Args:
|
||||
auto_resize: Resize the device tree automatically if it does not
|
||||
have enough space for the update
|
||||
|
||||
Raises:
|
||||
FdtException if auto_resize is False and there is not enough space
|
||||
"""
|
||||
if self._offset is None or self.dirty:
|
||||
node = self._node
|
||||
fdt_obj = node._fdt._fdt_obj
|
||||
if auto_resize:
|
||||
while fdt_obj.setprop(node.Offset(), self.name, self.bytes,
|
||||
(libfdt.NOSPACE,)) == -libfdt.NOSPACE:
|
||||
fdt_obj.resize(fdt_obj.totalsize() + 1024)
|
||||
fdt_obj.setprop(node.Offset(), self.name, self.bytes)
|
||||
else:
|
||||
fdt_obj.setprop(node.Offset(), self.name, self.bytes)
|
||||
|
||||
|
||||
class Node:
|
||||
"""A device tree node
|
||||
|
||||
@ -284,13 +324,7 @@ class Node:
|
||||
Args:
|
||||
prop_name: Name of property
|
||||
"""
|
||||
fdt_obj = self._fdt._fdt_obj
|
||||
if fdt_obj.setprop_u32(self.Offset(), prop_name, 0,
|
||||
(libfdt.NOSPACE,)) == -libfdt.NOSPACE:
|
||||
fdt_obj.resize(fdt_obj.totalsize() + 1024)
|
||||
fdt_obj.setprop_u32(self.Offset(), prop_name, 0)
|
||||
self.props[prop_name] = Prop(self, -1, prop_name, '\0' * 4)
|
||||
self._fdt.Invalidate()
|
||||
self.props[prop_name] = Prop(self, None, prop_name, '\0' * 4)
|
||||
|
||||
def SetInt(self, prop_name, val):
|
||||
"""Update an integer property int the device tree.
|
||||
@ -301,8 +335,34 @@ class Node:
|
||||
prop_name: Name of property
|
||||
val: Value to set
|
||||
"""
|
||||
fdt_obj = self._fdt._fdt_obj
|
||||
fdt_obj.setprop_u32(self.Offset(), prop_name, val)
|
||||
self.props[prop_name].SetInt(val)
|
||||
|
||||
def Sync(self, auto_resize=False):
|
||||
"""Sync node changes back to the device tree
|
||||
|
||||
This updates the device tree blob with any changes to this node and its
|
||||
subnodes since the last sync.
|
||||
|
||||
Args:
|
||||
auto_resize: Resize the device tree automatically if it does not
|
||||
have enough space for the update
|
||||
|
||||
Raises:
|
||||
FdtException if auto_resize is False and there is not enough space
|
||||
"""
|
||||
# Sync subnodes in reverse so that we don't disturb node offsets for
|
||||
# nodes that are earlier in the DT. This avoids an O(n^2) rescan of
|
||||
# node offsets.
|
||||
for node in reversed(self.subnodes):
|
||||
node.Sync(auto_resize)
|
||||
|
||||
# Sync properties now, whose offsets should not have been disturbed.
|
||||
# We do this after subnodes, since this disturbs the offsets of these
|
||||
# properties.
|
||||
prop_list = sorted(self.props.values(), key=lambda prop: prop._offset,
|
||||
reverse=True)
|
||||
for prop in prop_list:
|
||||
prop.Sync(auto_resize)
|
||||
|
||||
|
||||
class Fdt:
|
||||
@ -381,6 +441,19 @@ class Fdt:
|
||||
with open(self._fname, 'wb') as fd:
|
||||
fd.write(self._fdt_obj.as_bytearray())
|
||||
|
||||
def Sync(self, auto_resize=False):
|
||||
"""Make sure any DT changes are written to the blob
|
||||
|
||||
Args:
|
||||
auto_resize: Resize the device tree automatically if it does not
|
||||
have enough space for the update
|
||||
|
||||
Raises:
|
||||
FdtException if auto_resize is False and there is not enough space
|
||||
"""
|
||||
self._root.Sync(auto_resize)
|
||||
self.Invalidate()
|
||||
|
||||
def Pack(self):
|
||||
"""Pack the device tree down to its minimum size
|
||||
|
||||
|
@ -337,6 +337,7 @@ class TestProp(unittest.TestCase):
|
||||
self.node.AddZeroProp('one')
|
||||
self.node.AddZeroProp('two')
|
||||
self.node.AddZeroProp('three')
|
||||
self.dtb.Sync(auto_resize=True)
|
||||
|
||||
# Updating existing properties should be OK, since the device-tree size
|
||||
# does not change
|
||||
@ -344,12 +345,17 @@ class TestProp(unittest.TestCase):
|
||||
self.node.SetInt('one', 1)
|
||||
self.node.SetInt('two', 2)
|
||||
self.node.SetInt('three', 3)
|
||||
self.dtb.Sync(auto_resize=False)
|
||||
|
||||
# This should fail since it would need to increase the device-tree size
|
||||
self.node.AddZeroProp('four')
|
||||
with self.assertRaises(libfdt.FdtException) as e:
|
||||
self.node.SetInt('four', 4)
|
||||
self.dtb.Sync(auto_resize=False)
|
||||
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
|
||||
|
||||
def testAddNode(self):
|
||||
self.fdt.pack()
|
||||
|
||||
|
||||
class TestFdtUtil(unittest.TestCase):
|
||||
"""Tests for the fdt_util module
|
||||
|
Loading…
Reference in New Issue
Block a user