clk: renesas: Synchronize Gen2 tables with Linux 5.0
[oweals/u-boot.git] / tools / binman / entry.py
index de07f2721599d502856e4d83ebdea367473b0c24..648cfd241f1dac53d87459f6cb1f725d1e86848a 100644 (file)
@@ -17,10 +17,12 @@ try:
 except:
     have_importlib = False
 
-import fdt_util
-import control
 import os
+from sets import Set
 import sys
+
+import fdt_util
+import state
 import tools
 
 modules = {}
@@ -65,7 +67,7 @@ class Entry(object):
         self.name = node and (name_prefix + node.name) or 'none'
         self.offset = None
         self.size = None
-        self.data = ''
+        self.data = None
         self.contents_size = 0
         self.align = None
         self.align_size = None
@@ -74,24 +76,23 @@ class Entry(object):
         self.pad_after = 0
         self.offset_unset = False
         self.image_pos = None
+        self._expand_size = False
         if read_node:
             self.ReadNode()
 
     @staticmethod
-    def Create(section, node, etype=None):
-        """Create a new entry for a node.
+    def Lookup(section, node_path, etype):
+        """Look up the entry class for a node.
 
         Args:
-            section:  Section object containing this node
-            node:   Node object containing information about the entry to create
-            etype:  Entry type to use, or None to work it out (used for tests)
+            section:   Section object containing this node
+            node_node: Path name of Node object containing information about
+                       the entry to create (used for errors)
+            etype:   Entry type to use
 
         Returns:
-            A new Entry object of the correct type (a subclass of Entry)
+            The entry class object if found, else None
         """
-        if not etype:
-            etype = fdt_util.GetString(node, 'type', node.name)
-
         # Convert something like 'u-boot@0' to 'u_boot' since we are only
         # interested in the type.
         module_name = etype.replace('-', '_')
@@ -110,15 +111,34 @@ class Entry(object):
                     module = importlib.import_module(module_name)
                 else:
                     module = __import__(module_name)
-            except ImportError:
-                raise ValueError("Unknown entry type '%s' in node '%s'" %
-                        (etype, node.path))
+            except ImportError as e:
+                raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
+                                 (etype, node_path, module_name, e))
             finally:
                 sys.path = old_path
             modules[module_name] = module
 
+        # Look up the expected class name
+        return getattr(module, 'Entry_%s' % module_name)
+
+    @staticmethod
+    def Create(section, node, etype=None):
+        """Create a new entry for a node.
+
+        Args:
+            section: Section object containing this node
+            node:    Node object containing information about the entry to
+                     create
+            etype:   Entry type to use, or None to work it out (used for tests)
+
+        Returns:
+            A new Entry object of the correct type (a subclass of Entry)
+        """
+        if not etype:
+            etype = fdt_util.GetString(node, 'type', node.name)
+        obj = Entry.Lookup(section, node.path, etype)
+
         # Call its constructor to get the object we want.
-        obj = getattr(module, 'Entry_%s' % module_name)
         return obj(section, etype, node)
 
     def ReadNode(self):
@@ -126,6 +146,8 @@ class Entry(object):
 
         This reads all the fields we recognise from the node, ready for use.
         """
+        if 'pos' in self._node.props:
+            self.Raise("Please use 'offset' instead of 'pos'")
         self.offset = fdt_util.GetInt(self._node, 'offset')
         self.size = fdt_util.GetInt(self._node, 'size')
         self.align = fdt_util.GetInt(self._node, 'align')
@@ -140,20 +162,57 @@ class Entry(object):
                              "of two" % (self._node.path, self.align_size))
         self.align_end = fdt_util.GetInt(self._node, 'align-end')
         self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
+        self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
+
+    def GetDefaultFilename(self):
+        return None
+
+    def GetFdtSet(self):
+        """Get the set of device trees used by this entry
+
+        Returns:
+            Set containing the filename from this entry, if it is a .dtb, else
+            an empty set
+        """
+        fname = self.GetDefaultFilename()
+        # It would be better to use isinstance(self, Entry_blob_dtb) here but
+        # we cannot access Entry_blob_dtb
+        if fname and fname.endswith('.dtb'):
+            return Set([fname])
+        return Set()
+
+    def ExpandEntries(self):
+        pass
 
     def AddMissingProperties(self):
         """Add new properties to the device tree as needed for this entry"""
         for prop in ['offset', 'size', 'image-pos']:
             if not prop in self._node.props:
-                self._node.AddZeroProp(prop)
+                state.AddZeroProp(self._node, prop)
+        err = state.CheckAddHashProp(self._node)
+        if err:
+            self.Raise(err)
 
     def SetCalculatedProperties(self):
         """Set the value of device-tree properties calculated by binman"""
-        self._node.SetInt('offset', self.offset)
-        self._node.SetInt('size', self.size)
-        self._node.SetInt('image-pos', self.image_pos)
+        state.SetInt(self._node, 'offset', self.offset)
+        state.SetInt(self._node, 'size', self.size)
+        state.SetInt(self._node, 'image-pos',
+                       self.image_pos - self.section.GetRootSkipAtStart())
+        state.CheckSetHashValue(self._node, self.GetData)
 
     def ProcessFdt(self, fdt):
+        """Allow entries to adjust the device tree
+
+        Some entries need to adjust the device tree for their purposes. This
+        may involve adding or deleting properties.
+
+        Returns:
+            True if processing is complete
+            False if processing could not be completed due to a dependency.
+                This will cause the entry to be retried after others have been
+                called
+        """
         return True
 
     def SetPrefix(self, prefix):
@@ -332,8 +391,16 @@ class Entry(object):
         pass
 
     @staticmethod
-    def WriteMapLine(fd, indent, name, offset, size):
-        print('%s%08x  %08x  %s' % (' ' * indent, offset, size, name), file=fd)
+    def GetStr(value):
+        if value is None:
+            return '<none>  '
+        return '%08x' % value
+
+    @staticmethod
+    def WriteMapLine(fd, indent, name, offset, size, image_pos):
+        print('%s  %s%s  %s  %s' % (Entry.GetStr(image_pos), ' ' * indent,
+                                    Entry.GetStr(offset), Entry.GetStr(size),
+                                    name), file=fd)
 
     def WriteMap(self, fd, indent):
         """Write a map of the entry to a .map file
@@ -342,7 +409,17 @@ class Entry(object):
             fd: File to write the map to
             indent: Curent indent level of map (0=none, 1=one level, etc.)
         """
-        self.WriteMapLine(fd, indent, self.name, self.offset, self.size)
+        self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
+                          self.image_pos)
+
+    def GetEntries(self):
+        """Return a list of entries contained by this entry
+
+        Returns:
+            List of entries, or None if none. A normal entry has no entries
+                within it so will return None
+        """
+        return None
 
     def GetArg(self, name, datatype=str):
         """Get the value of an entry argument or device-tree-node property
@@ -360,7 +437,7 @@ class Entry(object):
         Raises:
             ValueError if the argument cannot be converted to in
         """
-        value = control.GetEntryArg(name)
+        value = state.GetEntryArg(name)
         if value is not None:
             if datatype == int:
                 try:
@@ -376,3 +453,80 @@ class Entry(object):
         else:
             value = fdt_util.GetDatatype(self._node, name, datatype)
         return value
+
+    @staticmethod
+    def WriteDocs(modules, test_missing=None):
+        """Write out documentation about the various entry types to stdout
+
+        Args:
+            modules: List of modules to include
+            test_missing: Used for testing. This is a module to report
+                as missing
+        """
+        print('''Binman Entry Documentation
+===========================
+
+This file describes the entry types supported by binman. These entry types can
+be placed in an image one by one to build up a final firmware image. It is
+fairly easy to create new entry types. Just add a new file to the 'etype'
+directory. You can use the existing entries as examples.
+
+Note that some entries are subclasses of others, using and extending their
+features to produce new behaviours.
+
+
+''')
+        modules = sorted(modules)
+
+        # Don't show the test entry
+        if '_testing' in modules:
+            modules.remove('_testing')
+        missing = []
+        for name in modules:
+            module = Entry.Lookup(name, name, name)
+            docs = getattr(module, '__doc__')
+            if test_missing == name:
+                docs = None
+            if docs:
+                lines = docs.splitlines()
+                first_line = lines[0]
+                rest = [line[4:] for line in lines[1:]]
+                hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
+                print(hdr)
+                print('-' * len(hdr))
+                print('\n'.join(rest))
+                print()
+                print()
+            else:
+                missing.append(name)
+
+        if missing:
+            raise ValueError('Documentation is missing for modules: %s' %
+                             ', '.join(missing))
+
+    def GetUniqueName(self):
+        """Get a unique name for a node
+
+        Returns:
+            String containing a unique name for a node, consisting of the name
+            of all ancestors (starting from within the 'binman' node) separated
+            by a dot ('.'). This can be useful for generating unique filesnames
+            in the output directory.
+        """
+        name = self.name
+        node = self._node
+        while node.parent:
+            node = node.parent
+            if node.name == 'binman':
+                break
+            name = '%s.%s' % (node.name, name)
+        return name
+
+    def ExpandToLimit(self, limit):
+        """Expand an entry so that it ends at the given offset limit"""
+        if self.offset + self.size < limit:
+            self.size = limit - self.offset
+            # Request the contents again, since changing the size requires that
+            # the data grows. This should not fail, but check it to be sure.
+            if not self.ObtainContents():
+                self.Raise('Cannot obtain contents when expanding entry')