Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | # SPDX-License-Identifier: GPL-2.0+ # Copyright 2024 Google LLC # Written by Simon Glass <sjg@chromium.org> """Entry-type module for producing multiple alternate sections""" import glob import os from binman.entry import EntryArg from binman.etype.section import Entry_section from dtoc import fdt_util from u_boot_pylib import tools class Entry_alternates_fdt(Entry_section): """Entry that generates alternative sections for each devicetree provided When creating an image designed to boot on multiple models, each model requires its own devicetree. This entry deals with selecting the correct devicetree from a directory containing them. Each one is read in turn, then used to produce section contents which are written to a file. This results in a number of images, one for each model. For example this produces images for each .dtb file in the 'dtb' directory:: alternates-fdt { fdt-list-dir = "dtb"; filename-pattern = "NAME.bin"; fdt-phase = "tpl"; section { u-boot-tpl { }; }; }; Each output file is named based on its input file, so an input file of `model1.dtb` results in an output file of `model1.bin` (i.e. the `NAME` in the `filename-pattern` property is replaced with the .dtb basename). Note that this entry type still produces contents for the 'main' image, in that case using the normal dtb provided to Binman, e.g. `u-boot-tpl.dtb`. But that image is unlikely to be useful, since it relates to whatever dtb happened to be the default when U-Boot builds (i.e. `CONFIG_DEFAULT_DEVICE_TREE`). However, Binman ensures that the size of each of the alternates is the same as the 'default' one, so they can in principle be 'slotted in' to the appropriate place in the main image. The optional `fdt-phase` property indicates the phase to build. In this case, it etype runs fdtgrep to obtain the devicetree subset for that phase, respecting the `bootph-xxx` tags in the devicetree. """ def __init__(self, section, etype, node): super().__init__(section, etype, node) self.fdt_list_dir = None self.filename_pattern = None self.required_props = ['fdt-list-dir'] self._cur_fdt = None self._fdt_phase = None self.fdtgrep = None self._fdt_dir = None self._fdts = None self._fname_pattern = None self._remove_props = None self.alternates = None def ReadNode(self): """Read properties from the node""" super().ReadNode() self._fdt_dir = fdt_util.GetString(self._node, 'fdt-list-dir') fname = tools.get_input_filename(self._fdt_dir) fdts = glob.glob('*.dtb', root_dir=fname) self._fdts = [os.path.splitext(f)[0] for f in fdts] self._fdt_phase = fdt_util.GetString(self._node, 'fdt-phase') # This is used by Image.WriteAlternates() self.alternates = self._fdts self._fname_pattern = fdt_util.GetString(self._node, 'filename-pattern') self._remove_props = [] props, = self.GetEntryArgsOrProps( [EntryArg('of-spl-remove-props', str)], required=False) if props: self._remove_props = props.split() def FdtContents(self, fdt_etype): # If there is no current FDT, just use the normal one if not self._cur_fdt: return self.section.FdtContents(fdt_etype) # Find the file to use fname = os.path.join(self._fdt_dir, f'{self._cur_fdt}.dtb') infile = tools.get_input_filename(fname) # Run fdtgrep if needed, to remove unwanted nodes and properties if self._fdt_phase: uniq = self.GetUniqueName() outfile = tools.get_output_filename( f'{uniq}.{self._cur_fdt}-{self._fdt_phase}.dtb') self.fdtgrep.create_for_phase(infile, self._fdt_phase, outfile, self._remove_props) return outfile, tools.read_file(outfile) return fname, tools.read_file(infile) def ProcessWithFdt(self, alt): """Produce the contents of this entry, using a particular FDT blob Args: alt (str): Name of the alternate Returns: tuple: str: Filename to use for the alternate's .bin file bytes: Contents of this entry's section, using the selected FDT """ pattern = self._fname_pattern or 'NAME.bin' fname = pattern.replace('NAME', alt) data = b'' try: self._cur_fdt = alt self.ProcessContents() data = self.GetPaddedData() finally: self._cur_fdt = None return fname, data def AddBintools(self, btools): super().AddBintools(btools) self.fdtgrep = self.AddBintool(btools, 'fdtgrep') |