[PATCH v2 1/3] binman: imx8mimage: Handle nxp,boot-from = "fspi"
Simon Glass
sjg at chromium.org
Sat May 30 00:03:43 CEST 2026
Hi Marek,
On 2026-05-25T23:51:02, Marek Vasut <marex at nabladev.com> wrote:
> binman: imx8mimage: Handle nxp,boot-from = 'fspi'
>
> Boot from FSPI requires additional 448 Byte long header, with U-Boot SPL
> starting at offset 0x1000. Currently, both i.MX8MM and i.MX8MN attempt
> to generate this header using fspi_conf_block with filename pointing at
> CONFIG_FSPI_CONF_FILE file. This does not work, for two reasons.
>
> First, the CONFIG_FSPI_CONF_FILE is generated by mkimage -T imx8mimage
> and may not be available yet when the fspi_conf_block is evaluated. That
> leads to a race condition where highly parallel builds fail to find the
> CONFIG_FSPI_CONF_FILE, which is usually called fspi_header.bin, on first
> build attempt.
>
> Second, binman gets confused and patches incorrect offset of DDR PHY
> firmware blobs into U-Boot SPL, the offset is incremented by exactly
> 0x1000 which is the size of fspi_conf_block.
>
> Fix both problems at once, make imx8mimage handle the generated FSPI
> header and prepend it in front of the imx8mimage processed data. This
> way, the race condition is solved, because the data generated by the
> [...]
>
> tools/binman/etype/nxp_imx8mimage.py | 11 ++++++++++-
> tools/binman/ftest.py | 9 +++++++++
> tools/binman/test/vendor/nxp_imx8m_fspi.dts | 18 ++++++++++++++++++
> 3 files changed, 37 insertions(+), 1 deletion(-)
> diff --git a/tools/binman/etype/nxp_imx8mimage.py b/tools/binman/etype/nxp_imx8mimage.py
> @@ -33,6 +35,7 @@ class Entry_nxp_imx8mimage(Entry_mkimage):
> def ReadNode(self):
> super().ReadNode()
> self.boot_from = fdt_util.GetString(self._node, 'nxp,boot-from')
> + self.fspi_header = fdt_util.GetString(self._node, 'nxp,fspi-header-filename')
> self.loader_address = fdt_util.GetInt(self._node, 'nxp,loader-address')
> self.rom_version = fdt_util.GetInt(self._node, 'nxp,rom-version')
Please update the class docstring to document
nxp,fspi-header-filename: what it is, that it only applies when
nxp,boot-from = 'fspi', and that the file is read relative to the
binman output directory. Binman has no separate entries.rst, so the
docstring is the documentation.
> diff --git a/tools/binman/etype/nxp_imx8mimage.py b/tools/binman/etype/nxp_imx8mimage.py
> @@ -52,7 +55,13 @@ class Entry_nxp_imx8mimage(Entry_mkimage):
> if self.mkimage.run_cmd(*args) is not None:
> - return tools.read_file(output_fname)
> + outdata = tools.read_file(output_fname)
> + if self.boot_from == 'fspi' and self.fspi_header:
> + spidata = tools.read_file(os.path.join(tools.get_output_dir(), self.fspi_header))
> + if len(spidata) < 0x1000:
> + spidata += tools.get_bytes(0, 0x1000 - len(spidata))
> + outdata = spidata + outdata
What happens if the header file is larger than 0x1000? The current
code silently concatenates and shifts everything downstream - exactly
the offset bug the commit message says we are trying to avoid. Please
raise a clear error when len(spidata) > 0x1000.
Also, if boot_from == 'fspi' but nxp,fspi-header-filename is unset,
the code silently produces an image with no FSPI header. A debug log
line noting the header is being skipped would help later.
> diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
> @@ -8099,6 +8099,15 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
> + def testNxpImx8MFSPI(self):
> + """Test that binman can produce an iMX8m FSPI image"""
> + testdir = tempfile.mkdtemp(prefix='binman.')
> + image_path = os.path.join(testdir, 'fspi_header.bin')
> + with open(image_path, 'w') as f:
> + f.write(bytes([0x87]).decode('latin1') * 448)
> + with terminal.capture():
> + self._DoTestFile('vendor/nxp_imx8m_fspi.dts', output_dir=testdir)
This only checks that binman does not crash. Please read back the
produced image and assert that the first 448 bytes are 0x87, that
bytes 0x1c0..0x1000 are zero, and that the mkimage output follows at
0x1000 - otherwise the regression we are guarding against would not be
caught.
Also, you should write files using tools.write_file() and and write
tools.get_bytes(0x87, 448) rather than the decode('latin1') trick.
Regards,
Simon
More information about the U-Boot
mailing list