string from the root node of the devicetree, so that things work correctly
with FIT's configuration-matching algortihm.
+Dealing with phases
+~~~~~~~~~~~~~~~~~~~
+
+FIT can be used to load firmware. In this case it may be necessary to run
+the devicetree for each model through fdtgrep to remove unwanted properties.
+The 'fit,fdt-phase' property can be provided to indicate the phase for which
+the devicetree is intended.
+
+For example this indicates that the FDT should be processed for VPL::
+
+ images {
+ @fdt-SEQ {
+ description = "fdt-NAME";
+ type = "flat_dt";
+ compression = "none";
+ fit,fdt-phase = "vpl";
+ };
+ };
+
+Using this mechanism, it is possible to generate a FIT which can provide VPL
+images for multiple models, with TPL selecting the correct model to use. The
+same approach can of course be used for SPL images.
+
+Note that the `of-spl-remove-props` entryarg can be used to indicate
+additional properties to remove. It is often used to remove properties like
+`clock-names` and `pinctrl-names` which are not needed in SPL builds.
+
+See :ref:`fdtgrep_filter` for more information.
+
Generating nodes from an ELF file (split-elf)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
firmware = "atf";
loadables = "uboot";
fdt = "fdt-SEQ";
- fit,compatible;
+ fit,compatible; // optional
};
};
Note that if no devicetree files are provided (with '-a of-list' as above)
then no nodes will be generated.
- The 'fit,compatible' property is replaced with the compatible string from
- the root node of the devicetree, so that things work correctly with FIT's
- configuration-matching algortihm.
+ The 'fit,compatible' property (if present) is replaced with the compatible
+ string from the root node of the devicetree, so that things work correctly
+ with FIT's configuration-matching algortihm.
+
+ Dealing with phases
+ ~~~~~~~~~~~~~~~~~~~
+
+ FIT can be used to load firmware. In this case it may be necessary to run
+ the devicetree for each model through fdtgrep to remove unwanted properties.
+ The 'fit,fdt-phase' property can be provided to indicate the phase for which
+ the devicetree is intended.
+
+ For example this indicates that the FDT should be processed for VPL::
+
+ images {
+ @fdt-SEQ {
+ description = "fdt-NAME";
+ type = "flat_dt";
+ compression = "none";
+ fit,fdt-phase = "vpl";
+ };
+ };
+
+ Using this mechanism, it is possible to generate a FIT which can provide VPL
+ images for multiple models, with TPL selecting the correct model to use. The
+ same approach can of course be used for SPL images.
+
+ Note that the `of-spl-remove-props` entryarg can be used to indicate
+ additional properties to remove. It is often used to remove properties like
+ `clock-names` and `pinctrl-names` which are not needed in SPL builds.
+
+ See :ref:`fdtgrep_filter` for more information.
Generating nodes from an ELF file (split-elf)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
self._fdts = None
self._fdt_dir = None
self.mkimage = None
+ self.fdtgrep = None
self._priv_entries = {}
self._loadables = []
+ self._remove_props = []
+ props, = self.GetEntryArgsOrProps(
+ [EntryArg('of-spl-remove-props', str)], required=False)
+ if props:
+ self._remove_props = props.split()
def ReadNode(self):
super().ReadNode()
rel_path = node.path[len(self._node.path) + 1:]
self.Raise(f"subnode '{rel_path}': {msg}")
+ def _run_fdtgrep(self, infile, phase, outfile):
+ """Run fdtgrep to create the dtb for a phase
+
+ Args:
+ infile (str): Input filename containing the full FDT contents (with
+ all nodes and properties)
+ phase (str): Phase to generate for ('tpl', 'vpl', 'spl')
+ outfile (str): Output filename to write the grepped FDT contents to
+ (with only neceesary nodes and properties)
+ """
+ return self.fdtgrep.create_for_phase(infile, phase, outfile,
+ self._remove_props)
+
def _build_input(self):
"""Finish the FIT by adding the 'data' properties to it
for seq, fdt_fname in enumerate(self._fdts):
node_name = node.name[1:].replace('SEQ', str(seq + 1))
fname = tools.get_input_filename(fdt_fname + '.dtb')
+ fdt_phase = None
with fsw.add_node(node_name):
for pname, prop in node.props.items():
if pname == 'fit,firmware':
fdt.Scan()
prop = fdt.GetRoot().props['compatible']
fsw.property('compatible', prop.bytes)
+ elif pname == 'fit,fdt-phase':
+ fdt_phase = fdt_util.GetString(node, pname)
elif pname.startswith('fit,'):
self._raise_subnode(
node, f"Unknown directive '{pname}'")
# Add data for 'images' nodes (but not 'config')
if depth == 1 and in_images:
- fsw.property('data', tools.read_file(fname))
+ if fdt_phase:
+ phase_fname = tools.get_output_filename(
+ f'{fdt_fname}-{fdt_phase}.dtb')
+ self._run_fdtgrep(fname, fdt_phase, phase_fname)
+ data = tools.read_file(phase_fname)
+ else:
+ data = tools.read_file(fname)
+ fsw.property('data', data)
for subnode in node.subnodes:
with fsw.add_node(subnode.name):
def AddBintools(self, btools):
super().AddBintools(btools)
self.mkimage = self.AddBintool(btools, 'mkimage')
+ self.fdtgrep = self.AddBintool(btools, 'fdtgrep')
def CheckMissing(self, missing_list):
# We must use our private entry list for this since generator nodes
self.assertEqual(f'u-boot,model-{expected}',
fnode.props['compatible'].value)
+ def testFitFdtPhase(self):
+ """Test an image with an FIT with fdt-phase in the fdt nodes"""
+ phase = 'tpl'
+ entry_args = {
+ f'{phase}-dtb': '1',
+ f'{phase}-bss-pad': 'y',
+ 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
+ 'of-list': 'model1 model2',
+ 'default-dt': 'model2',
+ }
+ testdir, dtb_list = self.SetupAlternateDts()
+ data = self._DoReadFileDtb(
+ '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
+ entry_args=entry_args, extra_indirs=[testdir])[0]
+ fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
+ fit = fdt.Fdt.FromData(fit_data)
+ fit.Scan()
+
+ # Check that each FDT has only the expected properties for the phase
+ for seq in range(1, 2):
+ fnode = fit.GetNode(f'/images/fdt-{seq}')
+ self.assertIsNotNone(fnode)
+ dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
+ dtb.Scan()
+
+ # Make sure that the 'bootph-pre-sram' tag in /node protects it from
+ # removal
+ node = dtb.GetNode('/node')
+ self.assertIsNotNone(node)
+ self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
+ node.props.keys())
+
+ # Make sure the other node is gone
+ self.assertIsNone(dtb.GetNode('/node/other-node'))
+
if __name__ == "__main__":
unittest.main()