aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
l---------tools/binman/README.rst1
-rw-r--r--tools/binman/binman.rst (renamed from tools/binman/README)959
-rw-r--r--tools/binman/cmdline.py5
-rw-r--r--tools/binman/control.py28
-rw-r--r--tools/binman/entries.rst (renamed from tools/binman/README.entries)336
-rw-r--r--tools/binman/entry.py73
-rw-r--r--tools/binman/entry_test.py12
-rw-r--r--tools/binman/etype/atf_bl31.py2
-rw-r--r--tools/binman/etype/blob.py4
-rw-r--r--tools/binman/etype/blob_dtb.py9
-rw-r--r--tools/binman/etype/blob_ext.py2
-rw-r--r--tools/binman/etype/blob_phase.py51
-rw-r--r--tools/binman/etype/cbfs.py12
-rw-r--r--tools/binman/etype/fdtmap.py30
-rw-r--r--tools/binman/etype/files.py2
-rw-r--r--tools/binman/etype/fit.py21
-rw-r--r--tools/binman/etype/intel_cmc.py2
-rw-r--r--tools/binman/etype/intel_fsp.py2
-rw-r--r--tools/binman/etype/intel_fsp_m.py2
-rw-r--r--tools/binman/etype/intel_fsp_s.py2
-rw-r--r--tools/binman/etype/intel_fsp_t.py2
-rw-r--r--tools/binman/etype/intel_ifwi.py10
-rw-r--r--tools/binman/etype/intel_me.py2
-rw-r--r--tools/binman/etype/intel_mrc.py2
-rw-r--r--tools/binman/etype/intel_refcode.py2
-rw-r--r--tools/binman/etype/intel_vbt.py2
-rw-r--r--tools/binman/etype/intel_vga.py2
-rw-r--r--tools/binman/etype/mkimage.py4
-rw-r--r--tools/binman/etype/scp.py2
-rw-r--r--tools/binman/etype/section.py15
-rw-r--r--tools/binman/etype/text.py6
-rw-r--r--tools/binman/etype/u_boot.py8
-rw-r--r--tools/binman/etype/u_boot_dtb_with_ucode.py4
-rw-r--r--tools/binman/etype/u_boot_expanded.py24
-rw-r--r--tools/binman/etype/u_boot_nodtb.py8
-rw-r--r--tools/binman/etype/u_boot_spl.py3
-rw-r--r--tools/binman/etype/u_boot_spl_bss_pad.py17
-rw-r--r--tools/binman/etype/u_boot_spl_expanded.py45
-rw-r--r--tools/binman/etype/u_boot_spl_nodtb.py24
-rw-r--r--tools/binman/etype/u_boot_tpl.py3
-rw-r--r--tools/binman/etype/u_boot_tpl_bss_pad.py44
-rw-r--r--tools/binman/etype/u_boot_tpl_expanded.py45
-rw-r--r--tools/binman/etype/u_boot_tpl_nodtb.py42
-rw-r--r--tools/binman/etype/u_boot_with_ucode_ptr.py2
-rw-r--r--tools/binman/ftest.py268
-rw-r--r--tools/binman/image.py17
-rw-r--r--tools/binman/index.rst9
-rw-r--r--tools/binman/setup.py2
-rw-r--r--tools/binman/state.py71
-rw-r--r--tools/binman/test/053_symbols.dts2
-rw-r--r--tools/binman/test/149_symbols_tpl.dts1
-rw-r--r--tools/binman/test/155_symbols_tpl_x86.dts1
-rw-r--r--tools/binman/test/192_symbols_nodtb.dts26
-rw-r--r--tools/binman/test/192_u_boot_tpl_nodtb.dts13
-rw-r--r--tools/binman/test/193_tpl_bss_pad.dts19
-rw-r--r--tools/binman/test/194_fdt_incl.dts17
-rw-r--r--tools/binman/test/195_fdt_incl_tpl.dts13
-rw-r--r--tools/binman/test/u_boot_binman_syms.c2
-rw-r--r--tools/dtoc/dtb_platdata.py620
-rw-r--r--tools/dtoc/dtoc_test_scan_drivers.cxx1
-rwxr-xr-xtools/dtoc/main.py9
-rw-r--r--tools/dtoc/src_scan.py597
-rw-r--r--tools/dtoc/test/dtoc_test.dts (renamed from tools/dtoc/dtoc_test.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_add_prop.dts (renamed from tools/dtoc/dtoc_test_add_prop.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr32.dts (renamed from tools/dtoc/dtoc_test_addr32.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr32_64.dts (renamed from tools/dtoc/dtoc_test_addr32_64.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr64.dts (renamed from tools/dtoc/dtoc_test_addr64.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr64_32.dts (renamed from tools/dtoc/dtoc_test_addr64_32.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad_path.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad_uc.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_aliases.dts (renamed from tools/dtoc/dtoc_test_aliases.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_bad_reg.dts (renamed from tools/dtoc/dtoc_test_bad_reg.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_bad_reg2.dts (renamed from tools/dtoc/dtoc_test_bad_reg2.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_driver_alias.dts (renamed from tools/dtoc/dtoc_test_driver_alias.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_empty.dts (renamed from tools/dtoc/dtoc_test_empty.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_inst.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_invalid_driver.dts (renamed from tools/dtoc/dtoc_test_invalid_driver.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle.dts (renamed from tools/dtoc/dtoc_test_phandle.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_bad.dts (renamed from tools/dtoc/dtoc_test_phandle_bad.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_bad2.dts (renamed from tools/dtoc/dtoc_test_phandle_bad2.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts (renamed from tools/dtoc/dtoc_test_phandle_cd_gpios.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_reorder.dts (renamed from tools/dtoc/dtoc_test_phandle_reorder.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_single.dts (renamed from tools/dtoc/dtoc_test_phandle_single.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_scan_drivers.cxx5
-rw-r--r--tools/dtoc/test/dtoc_test_simple.dts (renamed from tools/dtoc/dtoc_test_simple.dts)4
-rwxr-xr-xtools/dtoc/test_dtoc.py1023
-rwxr-xr-xtools/dtoc/test_fdt.py31
-rw-r--r--tools/dtoc/test_src_scan.py397
-rw-r--r--tools/fdtgrep.c2
-rw-r--r--tools/patman/README14
-rw-r--r--tools/patman/func_test.py2
-rw-r--r--tools/patman/gitutil.py45
-rwxr-xr-xtools/patman/main.py9
-rw-r--r--tools/patman/series.py10
-rw-r--r--tools/patman/tools.py8
96 files changed, 4432 insertions, 911 deletions
diff --git a/tools/binman/README.rst b/tools/binman/README.rst
new file mode 120000
index 0000000..b734f54
--- /dev/null
+++ b/tools/binman/README.rst
@@ -0,0 +1 @@
+binman.rst \ No newline at end of file
diff --git a/tools/binman/README b/tools/binman/binman.rst
index 45f0a0c..15314d1 100644
--- a/tools/binman/README
+++ b/tools/binman/binman.rst
@@ -1,47 +1,51 @@
-# SPDX-License-Identifier: GPL-2.0+
-# Copyright (c) 2016 Google, Inc
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (c) 2016 Google, Inc
Introduction
-------------
+============
Firmware often consists of several components which must be packaged together.
For example, we may have SPL, U-Boot, a device tree and an environment area
grouped together and placed in MMC flash. When the system starts, it must be
able to find these pieces.
-So far U-Boot has not provided a way to handle creating such images in a
-general way. Each SoC does what it needs to build an image, often packing or
-concatenating images in the U-Boot build system.
-
-Binman aims to provide a mechanism for building images, from simple
-SPL + U-Boot combinations, to more complex arrangements with many parts.
+Building firmware should be separate from packaging it. Many of the complexities
+of modern firmware build systems come from trying to do both at once. With
+binman, you build all the pieces that are needed, using whatever assortment of
+projects and build systems are needed, then use binman to stitch everything
+together.
What it does
------------
Binman reads your board's device tree and finds a node which describes the
-required image layout. It uses this to work out what to place where. The
-output file normally contains the device tree, so it is in principle possible
-to read an image and extract its constituent parts.
+required image layout. It uses this to work out what to place where.
+
+Binman provides a mechanism for building images, from simple SPL + U-Boot
+combinations, to more complex arrangements with many parts. It also allows
+users to inspect images, extract and replace binaries within them, repacking if
+needed.
Features
--------
-So far binman is pretty simple. It supports binary blobs, such as 'u-boot',
-'spl' and 'fdt'. It supports empty entries (such as setting to 0xff). It can
-place entries at a fixed location in the image, or fit them together with
-suitable padding and alignment. It provides a way to process binaries before
-they are included, by adding a Python plug-in. The device tree is available
-to U-Boot at run-time so that the images can be interpreted.
+Apart from basic padding, alignment and positioning features, Binman supports
+hierarchical images, compression, hashing and dealing with the binary blobs
+which are a sad trend in open-source firmware at present.
-Binman can update the device tree with the final location of everything when it
-is done. Entry positions can be provided to U-Boot SPL as run-time symbols,
-avoiding device-tree code overhead.
+Executable binaries can access the location of other binaries in an image by
+using special linker symbols (zero-overhead but somewhat limited) or by reading
+the devicetree description of the image.
-Binman can also support incorporating filesystems in the image if required.
-For example x86 platforms may use CBFS in some cases.
+Binman is designed primarily for use with U-Boot and associated binaries such
+as ARM Trusted Firmware, but it is suitable for use with other projects, such
+as Zephyr. Binman also provides facilities useful in Chromium OS, such as CBFS,
+vblocks and and the like.
+
+Binman provides a way to process binaries before they are included, by adding a
+Python plug-in.
Binman is intended for use with U-Boot but is designed to be general enough
to be useful in other image-packaging situations.
@@ -50,11 +54,11 @@ to be useful in other image-packaging situations.
Motivation
----------
-Packaging of firmware is quite a different task from building the various
-parts. In many cases the various binaries which go into the image come from
-separate build systems. For example, ARM Trusted Firmware is used on ARMv8
-devices but is not built in the U-Boot tree. If a Linux kernel is included
-in the firmware image, it is built elsewhere.
+As mentioned above, packaging of firmware is quite a different task from
+building the various parts. In many cases the various binaries which go into
+the image come from separate build systems. For example, ARM Trusted Firmware
+is used on ARMv8 devices but is not built in the U-Boot tree. If a Linux kernel
+is included in the firmware image, it is built elsewhere.
It is of course possible to add more and more build rules to the U-Boot
build system to cover these cases. It can shell out to other Makefiles and
@@ -67,18 +71,19 @@ standard format, we can support making valid images for any board without
manual effort, lots of READMEs, etc.
Benefits:
-- Each binary can have its own build system and tool chain without creating
-any dependencies between them
-- Avoids the need for a single-shot build: individual parts can be updated
-and brought in as needed
-- Provides for a standard image description available in the build and at
-run-time
-- SoC-specific image-signing tools can be accommodated
-- Avoids cluttering the U-Boot build system with image-building code
-- The image description is automatically available at run-time in U-Boot,
-SPL. It can be made available to other software also
-- The image description is easily readable (it's a text file in device-tree
-format) and permits flexible packing of binaries
+
+ - Each binary can have its own build system and tool chain without creating
+ any dependencies between them
+ - Avoids the need for a single-shot build: individual parts can be updated
+ and brought in as needed
+ - Provides for a standard image description available in the build and at
+ run-time
+ - SoC-specific image-signing tools can be accommodated
+ - Avoids cluttering the U-Boot build system with image-building code
+ - The image description is automatically available at run-time in U-Boot,
+ SPL. It can be made available to other software also
+ - The image description is easily readable (it's a text file in device-tree
+ format) and permits flexible packing of binaries
Terminology
@@ -136,6 +141,9 @@ the boundaries between building input files (mkimage) and packaging then
into a final image (binman).
+Using binman
+============
+
Example use of binman in U-Boot
-------------------------------
@@ -144,14 +152,14 @@ build system.
Consider sunxi. It has the following steps:
-1. It uses a custom mksunxiboot tool to build an SPL image called
-sunxi-spl.bin. This should probably move into mkimage.
+ #. It uses a custom mksunxiboot tool to build an SPL image called
+ sunxi-spl.bin. This should probably move into mkimage.
-2. It uses mkimage to package U-Boot into a legacy image file (so that it can
-hold the load and execution address) called u-boot.img.
+ #. It uses mkimage to package U-Boot into a legacy image file (so that it can
+ hold the load and execution address) called u-boot.img.
-3. It builds a final output image called u-boot-sunxi-with-spl.bin which
-consists of sunxi-spl.bin, some padding and u-boot.img.
+ #. It builds a final output image called u-boot-sunxi-with-spl.bin which
+ consists of sunxi-spl.bin, some padding and u-boot.img.
Binman is intended to replace the last step. The U-Boot build system builds
u-boot.bin and sunxi-spl.bin. Binman can then take over creation of
@@ -180,22 +188,22 @@ the configuration of the Intel-format descriptor.
Running binman
--------------
-First install prerequisites, e.g.
+First install prerequisites, e.g::
- sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
- liblz4-tool
+ sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
+ liblz4-tool
-Type:
+Type::
- binman build -b <board_name>
+ binman build -b <board_name>
to build an image for a board. The board name is the same name used when
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
Binman assumes that the input files for the build are in ../b/<board_name>.
-Or you can specify this explicitly:
+Or you can specify this explicitly::
- binman build -I <build_path>
+ binman build -I <build_path>
where <build_path> is the build directory containing the output of the U-Boot
build.
@@ -211,17 +219,12 @@ Binman has a few other options which you can see by running 'binman -h'.
Enabling binman for a board
---------------------------
-At present binman is invoked from a rule in the main Makefile. Typically you
-will have a rule like:
+At present binman is invoked from a rule in the main Makefile. You should be
+able to enable CONFIG_BINMAN to enable this rule.
-ifneq ($(CONFIG_ARCH_<something>),)
-u-boot-<your_suffix>.bin: <input_file_1> <input_file_2> checkbinman FORCE
- $(call if_changed,binman)
-endif
-
-This assumes that u-boot-<your_suffix>.bin is a target, and is the final file
-that you need to produce. You can make it a target by adding it to INPUTS-y
-either in the main Makefile or in a config.mk file in your arch subdirectory.
+The output file is typically named image.bin and is located in the output
+directory. If input files are needed to you add these to INPUTS-y either in the
+main Makefile or in a config.mk file in your arch subdirectory.
Once binman is executed it will pick up its instructions from a device-tree
file, typically <soc>-u-boot.dtsi, where <soc> is your CONFIG_SYS_SOC value.
@@ -229,22 +232,125 @@ You can use other, more specific CONFIG options - see 'Automatic .dtsi
inclusion' below.
+Access to binman entry offsets at run time (symbols)
+----------------------------------------------------
+
+Binman assembles images and determines where each entry is placed in the image.
+This information may be useful to U-Boot at run time. For example, in SPL it
+is useful to be able to find the location of U-Boot so that it can be executed
+when SPL is finished.
+
+Binman allows you to declare symbols in the SPL image which are filled in
+with their correct values during the build. For example::
+
+ binman_sym_declare(ulong, u_boot_any, image_pos);
+
+declares a ulong value which will be assigned to the image-pos of any U-Boot
+image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
+You can access this value with something like::
+
+ ulong u_boot_offset = binman_sym(ulong, u_boot_any, image_pos);
+
+Thus u_boot_offset will be set to the image-pos of U-Boot in memory, assuming
+that the whole image has been loaded, or is available in flash. You can then
+jump to that address to start U-Boot.
+
+At present this feature is only supported in SPL and TPL. In principle it is
+possible to fill in such symbols in U-Boot proper, as well, but a future C
+library is planned for this instead, to read from the device tree.
+
+As well as image-pos, it is possible to read the size of an entry and its
+offset (which is the start position of the entry within its parent).
+
+A small technical note: Binman automatically adds the base address of the image
+(i.e. __image_copy_start) to the value of the image-pos symbol, so that when the
+image is loaded to its linked address, the value will be correct and actually
+point into the image.
+
+For example, say SPL is at the start of the image and linked to start at address
+80108000. If U-Boot's image-pos is 0x8000 then binman will write an image-pos
+for U-Boot of 80110000 into the SPL binary, since it assumes the image is loaded
+to 80108000, with SPL at 80108000 and U-Boot at 80110000.
+
+For x86 devices (with the end-at-4gb property) this base address is not added
+since it is assumed that images are XIP and the offsets already include the
+address.
+
+
+Access to binman entry offsets at run time (fdt)
+------------------------------------------------
+
+Binman can update the U-Boot FDT to include the final position and size of
+each entry in the images it processes. The option to enable this is -u and it
+causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
+are set correctly for every entry. Since it is not necessary to specify these in
+the image definition, binman calculates the final values and writes these to
+the device tree. These can be used by U-Boot at run-time to find the location
+of each entry.
+
+Alternatively, an FDT map entry can be used to add a special FDT containing
+just the information about the image. This is preceded by a magic string so can
+be located anywhere in the image. An image header (typically at the start or end
+of the image) can be used to point to the FDT map. See fdtmap and image-header
+entries for more information.
+
+
+Map files
+---------
+
+The -m option causes binman to output a .map file for each image that it
+generates. This shows the offset and size of each entry. For example::
+
+ Offset Size Name
+ 00000000 00000028 main-section
+ 00000000 00000010 section@0
+ 00000000 00000004 u-boot
+ 00000010 00000010 section@1
+ 00000000 00000004 u-boot
+
+This shows a hierarchical image with two sections, each with a single entry. The
+offsets of the sections are absolute hex byte offsets within the image. The
+offsets of the entries are relative to their respective sections. The size of
+each entry is also shown, in bytes (hex). The indentation shows the entries
+nested inside their sections.
+
+
+Passing command-line arguments to entries
+-----------------------------------------
+
+Sometimes it is useful to pass binman the value of an entry property from the
+command line. For example some entries need access to files and it is not
+always convenient to put these filenames in the image definition (device tree).
+
+The-a option supports this::
+
+ -a<prop>=<value>
+
+where::
+
+ <prop> is the property to set
+ <value> is the value to set it to
+
+Not all properties can be provided this way. Only some entries support it,
+typically for filenames.
+
+
Image description format
-------------------------
+========================
The binman node is called 'binman'. An example image description is shown
-below:
-
- binman {
- filename = "u-boot-sunxi-with-spl.bin";
- pad-byte = <0xff>;
- blob {
- filename = "spl/sunxi-spl.bin";
- };
- u-boot {
- offset = <CONFIG_SPL_PAD_TO>;
- };
- };
+below::
+
+ binman {
+ filename = "u-boot-sunxi-with-spl.bin";
+ pad-byte = <0xff>;
+ blob {
+ filename = "spl/sunxi-spl.bin";
+ };
+ u-boot {
+ offset = <CONFIG_SPL_PAD_TO>;
+ };
+ };
This requests binman to create an image file called u-boot-sunxi-with-spl.bin
@@ -270,184 +376,184 @@ use any unique name, with the 'type' property providing the type.
The attributes supported for entries are described below.
offset:
- This sets the offset of an entry within the image or section containing
- it. The first byte of the image is normally at offset 0. If 'offset' is
- not provided, binman sets it to the end of the previous region, or the
- start of the image's entry area (normally 0) if there is no previous
- region.
+ This sets the offset of an entry within the image or section containing
+ it. The first byte of the image is normally at offset 0. If 'offset' is
+ not provided, binman sets it to the end of the previous region, or the
+ start of the image's entry area (normally 0) if there is no previous
+ region.
align:
- This sets the alignment of the entry. The entry offset is adjusted
- so that the entry starts on an aligned boundary within the containing
- section or image. For example 'align = <16>' means that the entry will
- start on a 16-byte boundary. This may mean that padding is added before
- the entry. The padding is part of the containing section but is not
- included in the entry, meaning that an empty space may be created before
- the entry starts. Alignment should be a power of 2. If 'align' is not
- provided, no alignment is performed.
+ This sets the alignment of the entry. The entry offset is adjusted
+ so that the entry starts on an aligned boundary within the containing
+ section or image. For example 'align = <16>' means that the entry will
+ start on a 16-byte boundary. This may mean that padding is added before
+ the entry. The padding is part of the containing section but is not
+ included in the entry, meaning that an empty space may be created before
+ the entry starts. Alignment should be a power of 2. If 'align' is not
+ provided, no alignment is performed.
size:
- This sets the size of the entry. The contents will be padded out to
- this size. If this is not provided, it will be set to the size of the
- contents.
+ This sets the size of the entry. The contents will be padded out to
+ this size. If this is not provided, it will be set to the size of the
+ contents.
pad-before:
- Padding before the contents of the entry. Normally this is 0, meaning
- that the contents start at the beginning of the entry. This can be used
- to offset the entry contents a little. While this does not affect the
- contents of the entry within binman itself (the padding is performed
- only when its parent section is assembled), the end result will be that
- the entry starts with the padding bytes, so may grow. Defaults to 0.
+ Padding before the contents of the entry. Normally this is 0, meaning
+ that the contents start at the beginning of the entry. This can be used
+ to offset the entry contents a little. While this does not affect the
+ contents of the entry within binman itself (the padding is performed
+ only when its parent section is assembled), the end result will be that
+ the entry starts with the padding bytes, so may grow. Defaults to 0.
pad-after:
- Padding after the contents of the entry. Normally this is 0, meaning
- that the entry ends at the last byte of content (unless adjusted by
- other properties). This allows room to be created in the image for
- this entry to expand later. While this does not affect the contents of
- the entry within binman itself (the padding is performed only when its
- parent section is assembled), the end result will be that the entry ends
- with the padding bytes, so may grow. Defaults to 0.
+ Padding after the contents of the entry. Normally this is 0, meaning
+ that the entry ends at the last byte of content (unless adjusted by
+ other properties). This allows room to be created in the image for
+ this entry to expand later. While this does not affect the contents of
+ the entry within binman itself (the padding is performed only when its
+ parent section is assembled), the end result will be that the entry ends
+ with the padding bytes, so may grow. Defaults to 0.
align-size:
- This sets the alignment of the entry size. For example, to ensure
- that the size of an entry is a multiple of 64 bytes, set this to 64.
- While this does not affect the contents of the entry within binman
- itself (the padding is performed only when its parent section is
- assembled), the end result is that the entry ends with the padding
- bytes, so may grow. If 'align-size' is not provided, no alignment is
- performed.
+ This sets the alignment of the entry size. For example, to ensure
+ that the size of an entry is a multiple of 64 bytes, set this to 64.
+ While this does not affect the contents of the entry within binman
+ itself (the padding is performed only when its parent section is
+ assembled), the end result is that the entry ends with the padding
+ bytes, so may grow. If 'align-size' is not provided, no alignment is
+ performed.
align-end:
- This sets the alignment of the end of an entry with respect to the
- containing section. Some entries require that they end on an alignment
- boundary, regardless of where they start. This does not move the start
- of the entry, so the contents of the entry will still start at the
- beginning. But there may be padding at the end. While this does not
- affect the contents of the entry within binman itself (the padding is
- performed only when its parent section is assembled), the end result
- is that the entry ends with the padding bytes, so may grow.
- If 'align-end' is not provided, no alignment is performed.
+ This sets the alignment of the end of an entry with respect to the
+ containing section. Some entries require that they end on an alignment
+ boundary, regardless of where they start. This does not move the start
+ of the entry, so the contents of the entry will still start at the
+ beginning. But there may be padding at the end. While this does not
+ affect the contents of the entry within binman itself (the padding is
+ performed only when its parent section is assembled), the end result
+ is that the entry ends with the padding bytes, so may grow.
+ If 'align-end' is not provided, no alignment is performed.
filename:
- For 'blob' types this provides the filename containing the binary to
- put into the entry. If binman knows about the entry type (like
- u-boot-bin), then there is no need to specify this.
+ For 'blob' types this provides the filename containing the binary to
+ put into the entry. If binman knows about the entry type (like
+ u-boot-bin), then there is no need to specify this.
type:
- Sets the type of an entry. This defaults to the entry name, but it is
- possible to use any name, and then add (for example) 'type = "u-boot"'
- to specify the type.
+ Sets the type of an entry. This defaults to the entry name, but it is
+ possible to use any name, and then add (for example) 'type = "u-boot"'
+ to specify the type.
offset-unset:
- Indicates that the offset of this entry should not be set by placing
- it immediately after the entry before. Instead, is set by another
- entry which knows where this entry should go. When this boolean
- property is present, binman will give an error if another entry does
- not set the offset (with the GetOffsets() method).
+ Indicates that the offset of this entry should not be set by placing
+ it immediately after the entry before. Instead, is set by another
+ entry which knows where this entry should go. When this boolean
+ property is present, binman will give an error if another entry does
+ not set the offset (with the GetOffsets() method).
image-pos:
- This cannot be set on entry (or at least it is ignored if it is), but
- with the -u option, binman will set it to the absolute image position
- for each entry. This makes it easy to find out exactly where the entry
- ended up in the image, regardless of parent sections, etc.
+ This cannot be set on entry (or at least it is ignored if it is), but
+ with the -u option, binman will set it to the absolute image position
+ for each entry. This makes it easy to find out exactly where the entry
+ ended up in the image, regardless of parent sections, etc.
expand-size:
- Expand the size of this entry to fit available space. This space is only
- limited by the size of the image/section and the position of the next
- entry.
+ Expand the size of this entry to fit available space. This space is only
+ limited by the size of the image/section and the position of the next
+ entry.
compress:
- Sets the compression algortihm to use (for blobs only). See the entry
- documentation for details.
+ Sets the compression algortihm to use (for blobs only). See the entry
+ documentation for details.
missing-msg:
- Sets the tag of the message to show if this entry is missing. This is
- used for external blobs. When they are missing it is helpful to show
- information about what needs to be fixed. See missing-blob-help for the
- message for each tag.
+ Sets the tag of the message to show if this entry is missing. This is
+ used for external blobs. When they are missing it is helpful to show
+ information about what needs to be fixed. See missing-blob-help for the
+ message for each tag.
The attributes supported for images and sections are described below. Several
are similar to those for entries.
size:
- Sets the image size in bytes, for example 'size = <0x100000>' for a
- 1MB image.
+ Sets the image size in bytes, for example 'size = <0x100000>' for a
+ 1MB image.
offset:
- This is similar to 'offset' in entries, setting the offset of a section
- within the image or section containing it. The first byte of the section
- is normally at offset 0. If 'offset' is not provided, binman sets it to
- the end of the previous region, or the start of the image's entry area
- (normally 0) if there is no previous region.
+ This is similar to 'offset' in entries, setting the offset of a section
+ within the image or section containing it. The first byte of the section
+ is normally at offset 0. If 'offset' is not provided, binman sets it to
+ the end of the previous region, or the start of the image's entry area
+ (normally 0) if there is no previous region.
align-size:
- This sets the alignment of the image size. For example, to ensure
- that the image ends on a 512-byte boundary, use 'align-size = <512>'.
- If 'align-size' is not provided, no alignment is performed.
+ This sets the alignment of the image size. For example, to ensure
+ that the image ends on a 512-byte boundary, use 'align-size = <512>'.
+ If 'align-size' is not provided, no alignment is performed.
pad-before:
- This sets the padding before the image entries. The first entry will
- be positioned after the padding. This defaults to 0.
+ This sets the padding before the image entries. The first entry will
+ be positioned after the padding. This defaults to 0.
pad-after:
- This sets the padding after the image entries. The padding will be
- placed after the last entry. This defaults to 0.
+ This sets the padding after the image entries. The padding will be
+ placed after the last entry. This defaults to 0.
pad-byte:
- This specifies the pad byte to use when padding in the image. It
- defaults to 0. To use 0xff, you would add 'pad-byte = <0xff>'.
+ This specifies the pad byte to use when padding in the image. It
+ defaults to 0. To use 0xff, you would add 'pad-byte = <0xff>'.
filename:
- This specifies the image filename. It defaults to 'image.bin'.
+ This specifies the image filename. It defaults to 'image.bin'.
sort-by-offset:
- This causes binman to reorder the entries as needed to make sure they
- are in increasing positional order. This can be used when your entry
- order may not match the positional order. A common situation is where
- the 'offset' properties are set by CONFIG options, so their ordering is
- not known a priori.
+ This causes binman to reorder the entries as needed to make sure they
+ are in increasing positional order. This can be used when your entry
+ order may not match the positional order. A common situation is where
+ the 'offset' properties are set by CONFIG options, so their ordering is
+ not known a priori.
- This is a boolean property so needs no value. To enable it, add a
- line 'sort-by-offset;' to your description.
+ This is a boolean property so needs no value. To enable it, add a
+ line 'sort-by-offset;' to your description.
multiple-images:
- Normally only a single image is generated. To create more than one
- image, put this property in the binman node. For example, this will
- create image1.bin containing u-boot.bin, and image2.bin containing
- both spl/u-boot-spl.bin and u-boot.bin:
-
- binman {
- multiple-images;
- image1 {
- u-boot {
- };
- };
-
- image2 {
- spl {
- };
- u-boot {
- };
- };
- };
+ Normally only a single image is generated. To create more than one
+ image, put this property in the binman node. For example, this will
+ create image1.bin containing u-boot.bin, and image2.bin containing
+ both spl/u-boot-spl.bin and u-boot.bin::
+
+ binman {
+ multiple-images;
+ image1 {
+ u-boot {
+ };
+ };
+
+ image2 {
+ spl {
+ };
+ u-boot {
+ };
+ };
+ };
end-at-4gb:
- For x86 machines the ROM offsets start just before 4GB and extend
- up so that the image finished at the 4GB boundary. This boolean
- option can be enabled to support this. The image size must be
- provided so that binman knows when the image should start. For an
- 8MB ROM, the offset of the first entry would be 0xfff80000 with
- this option, instead of 0 without this option.
+ For x86 machines the ROM offsets start just before 4GB and extend
+ up so that the image finished at the 4GB boundary. This boolean
+ option can be enabled to support this. The image size must be
+ provided so that binman knows when the image should start. For an
+ 8MB ROM, the offset of the first entry would be 0xfff80000 with
+ this option, instead of 0 without this option.
skip-at-start:
- This property specifies the entry offset of the first entry.
+ This property specifies the entry offset of the first entry.
- For PowerPC mpc85xx based CPU, CONFIG_SYS_TEXT_BASE is the entry
- offset of the first entry. It can be 0xeff40000 or 0xfff40000 for
- nor flash boot, 0x201000 for sd boot etc.
+ For PowerPC mpc85xx based CPU, CONFIG_SYS_TEXT_BASE is the entry
+ offset of the first entry. It can be 0xeff40000 or 0xfff40000 for
+ nor flash boot, 0x201000 for sd boot etc.
- 'end-at-4gb' property is not applicable where CONFIG_SYS_TEXT_BASE +
- Image size != 4gb.
+ 'end-at-4gb' property is not applicable where CONFIG_SYS_TEXT_BASE +
+ Image size != 4gb.
Examples of the above options can be found in the tests. See the
tools/binman/test directory.
@@ -470,23 +576,23 @@ This feature provides a way of creating hierarchical images. For example here
is an example image with two copies of U-Boot. One is read-only (ro), intended
to be written only in the factory. Another is read-write (rw), so that it can be
upgraded in the field. The sizes are fixed so that the ro/rw boundary is known
-and can be programmed:
-
- binman {
- section@0 {
- read-only;
- name-prefix = "ro-";
- size = <0x100000>;
- u-boot {
- };
- };
- section@1 {
- name-prefix = "rw-";
- size = <0x100000>;
- u-boot {
- };
- };
- };
+and can be programmed::
+
+ binman {
+ section@0 {
+ read-only;
+ name-prefix = "ro-";
+ size = <0x100000>;
+ u-boot {
+ };
+ };
+ section@1 {
+ name-prefix = "rw-";
+ size = <0x100000>;
+ u-boot {
+ };
+ };
+ };
This image could be placed into a SPI flash chip, with the protection boundary
set at 1MB.
@@ -494,14 +600,14 @@ set at 1MB.
A few special properties are provided for sections:
read-only:
- Indicates that this section is read-only. This has no impact on binman's
- operation, but his property can be read at run time.
+ Indicates that this section is read-only. This has no impact on binman's
+ operation, but his property can be read at run time.
name-prefix:
- This string is prepended to all the names of the binaries in the
- section. In the example above, the 'u-boot' binaries which actually be
- renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
- distinguish binaries with otherwise identical names.
+ This string is prepended to all the names of the binaries in the
+ section. In the example above, the 'u-boot' binaries which actually be
+ renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
+ distinguish binaries with otherwise identical names.
Image Properties
@@ -510,37 +616,196 @@ Image Properties
Image nodes act like sections but also have a few extra properties:
filename:
- Output filename for the image. This defaults to image.bin (or in the
- case of multiple images <nodename>.bin where <nodename> is the name of
- the image node.
+ Output filename for the image. This defaults to image.bin (or in the
+ case of multiple images <nodename>.bin where <nodename> is the name of
+ the image node.
allow-repack:
- Create an image that can be repacked. With this option it is possible
- to change anything in the image after it is created, including updating
- the position and size of image components. By default this is not
- permitted since it is not possibly to know whether this might violate a
- constraint in the image description. For example, if a section has to
- increase in size to hold a larger binary, that might cause the section
- to fall out of its allow region (e.g. read-only portion of flash).
+ Create an image that can be repacked. With this option it is possible
+ to change anything in the image after it is created, including updating
+ the position and size of image components. By default this is not
+ permitted since it is not possibly to know whether this might violate a
+ constraint in the image description. For example, if a section has to
+ increase in size to hold a larger binary, that might cause the section
+ to fall out of its allow region (e.g. read-only portion of flash).
+
+ Adding this property causes the original offset and size values in the
+ image description to be stored in the FDT and fdtmap.
+
+
+Hashing Entries
+---------------
+
+It is possible to ask binman to hash the contents of an entry and write that
+value back to the device-tree node. For example::
+
+ binman {
+ u-boot {
+ hash {
+ algo = "sha256";
+ };
+ };
+ };
+
+Here, a new 'value' property will be written to the 'hash' node containing
+the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
+sections can be hased if desired, by adding the 'hash' node to the section.
+
+The has value can be chcked at runtime by hashing the data actually read and
+comparing this has to the value in the device tree.
+
+
+Expanded entries
+----------------
+
+Binman automatically replaces 'u-boot' with an expanded version of that, i.e.
+'u-boot-expanded'. This means that when you write::
+
+ u-boot {
+ };
+
+you actually get::
+
+ u-boot {
+ type = "u-boot-expanded';
+ };
+
+which in turn expands to::
+
+ u-boot {
+ type = "section";
+
+ u-boot-nodtb {
+ };
+
+ u-boot-dtb {
+ };
+ };
+
+U-Boot's various phase binaries actually comprise two or three pieces.
+For example, u-boot.bin has the executable followed by a devicetree.
+
+With binman we want to be able to update that devicetree with full image
+information so that it is accessible to the executable. This is tricky
+if it is not clear where the devicetree starts.
+
+The above feature ensures that the devicetree is clearly separated from the
+U-Boot executable and can be updated separately by binman as needed. It can be
+disabled with the --no-expanded flag if required.
+
+The same applies for u-boot-spl and u-boot-spl. In those cases, the expansion
+includes the BSS padding, so for example::
+
+ spl {
+ type = "u-boot-spl"
+ };
+
+you actually get::
+
+ spl {
+ type = "u-boot-expanded';
+ };
+
+which in turn expands to::
+
+ spl {
+ type = "section";
+
+ u-boot-spl-nodtb {
+ };
+
+ u-boot-spl-bss-pad {
+ };
+
+ u-boot-spl-dtb {
+ };
+ };
+
+Of course we should not expand SPL if it has no devicetree. Also if the BSS
+padding is not needed (because BSS is in RAM as with CONFIG_SPL_SEPARATE_BSS),
+the 'u-boot-spl-bss-pad' subnode should not be created. The use of the expaned
+entry type is controlled by the UseExpanded() method. In the SPL case it checks
+the 'spl-dtb' entry arg, which is 'y' or '1' if SPL has a devicetree.
+
+For the BSS case, a 'spl-bss-pad' entry arg controls whether it is present. All
+entry args are provided by the U-Boot Makefile.
+
+
+Compression
+-----------
+
+Binman support compression for 'blob' entries (those of type 'blob' and
+derivatives). To enable this for an entry, add a 'compress' property::
+
+ blob {
+ filename = "datafile";
+ compress = "lz4";
+ };
+
+The entry will then contain the compressed data, using the 'lz4' compression
+algorithm. Currently this is the only one that is supported. The uncompressed
+size is written to the node in an 'uncomp-size' property, if -u is used.
+
+Compression is also supported for sections. In that case the entire section is
+compressed in one block, including all its contents. This means that accessing
+an entry from the section required decompressing the entire section. Also, the
+size of a section indicates the space that it consumes in its parent section
+(and typically the image). With compression, the section may contain more data,
+and the uncomp-size property indicates that, as above. The contents of the
+section is compressed first, before any padding is added. This ensures that the
+padding itself is not compressed, which would be a waste of time.
+
+
+Automatic .dtsi inclusion
+-------------------------
+
+It is sometimes inconvenient to add a 'binman' node to the .dts file for each
+board. This can be done by using #include to bring in a common file. Another
+approach supported by the U-Boot build system is to automatically include
+a common header. You can then put the binman node (and anything else that is
+specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
+file.
- Adding this property causes the original offset and size values in the
- image description to be stored in the FDT and fdtmap.
+Binman will search for the following files in arch/<arch>/dts::
+
+ <dts>-u-boot.dtsi where <dts> is the base name of the .dts file
+ <CONFIG_SYS_SOC>-u-boot.dtsi
+ <CONFIG_SYS_CPU>-u-boot.dtsi
+ <CONFIG_SYS_VENDOR>-u-boot.dtsi
+ u-boot.dtsi
+
+U-Boot will only use the first one that it finds. If you need to include a
+more general file you can do that from the more specific file using #include.
+If you are having trouble figuring out what is going on, you can uncomment
+the 'warning' line in scripts/Makefile.lib to see what it has found::
+
+ # Uncomment for debugging
+ # This shows all the files that were considered and the one that we chose.
+ # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
Entry Documentation
--------------------
+===================
For details on the various entry types supported by binman and how to use them,
-see README.entries. This is generated from the source code using:
+see entries.rst which is generated from the source code using:
+
+ binman entry-docs >tools/binman/entries.rst
+
+.. toctree::
+ :maxdepth: 2
+
+ entries
- binman entry-docs >tools/binman/README.entries
+Managing images
+===============
Listing images
--------------
It is possible to list the entries in an existing firmware image created by
-binman, provided that there is an 'fdtmap' entry in the image. For example:
+binman, provided that there is an 'fdtmap' entry in the image. For example::
$ binman ls -i image.bin
Name Image-pos Size Entry-type Offset Uncomp-size
@@ -559,7 +824,7 @@ This shows the hierarchy of the image, the position, size and type of each
entry, the offset of each entry within its parent and the uncompressed size if
the entry is compressed.
-It is also possible to list just some files in an image, e.g.
+It is also possible to list just some files in an image, e.g.::
$ binman ls -i image.bin section/cbfs
Name Image-pos Size Entry-type Offset Uncomp-size
@@ -568,7 +833,7 @@ It is also possible to list just some files in an image, e.g.
u-boot 138 4 u-boot 38
u-boot-dtb 180 108 u-boot-dtb 80 3b5
-or with wildcards:
+or with wildcards::
$ binman ls -i image.bin "*cb*" "*head*"
Name Image-pos Size Entry-type Offset Uncomp-size
@@ -583,22 +848,22 @@ Extracting files from images
----------------------------
You can extract files from an existing firmware image created by binman,
-provided that there is an 'fdtmap' entry in the image. For example:
+provided that there is an 'fdtmap' entry in the image. For example::
$ binman extract -i image.bin section/cbfs/u-boot
which will write the uncompressed contents of that entry to the file 'u-boot' in
the current directory. You can also extract to a particular file, in this case
-u-boot.bin:
+u-boot.bin::
$ binman extract -i image.bin section/cbfs/u-boot -f u-boot.bin
It is possible to extract all files into a destination directory, which will
-put files in subdirectories matching the entry hierarchy:
+put files in subdirectories matching the entry hierarchy::
$ binman extract -i image.bin -O outdir
-or just a selection:
+or just a selection::
$ binman extract -i image.bin "*u-boot*" -O outdir
@@ -616,18 +881,18 @@ to the that entry, compressing if necessary. If the entry size changes, you must
add the 'allow-repack' property to the original image before generating it (see
above), otherwise you will get an error.
-You can also use a particular file, in this case u-boot.bin:
+You can also use a particular file, in this case u-boot.bin::
$ binman replace -i image.bin section/cbfs/u-boot -f u-boot.bin
It is possible to replace all files from a source directory which uses the same
-hierarchy as the entries:
+hierarchy as the entries::
$ binman replace -i image.bin -I indir
Files that are missing will generate a warning.
-You can also replace just a selection of entries:
+You can also replace just a selection of entries::
$ binman replace -i image.bin "*u-boot*" -I indir
@@ -652,27 +917,9 @@ by increasing the -v/--verbosity from the default of 1:
You can use BINMAN_VERBOSE=5 (for example) when building to select this.
-Hashing Entries
----------------
-
-It is possible to ask binman to hash the contents of an entry and write that
-value back to the device-tree node. For example:
-
- binman {
- u-boot {
- hash {
- algo = "sha256";
- };
- };
- };
-
-Here, a new 'value' property will be written to the 'hash' node containing
-the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
-sections can be hased if desired, by adding the 'hash' node to the section.
-
-The has value can be chcked at runtime by hashing the data actually read and
-comparing this has to the value in the device tree.
+Technical details
+=================
Order of image creation
-----------------------
@@ -749,162 +996,6 @@ what happens in this stage.
final step.
-Automatic .dtsi inclusion
--------------------------
-
-It is sometimes inconvenient to add a 'binman' node to the .dts file for each
-board. This can be done by using #include to bring in a common file. Another
-approach supported by the U-Boot build system is to automatically include
-a common header. You can then put the binman node (and anything else that is
-specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
-file.
-
-Binman will search for the following files in arch/<arch>/dts:
-
- <dts>-u-boot.dtsi where <dts> is the base name of the .dts file
- <CONFIG_SYS_SOC>-u-boot.dtsi
- <CONFIG_SYS_CPU>-u-boot.dtsi
- <CONFIG_SYS_VENDOR>-u-boot.dtsi
- u-boot.dtsi
-
-U-Boot will only use the first one that it finds. If you need to include a
-more general file you can do that from the more specific file using #include.
-If you are having trouble figuring out what is going on, you can uncomment
-the 'warning' line in scripts/Makefile.lib to see what it has found:
-
- # Uncomment for debugging
- # This shows all the files that were considered and the one that we chose.
- # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
-
-
-Access to binman entry offsets at run time (symbols)
-----------------------------------------------------
-
-Binman assembles images and determines where each entry is placed in the image.
-This information may be useful to U-Boot at run time. For example, in SPL it
-is useful to be able to find the location of U-Boot so that it can be executed
-when SPL is finished.
-
-Binman allows you to declare symbols in the SPL image which are filled in
-with their correct values during the build. For example:
-
- binman_sym_declare(ulong, u_boot_any, image_pos);
-
-declares a ulong value which will be assigned to the image-pos of any U-Boot
-image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
-You can access this value with something like:
-
- ulong u_boot_offset = binman_sym(ulong, u_boot_any, image_pos);
-
-Thus u_boot_offset will be set to the image-pos of U-Boot in memory, assuming
-that the whole image has been loaded, or is available in flash. You can then
-jump to that address to start U-Boot.
-
-At present this feature is only supported in SPL and TPL. In principle it is
-possible to fill in such symbols in U-Boot proper, as well, but a future C
-library is planned for this instead, to read from the device tree.
-
-As well as image-pos, it is possible to read the size of an entry and its
-offset (which is the start position of the entry within its parent).
-
-A small technical note: Binman automatically adds the base address of the image
-(i.e. __image_copy_start) to the value of the image-pos symbol, so that when the
-image is loaded to its linked address, the value will be correct and actually
-point into the image.
-
-For example, say SPL is at the start of the image and linked to start at address
-80108000. If U-Boot's image-pos is 0x8000 then binman will write an image-pos
-for U-Boot of 80110000 into the SPL binary, since it assumes the image is loaded
-to 80108000, with SPL at 80108000 and U-Boot at 80110000.
-
-For x86 devices (with the end-at-4gb property) this base address is not added
-since it is assumed that images are XIP and the offsets already include the
-address.
-
-
-Access to binman entry offsets at run time (fdt)
-------------------------------------------------
-
-Binman can update the U-Boot FDT to include the final position and size of
-each entry in the images it processes. The option to enable this is -u and it
-causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
-are set correctly for every entry. Since it is not necessary to specify these in
-the image definition, binman calculates the final values and writes these to
-the device tree. These can be used by U-Boot at run-time to find the location
-of each entry.
-
-Alternatively, an FDT map entry can be used to add a special FDT containing
-just the information about the image. This is preceded by a magic string so can
-be located anywhere in the image. An image header (typically at the start or end
-of the image) can be used to point to the FDT map. See fdtmap and image-header
-entries for more information.
-
-
-Compression
------------
-
-Binman support compression for 'blob' entries (those of type 'blob' and
-derivatives). To enable this for an entry, add a 'compress' property:
-
- blob {
- filename = "datafile";
- compress = "lz4";
- };
-
-The entry will then contain the compressed data, using the 'lz4' compression
-algorithm. Currently this is the only one that is supported. The uncompressed
-size is written to the node in an 'uncomp-size' property, if -u is used.
-
-Compression is also supported for sections. In that case the entire section is
-compressed in one block, including all its contents. This means that accessing
-an entry from the section required decompressing the entire section. Also, the
-size of a section indicates the space that it consumes in its parent section
-(and typically the image). With compression, the section may contain more data,
-and the uncomp-size property indicates that, as above. The contents of the
-section is compressed first, before any padding is added. This ensures that the
-padding itself is not compressed, which would be a waste of time.
-
-
-Map files
----------
-
-The -m option causes binman to output a .map file for each image that it
-generates. This shows the offset and size of each entry. For example:
-
- Offset Size Name
- 00000000 00000028 main-section
- 00000000 00000010 section@0
- 00000000 00000004 u-boot
- 00000010 00000010 section@1
- 00000000 00000004 u-boot
-
-This shows a hierarchical image with two sections, each with a single entry. The
-offsets of the sections are absolute hex byte offsets within the image. The
-offsets of the entries are relative to their respective sections. The size of
-each entry is also shown, in bytes (hex). The indentation shows the entries
-nested inside their sections.
-
-
-Passing command-line arguments to entries
------------------------------------------
-
-Sometimes it is useful to pass binman the value of an entry property from the
-command line. For example some entries need access to files and it is not
-always convenient to put these filenames in the image definition (device tree).
-
-The-a option supports this:
-
- -a<prop>=<value>
-
-where
-
- <prop> is the property to set
- <value> is the value to set it to
-
-Not all properties can be provided this way. Only some entries support it,
-typically for filenames.
-
-
External tools
--------------
@@ -927,7 +1018,7 @@ Code coverage
Binman is a critical tool and is designed to be very testable. Entry
implementations target 100% test coverage. Run 'binman test -T' to check this.
-To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
+To enable Python test coverage on Debian-type distributions (e.g. Ubuntu)::
$ sudo apt-get install python-coverage python3-coverage python-pytest
@@ -938,7 +1029,7 @@ Concurrent tests
Binman tries to run tests concurrently. This means that the tests make use of
all available CPUs to run.
- To enable this:
+ To enable this::
$ sudo apt-get install python-subunit python3-subunit
@@ -961,19 +1052,19 @@ Binman's tests have been written under the assumption that they'll be run on a
x86-like host and there hasn't been an attempt to make them portable yet.
However, it's possible to run the tests by cross-compiling to x86.
-To install an x86 cross-compiler on Debian-type distributions (e.g. Ubuntu):
+To install an x86 cross-compiler on Debian-type distributions (e.g. Ubuntu)::
$ sudo apt-get install gcc-x86-64-linux-gnu
-Then, you can run the tests under cross-compilation:
+Then, you can run the tests under cross-compilation::
$ CROSS_COMPILE=x86_64-linux-gnu- binman test -T
You can also use gcc-i686-linux-gnu similar to the above.
-Advanced Features / Technical docs
-----------------------------------
+Writing new entries and debugging
+---------------------------------
The behaviour of entries is defined by the Entry class. All other entries are
a subclass of this. An important subclass is Entry_blob which takes binary
@@ -1001,13 +1092,13 @@ the DTC environment variable. This can be useful when the system dtc is too
old.
To enable a full backtrace and other debugging features in binman, pass
-BINMAN_DEBUG=1 to your build:
+BINMAN_DEBUG=1 to your build::
make qemu-x86_defconfig
make BINMAN_DEBUG=1
To enable verbose logging from binman, base BINMAN_VERBOSE to your build, which
-adds a -v<level> option to the call to binman:
+adds a -v<level> option to the call to binman::
make qemu-x86_defconfig
make BINMAN_VERBOSE=5
@@ -1047,8 +1138,10 @@ To do
-----
Some ideas:
+
- Use of-platdata to make the information available to code that is unable
- to use device tree (such as a very small SPL image)
+ to use device tree (such as a very small SPL image). For now, limited info is
+ available via linker symbols
- Allow easy building of images by specifying just the board name
- Support building an image for a board (-b) more completely, with a
configurable build directory
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index c007d0a..95f9ba2 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -56,6 +56,9 @@ controlled by a description in the board device tree.'''
default=False, help='Output a map file for each image')
build_parser.add_argument('-M', '--allow-missing', action='store_true',
default=False, help='Allow external blobs to be missing')
+ build_parser.add_argument('-n', '--no-expanded', action='store_true',
+ help="Don't use 'expanded' versions of entries where available; "
+ "normally 'u-boot' becomes 'u-boot-expanded', for example")
build_parser.add_argument('-O', '--outdir', type=str,
action='store', help='Path to directory to use for intermediate and '
'output files')
@@ -66,7 +69,7 @@ controlled by a description in the board device tree.'''
default=False, help='Update the binman node with offset/size info')
entry_parser = subparsers.add_parser('entry-docs',
- help='Write out entry documentation (see README.entries)')
+ help='Write out entry documentation (see entries.rst)')
list_parser = subparsers.add_parser('ls', help='List files in an image')
list_parser.add_argument('-i', '--image', type=str, required=True,
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 1952b2a..f57e34d 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -28,7 +28,7 @@ images = OrderedDict()
# value: Text for the help
missing_blob_help = {}
-def _ReadImageDesc(binman_node):
+def _ReadImageDesc(binman_node, use_expanded):
"""Read the image descriptions from the /binman node
This normally produces a single Image object called 'image'. But if
@@ -36,15 +36,17 @@ def _ReadImageDesc(binman_node):
Args:
binman_node: Node object of the /binman node
+ use_expanded: True if the FDT will be updated with the entry information
Returns:
OrderedDict of Image objects, each of which describes an image
"""
images = OrderedDict()
if 'multiple-images' in binman_node.props:
for node in binman_node.subnodes:
- images[node.name] = Image(node.name, node)
+ images[node.name] = Image(node.name, node,
+ use_expanded=use_expanded)
else:
- images['image'] = Image('image', binman_node)
+ images['image'] = Image('image', binman_node, use_expanded=use_expanded)
return images
def _FindBinmanNode(dtb):
@@ -241,7 +243,7 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
# If this entry has children, create a directory for it and put its
# data in a file called 'root' in that directory
if entry.GetEntries():
- if not os.path.exists(fname):
+ if fname and not os.path.exists(fname):
os.makedirs(fname)
fname = os.path.join(fname, 'root')
tout.Notice("Write entry '%s' size %x to '%s'" %
@@ -399,7 +401,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
return image
-def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
+def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
"""Prepare the images to be processed and select the device tree
This function:
@@ -413,6 +415,9 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
dtb_fname: Filename of the device tree file to use (.dts or .dtb)
selected_images: List of images to output, or None for all
update_fdt: True to update the FDT wth entry offsets, etc.
+ use_expanded: True to use expanded versions of entries, if available.
+ So if 'u-boot' is called for, we use 'u-boot-expanded' instead. This
+ is needed if update_fdt is True (although tests may disable it)
Returns:
OrderedDict of images:
@@ -438,7 +443,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
raise ValueError("Device tree '%s' does not have a 'binman' "
"node" % dtb_fname)
- images = _ReadImageDesc(node)
+ images = _ReadImageDesc(node, use_expanded)
if select_images:
skip = []
@@ -564,7 +569,7 @@ def Binman(args):
if not pager:
pager = 'more'
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
- 'README')
+ 'README.rst')
command.Run(pager, fname)
return 0
@@ -611,6 +616,13 @@ def Binman(args):
elf.debug = args.debug
cbfs_util.VERBOSE = args.verbosity > 2
state.use_fake_dtb = args.fake_dtb
+
+ # Normally we replace the 'u-boot' etype with 'u-boot-expanded', etc.
+ # When running tests this can be disabled using this flag. When not
+ # updating the FDT in image, it is not needed by binman, but we use it
+ # for consistency, so that the images look the same to U-Boot at
+ # runtime.
+ use_expanded = not args.no_expanded
try:
tools.SetInputDirs(args.indir)
tools.PrepareOutputDir(args.outdir, args.preserve)
@@ -618,7 +630,7 @@ def Binman(args):
state.SetEntryArgs(args.entry_arg)
images = PrepareImagesAndDtbs(dtb_fname, args.image,
- args.update_fdt)
+ args.update_fdt, use_expanded)
missing = False
for image in images.values():
missing |= ProcessImage(image, args.update_fdt, args.map,
diff --git a/tools/binman/README.entries b/tools/binman/entries.rst
index 999b776..f6faa15 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/entries.rst
@@ -11,8 +11,8 @@ features to produce new behaviours.
-Entry: atf-bl31: Entry containing an ARM Trusted Firmware (ATF) BL31 blob
--------------------------------------------------------------------------
+Entry: atf-bl31: ARM Trusted Firmware (ATF) BL31 blob
+-----------------------------------------------------
Properties / Entry arguments:
- atf-bl31-path: Filename of file to read into entry. This is typically
@@ -25,8 +25,8 @@ about ATF.
-Entry: blob: Entry containing an arbitrary binary blob
-------------------------------------------------------
+Entry: blob: Arbitrary binary blob
+----------------------------------
Note: This should not be used by itself. It is normally used as a parent
class by other entry types.
@@ -39,7 +39,7 @@ Properties / Entry arguments:
This entry reads data from a file and places it in the entry. The
default filename is often specified specified by the subclass. See for
-example the 'u_boot' entry which provides the filename 'u-boot.bin'.
+example the 'u-boot' entry which provides the filename 'u-boot.bin'.
If compression is enabled, an extra 'uncomp-size' property is written to
the node (if enabled with -u) which provides the uncompressed size of the
@@ -56,8 +56,8 @@ obtained from the list of available device-tree files, managed by the
-Entry: blob-ext: Entry containing an externally built binary blob
------------------------------------------------------------------
+Entry: blob-ext: Externally built binary blob
+---------------------------------------------
Note: This should not be used by itself. It is normally used as a parent
class by other entry types.
@@ -87,8 +87,17 @@ See cros_ec_rw for an example of this.
-Entry: cbfs: Entry containing a Coreboot Filesystem (CBFS)
-----------------------------------------------------------
+Entry: blob-phase: Section that holds a phase binary
+----------------------------------------------------
+
+This is a base class that should not normally be used directly. It is used
+when converting a 'u-boot' entry automatically into a 'u-boot-expanded'
+entry; similarly for SPL.
+
+
+
+Entry: cbfs: Coreboot Filesystem (CBFS)
+---------------------------------------
A CBFS provides a way to group files into a group. It has a simple directory
structure and allows the position of individual files to be set, since it is
@@ -97,7 +106,7 @@ is not used, it supports compression and storing ELF files.
CBFS is used by coreboot as its way of orgnanising SPI-flash contents.
-The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.:
+The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.::
cbfs {
size = <0x100000>;
@@ -113,7 +122,7 @@ This creates a CBFS 1MB in size two files in it: u-boot.bin and u-boot.dtb.
Note that the size is required since binman does not support calculating it.
The contents of each entry is just what binman would normally provide if it
were not a CBFS node. A blob type can be used to import arbitrary files as
-with the second subnode below:
+with the second subnode below::
cbfs {
size = <0x100000>;
@@ -159,7 +168,7 @@ cbfs-type:
This is an ELF file that has been loaded (i.e. mapped to memory), so
appears in the CBFS as a flat binary. The input file must be an ELF
image, for example this puts "u-boot" (the ELF image) into a 'stage'
- entry:
+ entry::
cbfs {
size = <0x100000>;
@@ -169,7 +178,7 @@ cbfs-type:
};
};
- You can use your own ELF file with something like:
+ You can use your own ELF file with something like::
cbfs {
size = <0x100000>;
@@ -202,7 +211,7 @@ not support other file types (e.g. payload), adding multiple files (like the
particular offset in the CBFS and a few other things.
Of course binman can create images containing multiple CBFSs, simply by
-defining these in the binman config:
+defining these in the binman config::
binman {
@@ -270,38 +279,39 @@ sizes are included.
Note that the -u option must be provided to ensure that binman updates the
FDT with the position of each entry.
-Example output for a simple image with U-Boot and an FDT map:
+Example output for a simple image with U-Boot and an FDT map::
-/ {
- image-name = "binman";
- size = <0x00000112>;
- image-pos = <0x00000000>;
- offset = <0x00000000>;
- u-boot {
- size = <0x00000004>;
+ / {
+ image-name = "binman";
+ size = <0x00000112>;
image-pos = <0x00000000>;
offset = <0x00000000>;
+ u-boot {
+ size = <0x00000004>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ };
+ fdtmap {
+ size = <0x0000010e>;
+ image-pos = <0x00000004>;
+ offset = <0x00000004>;
+ };
};
- fdtmap {
- size = <0x0000010e>;
- image-pos = <0x00000004>;
- offset = <0x00000004>;
- };
-};
If allow-repack is used then 'orig-offset' and 'orig-size' properties are
added as necessary. See the binman README.
-Entry: files: Entry containing a set of files
----------------------------------------------
+Entry: files: A set of files arranged in a section
+--------------------------------------------------
Properties / Entry arguments:
- pattern: Filename pattern to match the files to include
- files-compress: Compression algorithm to use:
none: No compression
lz4: Use lz4 compression (via 'lz4' command-line utility)
+ - files-align: Align each file to the given alignment
This entry reads a number of files and places each in a separate sub-entry
within this entry. To access these you need to enable device-tree updates
@@ -325,8 +335,8 @@ byte value of a region.
-Entry: fit: Entry containing a FIT
-----------------------------------
+Entry: fit: Flat Image Tree (FIT)
+---------------------------------
This calls mkimage to create a FIT (U-Boot Flat Image Tree) based on the
input provided.
@@ -334,7 +344,7 @@ input provided.
Nodes for the FIT should be written out in the binman configuration just as
they would be in a file passed to mkimage.
-For example, this creates an image containing a FIT with U-Boot SPL:
+For example, this creates an image containing a FIT with U-Boot SPL::
binman {
fit {
@@ -364,7 +374,7 @@ that you want to generates nodes for two files: file1.dtb and file2.dtb
The fit,fdt-list property (see above) indicates that of-list should be used.
If the property is missing you will get an error.
-Then add a 'generator node', a node with a name starting with '@':
+Then add a 'generator node', a node with a name starting with '@'::
images {
@fdt-SEQ {
@@ -379,7 +389,7 @@ files. All the properties you specify will be included in the node. This
node acts like a template to generate the nodes. The generator node itself
does not appear in the output - it is replaced with what binman generates.
-You can create config nodes in a similar way:
+You can create config nodes in a similar way::
configurations {
default = "@config-DEFAULT-SEQ";
@@ -396,8 +406,10 @@ each of your two files.
Available substitutions for '@' nodes are:
- SEQ Sequence number of the generated fdt (1, 2, ...)
- NAME Name of the dtb as provided (i.e. without adding '.dtb')
+SEQ:
+ Sequence number of the generated fdt (1, 2, ...)
+NAME
+ Name of the dtb as provided (i.e. without adding '.dtb')
Note that if no devicetree files are provided (with '-a of-list' as above)
then no nodes will be generated.
@@ -406,10 +418,11 @@ The 'default' property, if present, will be automatically set to the name
if of configuration whose devicetree matches the 'default-dt' entry
argument, e.g. with '-a default-dt=sun50i-a64-pine64-lts'.
-Available substitutions for '@' property values are:
+Available substitutions for '@' property values are
- DEFAULT-SEQ Sequence number of the default fdt,as provided by the
- 'default-dt' entry argument
+DEFAULT-SEQ:
+ Sequence number of the default fdt,as provided by the 'default-dt' entry
+ argument
Properties (in the 'fit' node itself):
fit,external-offset: Indicates that the contents of the FIT are external
@@ -478,8 +491,8 @@ first/last in the entry list.
-Entry: intel-cmc: Entry containing an Intel Chipset Micro Code (CMC) file
--------------------------------------------------------------------------
+Entry: intel-cmc: Intel Chipset Micro Code (CMC) file
+-----------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -531,8 +544,8 @@ This entry contains a pointer to the FIT. It is required to be at address
-Entry: intel-fsp: Entry containing an Intel Firmware Support Package (FSP) file
--------------------------------------------------------------------------------
+Entry: intel-fsp: Intel Firmware Support Package (FSP) file
+-----------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -548,8 +561,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-fsp-m: Entry containing Intel Firmware Support Package (FSP) memory init
--------------------------------------------------------------------------------------
+Entry: intel-fsp-m: Intel Firmware Support Package (FSP) memory init
+--------------------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -565,8 +578,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-fsp-s: Entry containing Intel Firmware Support Package (FSP) silicon init
---------------------------------------------------------------------------------------
+Entry: intel-fsp-s: Intel Firmware Support Package (FSP) silicon init
+---------------------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -582,8 +595,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-fsp-t: Entry containing Intel Firmware Support Package (FSP) temp ram init
----------------------------------------------------------------------------------------
+Entry: intel-fsp-t: Intel Firmware Support Package (FSP) temp ram init
+----------------------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -598,8 +611,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-ifwi: Entry containing an Intel Integrated Firmware Image (IFWI) file
-----------------------------------------------------------------------------------
+Entry: intel-ifwi: Intel Integrated Firmware Image (IFWI) file
+--------------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry. This is either the
@@ -623,17 +636,17 @@ Each subnode describes an entry which is placed into the IFWFI with a given
sub-partition (and optional entry name).
Properties for subnodes:
- ifwi-subpart - sub-parition to put this entry into, e.g. "IBBP"
- ifwi-entry - entry name t use, e.g. "IBBL"
- ifwi-replace - if present, indicates that the item should be replaced
- in the IFWI. Otherwise it is added.
+ - ifwi-subpart: sub-parition to put this entry into, e.g. "IBBP"
+ - ifwi-entry: entry name t use, e.g. "IBBL"
+ - ifwi-replace: if present, indicates that the item should be replaced
+ in the IFWI. Otherwise it is added.
See README.x86 for information about x86 binary blobs.
-Entry: intel-me: Entry containing an Intel Management Engine (ME) file
-----------------------------------------------------------------------
+Entry: intel-me: Intel Management Engine (ME) file
+--------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -652,8 +665,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-mrc: Entry containing an Intel Memory Reference Code (MRC) file
-----------------------------------------------------------------------------
+Entry: intel-mrc: Intel Memory Reference Code (MRC) file
+--------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -666,8 +679,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-refcode: Entry containing an Intel Reference Code file
--------------------------------------------------------------------
+Entry: intel-refcode: Intel Reference Code file
+-----------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -680,8 +693,8 @@ See README.x86 for information about x86 binary blobs.
-Entry: intel-vbt: Entry containing an Intel Video BIOS Table (VBT) file
------------------------------------------------------------------------
+Entry: intel-vbt: Intel Video BIOS Table (VBT) file
+---------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -693,8 +706,8 @@ See README.x86 for information about Intel binary blobs.
-Entry: intel-vga: Entry containing an Intel Video Graphics Adaptor (VGA) file
------------------------------------------------------------------------------
+Entry: intel-vga: Intel Video Graphics Adaptor (VGA) file
+---------------------------------------------------------
Properties / Entry arguments:
- filename: Filename of file to read into entry
@@ -708,15 +721,15 @@ See README.x86 for information about Intel binary blobs.
-Entry: mkimage: Entry containing a binary produced by mkimage
--------------------------------------------------------------
+Entry: mkimage: Binary produced by mkimage
+------------------------------------------
Properties / Entry arguments:
- datafile: Filename for -d argument
- args: Other arguments to pass
The data passed to mkimage is collected from subnodes of the mkimage node,
-e.g.:
+e.g.::
mkimage {
args = "-n test -T imximage";
@@ -743,8 +756,8 @@ placed at offset 'RESET_VECTOR_ADDRESS - 0xffc'.
-Entry: scp: Entry containing a System Control Processor (SCP) firmware blob
----------------------------------------------------------------------------
+Entry: scp: System Control Processor (SCP) firmware blob
+--------------------------------------------------------
Properties / Entry arguments:
- scp-path: Filename of file to read into the entry, typically scp.bin
@@ -756,11 +769,13 @@ This entry holds firmware for an external platform-specific coprocessor.
Entry: section: Entry that contains other entries
-------------------------------------------------
-Properties / Entry arguments: (see binman README for more information)
+Properties / Entry arguments: (see binman README for more information):
pad-byte: Pad byte to use when padding
sort-by-offset: True if entries should be sorted by offset, False if
- they must be in-order in the device tree description
+ they must be in-order in the device tree description
+
end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
+
skip-at-start: Number of bytes before the first entry starts. These
effectively adjust the starting offset of entries. For example,
if this is 16, then the first entry would start at 16. An entry
@@ -798,7 +813,7 @@ Properties / Entry arguments:
<text>: The text to place in the entry (overrides the above mechanism).
This is useful when the text is constant.
-Example node:
+Example node::
text {
size = <50>;
@@ -811,7 +826,7 @@ You can then use:
and binman will insert that string into the entry.
-It is also possible to put the string directly in the node:
+It is also possible to put the string directly in the node::
text {
size = <8>;
@@ -819,7 +834,7 @@ It is also possible to put the string directly in the node:
message = "a message directly in the node"
};
-or just:
+or just::
text {
size = <8>;
@@ -839,8 +854,7 @@ Properties / Entry arguments:
This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. The binary typically includes a device tree
-blob at the end of it. Use u_boot_nodtb if you want to package the device
-tree separately.
+blob at the end of it.
U-Boot can access binman symbols at runtime. See:
@@ -848,6 +862,9 @@ U-Boot can access binman symbols at runtime. See:
in the binman README for more information.
+Note that this entry is automatically replaced with u-boot-expanded unless
+--no-expanded is used.
+
Entry: u-boot-dtb: U-Boot device tree
@@ -875,9 +892,9 @@ See Entry_u_boot_ucode for full details of the three entries involved in
this process. This entry provides the U-Boot device-tree file, which
contains the microcode. If the microcode is not being collated into one
place then the offset and size of the microcode is recorded by this entry,
-for use by u_boot_with_ucode_ptr. If it is being collated, then this
+for use by u-boot-with-ucode_ptr. If it is being collated, then this
entry deletes the microcode from the device tree (to save space) and makes
-it available to u_boot_ucode.
+it available to u-boot-ucode.
@@ -901,6 +918,21 @@ Properties / Entry arguments:
+Entry: u-boot-expanded: U-Boot flat binary broken out into its component parts
+------------------------------------------------------------------------------
+
+This is a section containing the U-Boot binary and a devicetree. Using this
+entry type automatically creates this section, with the following entries
+in it:
+
+ u-boot-nodtb
+ u-boot-dtb
+
+Having the devicetree separate allows binman to update it in the final
+image, so that the entries positions are provided to the running U-Boot.
+
+
+
Entry: u-boot-img: U-Boot legacy image
--------------------------------------
@@ -919,13 +951,13 @@ Entry: u-boot-nodtb: U-Boot flat binary without device tree appended
--------------------------------------------------------------------
Properties / Entry arguments:
- - filename: Filename of u-boot.bin (default 'u-boot-nodtb.bin')
+ - filename: Filename to include (default 'u-boot-nodtb.bin')
This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. It does not include a device tree blob at
-the end of it so normally cannot work without it. You can add a u_boot_dtb
-entry after this one, or use a u_boot entry instead (which contains both
-U-Boot and the device tree).
+the end of it so normally cannot work without it. You can add a u-boot-dtb
+entry after this one, or use a u-boot entry instead, normally expands to a
+section containing u-boot and u-boot-dtb
@@ -951,6 +983,9 @@ in the binman README for more information.
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
binman uses that to look up symbols to write into the SPL binary.
+Note that this entry is automatically replaced with u-boot-spl-expanded
+unless --no-expanded is used.
+
Entry: u-boot-spl-bss-pad: U-Boot SPL binary padded with a BSS region
@@ -959,13 +994,16 @@ Entry: u-boot-spl-bss-pad: U-Boot SPL binary padded with a BSS region
Properties / Entry arguments:
None
-This is similar to u_boot_spl except that padding is added after the SPL
-binary to cover the BSS (Block Started by Symbol) region. This region holds
-the various used by SPL. It is set to 0 by SPL when it starts up. If you
-want to append data to the SPL image (such as a device tree file), you must
-pad out the BSS region to avoid the data overlapping with U-Boot variables.
-This entry is useful in that case. It automatically pads out the entry size
-to cover both the code, data and BSS.
+This holds the padding added after the SPL binary to cover the BSS (Block
+Started by Symbol) region. This region holds the various variables used by
+SPL. It is set to 0 by SPL when it starts up. If you want to append data to
+the SPL image (such as a device tree file), you must pad out the BSS region
+to avoid the data overlapping with U-Boot variables. This entry is useful in
+that case. It automatically pads out the entry size to cover both the code,
+data and BSS.
+
+The contents of this entry will a certain number of zero bytes, determined
+by __bss_size
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
binman uses that to look up the BSS address.
@@ -995,18 +1033,50 @@ be relocated to any address for execution.
+Entry: u-boot-spl-expanded: U-Boot SPL flat binary broken out into its component parts
+--------------------------------------------------------------------------------------
+
+Properties / Entry arguments:
+ - spl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+ select)
+
+This is a section containing the U-Boot binary, BSS padding if needed and a
+devicetree. Using this entry type automatically creates this section, with
+the following entries in it:
+
+ u-boot-spl-nodtb
+ u-boot-spl-bss-pad
+ u-boot-dtb
+
+Having the devicetree separate allows binman to update it in the final
+image, so that the entries positions are provided to the running U-Boot.
+
+This entry is selected based on the value of the 'spl-dtb' entryarg. If
+this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+
+
+
Entry: u-boot-spl-nodtb: SPL binary without device tree appended
----------------------------------------------------------------
Properties / Entry arguments:
- - filename: Filename of spl/u-boot-spl-nodtb.bin (default
- 'spl/u-boot-spl-nodtb.bin')
+ - filename: Filename to include (default 'spl/u-boot-spl-nodtb.bin')
This is the U-Boot SPL binary, It does not include a device tree blob at
the end of it so may not be able to work without it, assuming SPL needs
-a device tree to operation on your platform. You can add a u_boot_spl_dtb
-entry after this one, or use a u_boot_spl entry instead (which contains
-both SPL and the device tree).
+a device tree to operate on your platform. You can add a u-boot-spl-dtb
+entry after this one, or use a u-boot-spl entry instead' which normally
+expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
+u-boot-spl-dtb
+
+SPL can access binman symbols at runtime. See:
+
+ 'Access to binman entry offsets at run time (symbols)'
+
+in the binman README for more information.
+
+The ELF file 'spl/u-boot-spl' must also be available for this to work, since
+binman uses that to look up symbols to write into the SPL binary.
@@ -1042,6 +1112,31 @@ in the binman README for more information.
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
binman uses that to look up symbols to write into the TPL binary.
+Note that this entry is automatically replaced with u-boot-tpl-expanded
+unless --no-expanded is used.
+
+
+
+Entry: u-boot-tpl-bss-pad: U-Boot TPL binary padded with a BSS region
+---------------------------------------------------------------------
+
+Properties / Entry arguments:
+ None
+
+This holds the padding added after the TPL binary to cover the BSS (Block
+Started by Symbol) region. This region holds the various variables used by
+TPL. It is set to 0 by TPL when it starts up. If you want to append data to
+the TPL image (such as a device tree file), you must pad out the BSS region
+to avoid the data overlapping with U-Boot variables. This entry is useful in
+that case. It automatically pads out the entry size to cover both the code,
+data and BSS.
+
+The contents of this entry will a certain number of zero bytes, determined
+by __bss_size
+
+The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
+binman uses that to look up the BSS address.
+
Entry: u-boot-tpl-dtb: U-Boot TPL device tree
@@ -1077,6 +1172,53 @@ be relocated to any address for execution.
+Entry: u-boot-tpl-expanded: U-Boot TPL flat binary broken out into its component parts
+--------------------------------------------------------------------------------------
+
+Properties / Entry arguments:
+ - tpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+ select)
+
+This is a section containing the U-Boot binary, BSS padding if needed and a
+devicetree. Using this entry type automatically creates this section, with
+the following entries in it:
+
+ u-boot-tpl-nodtb
+ u-boot-tpl-bss-pad
+ u-boot-dtb
+
+Having the devicetree separate allows binman to update it in the final
+image, so that the entries positions are provided to the running U-Boot.
+
+This entry is selected based on the value of the 'tpl-dtb' entryarg. If
+this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+
+
+
+Entry: u-boot-tpl-nodtb: TPL binary without device tree appended
+----------------------------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename to include (default 'tpl/u-boot-tpl-nodtb.bin')
+
+This is the U-Boot TPL binary, It does not include a device tree blob at
+the end of it so may not be able to work without it, assuming TPL needs
+a device tree to operate on your platform. You can add a u-boot-tpl-dtb
+entry after this one, or use a u-boot-tpl entry instead, which normally
+expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
+u-boot-tpl-dtb
+
+TPL can access binman symbols at runtime. See:
+
+ 'Access to binman entry offsets at run time (symbols)'
+
+in the binman README for more information.
+
+The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
+binman uses that to look up symbols to write into the TPL binary.
+
+
+
Entry: u-boot-tpl-with-ucode-ptr: U-Boot TPL with embedded microcode pointer
----------------------------------------------------------------------------
@@ -1147,7 +1289,7 @@ Properties / Entry arguments:
See Entry_u_boot_ucode for full details of the three entries involved in
this process. This entry updates U-Boot with the offset and size of the
microcode, to allow early x86 boot code to find it without doing anything
-complicated. Otherwise it is the same as the u_boot entry.
+complicated. Otherwise it is the same as the u-boot entry.
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index d58a730..1cfa024 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -102,22 +102,30 @@ class Entry(object):
self.allow_missing = False
@staticmethod
- def Lookup(node_path, etype):
+ def Lookup(node_path, etype, expanded):
"""Look up the entry class for a node.
Args:
node_node: Path name of Node object containing information about
the entry to create (used for errors)
etype: Entry type to use
+ expanded: Use the expanded version of etype
Returns:
- The entry class object if found, else None
+ The entry class object if found, else None if not found and expanded
+ is True
+
+ Raise:
+ ValueError if expanded is False and the class is not found
"""
# Convert something like 'u-boot@0' to 'u_boot' since we are only
# interested in the type.
module_name = etype.replace('-', '_')
+
if '@' in module_name:
module_name = module_name.split('@')[0]
+ if expanded:
+ module_name += '_expanded'
module = modules.get(module_name)
# Also allow entry-type modules to be brought in from the etype directory.
@@ -127,6 +135,8 @@ class Entry(object):
try:
module = importlib.import_module('binman.etype.' + module_name)
except ImportError as e:
+ if expanded:
+ return None
raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
(etype, node_path, module_name, e))
modules[module_name] = module
@@ -135,21 +145,31 @@ class Entry(object):
return getattr(module, 'Entry_%s' % module_name)
@staticmethod
- def Create(section, node, etype=None):
+ def Create(section, node, etype=None, expanded=False):
"""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)
+ 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)
+ expanded: True to use expanded versions of entries, where available
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(node.path, etype)
+ obj = Entry.Lookup(node.path, etype, expanded)
+ if obj and expanded:
+ # Check whether to use the expanded entry
+ new_etype = etype + '-expanded'
+ if obj.UseExpanded(node, etype, new_etype):
+ etype = new_etype
+ else:
+ obj = None
+ if not obj:
+ obj = Entry.Lookup(node.path, etype, False)
# Call its constructor to get the object we want.
return obj(section, etype, node)
@@ -205,12 +225,23 @@ class Entry(object):
Dict:
key: Filename from this entry (without the path)
value: Tuple:
- Fdt object for this dtb, or None if not available
+ Entry object for this dtb
Filename of file containing this dtb
"""
return {}
def ExpandEntries(self):
+ """Expand out entries which produce other entries
+
+ Some entries generate subnodes automatically, from which sub-entries
+ are then created. This method allows those to be added to the binman
+ definition for the current image. An entry which implements this method
+ should call state.AddSubnode() to add a subnode and can add properties
+ with state.AddString(), etc.
+
+ An example is 'files', which produces a section containing a list of
+ files.
+ """
pass
def AddMissingProperties(self, have_image_pos):
@@ -637,7 +668,7 @@ features to produce new behaviours.
modules.remove('_testing')
missing = []
for name in modules:
- module = Entry.Lookup('WriteDocs', name)
+ module = Entry.Lookup('WriteDocs', name, False)
docs = getattr(module, '__doc__')
if test_missing == name:
docs = None
@@ -896,3 +927,25 @@ features to produce new behaviours.
self.uncomp_size = len(indata)
data = tools.Compress(indata, self.compress)
return data
+
+ @classmethod
+ def UseExpanded(cls, node, etype, new_etype):
+ """Check whether to use an expanded entry type
+
+ This is called by Entry.Create() when it finds an expanded version of
+ an entry type (e.g. 'u-boot-expanded'). If this method returns True then
+ it will be used (e.g. in place of 'u-boot'). If it returns False, it is
+ ignored.
+
+ Args:
+ node: Node object containing information about the entry to
+ create
+ etype: Original entry type being used
+ new_etype: New entry type proposed
+
+ Returns:
+ True to use this entry type, False to use the original one
+ """
+ tout.Info("Node '%s': etype '%s': %s selected" %
+ (node.path, etype, new_etype))
+ return True
diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py
index 80802f3..c3d5f3e 100644
--- a/tools/binman/entry_test.py
+++ b/tools/binman/entry_test.py
@@ -87,6 +87,18 @@ class TestEntry(unittest.TestCase):
base = entry.Entry.Create(None, self.GetNode(), 'blob-dtb')
self.assertIsNone(base.ReadChildData(base))
+ def testExpandedEntry(self):
+ """Test use of an expanded entry when available"""
+ base = entry.Entry.Create(None, self.GetNode())
+ self.assertEqual('u-boot', base.etype)
+
+ expanded = entry.Entry.Create(None, self.GetNode(), expanded=True)
+ self.assertEqual('u-boot-expanded', expanded.etype)
+
+ with self.assertRaises(ValueError) as e:
+ entry.Entry.Create(None, self.GetNode(), 'missing', expanded=True)
+ self.assertIn("Unknown entry type 'missing' in node '/binman/u-boot'",
+ str(e.exception))
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/etype/atf_bl31.py b/tools/binman/etype/atf_bl31.py
index 195adc7..163d714 100644
--- a/tools/binman/etype/atf_bl31.py
+++ b/tools/binman/etype/atf_bl31.py
@@ -8,7 +8,7 @@
from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
class Entry_atf_bl31(Entry_blob_named_by_arg):
- """Entry containing an ARM Trusted Firmware (ATF) BL31 blob
+ """ARM Trusted Firmware (ATF) BL31 blob
Properties / Entry arguments:
- atf-bl31-path: Filename of file to read into entry. This is typically
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index 81756c3..018f8c9 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -11,7 +11,7 @@ from patman import tools
from patman import tout
class Entry_blob(Entry):
- """Entry containing an arbitrary binary blob
+ """Arbitrary binary blob
Note: This should not be used by itself. It is normally used as a parent
class by other entry types.
@@ -24,7 +24,7 @@ class Entry_blob(Entry):
This entry reads data from a file and places it in the entry. The
default filename is often specified specified by the subclass. See for
- example the 'u_boot' entry which provides the filename 'u-boot.bin'.
+ example the 'u-boot' entry which provides the filename 'u-boot.bin'.
If compression is enabled, an extra 'uncomp-size' property is written to
the node (if enabled with -u) which provides the uncompressed size of the
diff --git a/tools/binman/etype/blob_dtb.py b/tools/binman/etype/blob_dtb.py
index 724647a..3ce7511 100644
--- a/tools/binman/etype/blob_dtb.py
+++ b/tools/binman/etype/blob_dtb.py
@@ -44,15 +44,6 @@ class Entry_blob_dtb(Entry_blob):
return None
def GetFdts(self):
- """Get the device trees used by this entry
-
- Returns:
- Dict:
- key: Filename from this entry (without the path)
- value: Tuple:
- Fdt object for this dtb, or None if not available
- Filename of file containing this dtb
- """
fname = self.GetDefaultFilename()
return {self.GetFdtEtype(): [self, fname]}
diff --git a/tools/binman/etype/blob_ext.py b/tools/binman/etype/blob_ext.py
index e372445..d6b0ca1 100644
--- a/tools/binman/etype/blob_ext.py
+++ b/tools/binman/etype/blob_ext.py
@@ -13,7 +13,7 @@ from patman import tools
from patman import tout
class Entry_blob_ext(Entry_blob):
- """Entry containing an externally built binary blob
+ """Externally built binary blob
Note: This should not be used by itself. It is normally used as a parent
class by other entry types.
diff --git a/tools/binman/etype/blob_phase.py b/tools/binman/etype/blob_phase.py
new file mode 100644
index 0000000..54ca54c
--- /dev/null
+++ b/tools/binman/etype/blob_phase.py
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type base class for U-Boot or SPL binary with devicetree
+#
+
+from binman.etype.section import Entry_section
+
+class Entry_blob_phase(Entry_section):
+ """Section that holds a phase binary
+
+ This is a base class that should not normally be used directly. It is used
+ when converting a 'u-boot' entry automatically into a 'u-boot-expanded'
+ entry; similarly for SPL.
+ """
+ def __init__(self, section, etype, node, root_fname, dtb_file, bss_pad):
+ """Set up a new blob for a phase
+
+ This holds an executable for a U-Boot phase, optional BSS padding and
+ a devicetree
+
+ Args:
+ section: entry_Section object for this entry's parent
+ etype: Type of object
+ node: Node defining this entry
+ root_fname: Root filename for the binary ('u-boot',
+ 'spl/u-boot-spl', etc.)
+ dtb_file: Name of devicetree file ('u-boot.dtb', u-boot-spl.dtb',
+ etc.)
+ bss_pad: True to add BSS padding before the devicetree
+ """
+ # Put this here to allow entry-docs and help to work without libfdt
+ global state
+ from binman import state
+
+ super().__init__(section, etype, node)
+ self.root_fname = root_fname
+ self.dtb_file = dtb_file
+ self.bss_pad = bss_pad
+
+ def ExpandEntries(self):
+ """Create the subnodes"""
+ names = [self.root_fname + '-nodtb', self.root_fname + '-dtb']
+ if self.bss_pad:
+ names.insert(1, self.root_fname + '-bss-pad')
+ for name in names:
+ subnode = state.AddSubnode(self._node, name)
+
+ # Read entries again, now that we have some
+ self._ReadEntries()
diff --git a/tools/binman/etype/cbfs.py b/tools/binman/etype/cbfs.py
index 6cdbaa0..1daddeb 100644
--- a/tools/binman/etype/cbfs.py
+++ b/tools/binman/etype/cbfs.py
@@ -13,7 +13,7 @@ from binman.entry import Entry
from dtoc import fdt_util
class Entry_cbfs(Entry):
- """Entry containing a Coreboot Filesystem (CBFS)
+ """Coreboot Filesystem (CBFS)
A CBFS provides a way to group files into a group. It has a simple directory
structure and allows the position of individual files to be set, since it is
@@ -22,7 +22,7 @@ class Entry_cbfs(Entry):
CBFS is used by coreboot as its way of orgnanising SPI-flash contents.
- The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.:
+ The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.::
cbfs {
size = <0x100000>;
@@ -38,7 +38,7 @@ class Entry_cbfs(Entry):
Note that the size is required since binman does not support calculating it.
The contents of each entry is just what binman would normally provide if it
were not a CBFS node. A blob type can be used to import arbitrary files as
- with the second subnode below:
+ with the second subnode below::
cbfs {
size = <0x100000>;
@@ -84,7 +84,7 @@ class Entry_cbfs(Entry):
This is an ELF file that has been loaded (i.e. mapped to memory), so
appears in the CBFS as a flat binary. The input file must be an ELF
image, for example this puts "u-boot" (the ELF image) into a 'stage'
- entry:
+ entry::
cbfs {
size = <0x100000>;
@@ -94,7 +94,7 @@ class Entry_cbfs(Entry):
};
};
- You can use your own ELF file with something like:
+ You can use your own ELF file with something like::
cbfs {
size = <0x100000>;
@@ -127,7 +127,7 @@ class Entry_cbfs(Entry):
particular offset in the CBFS and a few other things.
Of course binman can create images containing multiple CBFSs, simply by
- defining these in the binman config:
+ defining these in the binman config::
binman {
diff --git a/tools/binman/etype/fdtmap.py b/tools/binman/etype/fdtmap.py
index 6ca88a1..2339fee 100644
--- a/tools/binman/etype/fdtmap.py
+++ b/tools/binman/etype/fdtmap.py
@@ -53,24 +53,24 @@ class Entry_fdtmap(Entry):
Note that the -u option must be provided to ensure that binman updates the
FDT with the position of each entry.
- Example output for a simple image with U-Boot and an FDT map:
-
- / {
- image-name = "binman";
- size = <0x00000112>;
- image-pos = <0x00000000>;
- offset = <0x00000000>;
- u-boot {
- size = <0x00000004>;
+ Example output for a simple image with U-Boot and an FDT map::
+
+ / {
+ image-name = "binman";
+ size = <0x00000112>;
image-pos = <0x00000000>;
offset = <0x00000000>;
+ u-boot {
+ size = <0x00000004>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ };
+ fdtmap {
+ size = <0x0000010e>;
+ image-pos = <0x00000004>;
+ offset = <0x00000004>;
+ };
};
- fdtmap {
- size = <0x0000010e>;
- image-pos = <0x00000004>;
- offset = <0x00000004>;
- };
- };
If allow-repack is used then 'orig-offset' and 'orig-size' properties are
added as necessary. See the binman README.
diff --git a/tools/binman/etype/files.py b/tools/binman/etype/files.py
index 1feebd0..5db36ab 100644
--- a/tools/binman/etype/files.py
+++ b/tools/binman/etype/files.py
@@ -15,7 +15,7 @@ from patman import tools
class Entry_files(Entry_section):
- """Entry containing a set of files
+ """A set of files arranged in a section
Properties / Entry arguments:
- pattern: Filename pattern to match the files to include
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 1a7cbd7..6936f57 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -14,7 +14,7 @@ from dtoc.fdt import Fdt
from patman import tools
class Entry_fit(Entry):
- """Entry containing a FIT
+ """Flat Image Tree (FIT)
This calls mkimage to create a FIT (U-Boot Flat Image Tree) based on the
input provided.
@@ -22,7 +22,7 @@ class Entry_fit(Entry):
Nodes for the FIT should be written out in the binman configuration just as
they would be in a file passed to mkimage.
- For example, this creates an image containing a FIT with U-Boot SPL:
+ For example, this creates an image containing a FIT with U-Boot SPL::
binman {
fit {
@@ -52,7 +52,7 @@ class Entry_fit(Entry):
The fit,fdt-list property (see above) indicates that of-list should be used.
If the property is missing you will get an error.
- Then add a 'generator node', a node with a name starting with '@':
+ Then add a 'generator node', a node with a name starting with '@'::
images {
@fdt-SEQ {
@@ -67,7 +67,7 @@ class Entry_fit(Entry):
node acts like a template to generate the nodes. The generator node itself
does not appear in the output - it is replaced with what binman generates.
- You can create config nodes in a similar way:
+ You can create config nodes in a similar way::
configurations {
default = "@config-DEFAULT-SEQ";
@@ -84,8 +84,10 @@ class Entry_fit(Entry):
Available substitutions for '@' nodes are:
- SEQ Sequence number of the generated fdt (1, 2, ...)
- NAME Name of the dtb as provided (i.e. without adding '.dtb')
+ SEQ:
+ Sequence number of the generated fdt (1, 2, ...)
+ NAME
+ Name of the dtb as provided (i.e. without adding '.dtb')
Note that if no devicetree files are provided (with '-a of-list' as above)
then no nodes will be generated.
@@ -94,10 +96,11 @@ class Entry_fit(Entry):
if of configuration whose devicetree matches the 'default-dt' entry
argument, e.g. with '-a default-dt=sun50i-a64-pine64-lts'.
- Available substitutions for '@' property values are:
+ Available substitutions for '@' property values are
- DEFAULT-SEQ Sequence number of the default fdt,as provided by the
- 'default-dt' entry argument
+ DEFAULT-SEQ:
+ Sequence number of the default fdt,as provided by the 'default-dt' entry
+ argument
Properties (in the 'fit' node itself):
fit,external-offset: Indicates that the contents of the FIT are external
diff --git a/tools/binman/etype/intel_cmc.py b/tools/binman/etype/intel_cmc.py
index 644fa42..494d43c 100644
--- a/tools/binman/etype/intel_cmc.py
+++ b/tools/binman/etype/intel_cmc.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_cmc(Entry_blob_ext):
- """Entry containing an Intel Chipset Micro Code (CMC) file
+ """Intel Chipset Micro Code (CMC) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_fsp.py b/tools/binman/etype/intel_fsp.py
index 2ac012b..326cb7d 100644
--- a/tools/binman/etype/intel_fsp.py
+++ b/tools/binman/etype/intel_fsp.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_fsp(Entry_blob_ext):
- """Entry containing an Intel Firmware Support Package (FSP) file
+ """Intel Firmware Support Package (FSP) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_fsp_m.py b/tools/binman/etype/intel_fsp_m.py
index 434b0f1..9bcac790 100644
--- a/tools/binman/etype/intel_fsp_m.py
+++ b/tools/binman/etype/intel_fsp_m.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_fsp_m(Entry_blob_ext):
- """Entry containing Intel Firmware Support Package (FSP) memory init
+ """Intel Firmware Support Package (FSP) memory init
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_fsp_s.py b/tools/binman/etype/intel_fsp_s.py
index 564e122..1d5046d 100644
--- a/tools/binman/etype/intel_fsp_s.py
+++ b/tools/binman/etype/intel_fsp_s.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_fsp_s(Entry_blob_ext):
- """Entry containing Intel Firmware Support Package (FSP) silicon init
+ """Intel Firmware Support Package (FSP) silicon init
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_fsp_t.py b/tools/binman/etype/intel_fsp_t.py
index df0c5fb..80d95cc 100644
--- a/tools/binman/etype/intel_fsp_t.py
+++ b/tools/binman/etype/intel_fsp_t.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_fsp_t(Entry_blob_ext):
- """Entry containing Intel Firmware Support Package (FSP) temp ram init
+ """Intel Firmware Support Package (FSP) temp ram init
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_ifwi.py b/tools/binman/etype/intel_ifwi.py
index 1a0e481..903d39b 100644
--- a/tools/binman/etype/intel_ifwi.py
+++ b/tools/binman/etype/intel_ifwi.py
@@ -13,7 +13,7 @@ from dtoc import fdt_util
from patman import tools
class Entry_intel_ifwi(Entry_blob_ext):
- """Entry containing an Intel Integrated Firmware Image (IFWI) file
+ """Intel Integrated Firmware Image (IFWI) file
Properties / Entry arguments:
- filename: Filename of file to read into entry. This is either the
@@ -37,10 +37,10 @@ class Entry_intel_ifwi(Entry_blob_ext):
sub-partition (and optional entry name).
Properties for subnodes:
- ifwi-subpart - sub-parition to put this entry into, e.g. "IBBP"
- ifwi-entry - entry name t use, e.g. "IBBL"
- ifwi-replace - if present, indicates that the item should be replaced
- in the IFWI. Otherwise it is added.
+ - ifwi-subpart: sub-parition to put this entry into, e.g. "IBBP"
+ - ifwi-entry: entry name t use, e.g. "IBBL"
+ - ifwi-replace: if present, indicates that the item should be replaced
+ in the IFWI. Otherwise it is added.
See README.x86 for information about x86 binary blobs.
"""
diff --git a/tools/binman/etype/intel_me.py b/tools/binman/etype/intel_me.py
index a6fe542..b93ebab 100644
--- a/tools/binman/etype/intel_me.py
+++ b/tools/binman/etype/intel_me.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_me(Entry_blob_ext):
- """Entry containing an Intel Management Engine (ME) file
+ """Intel Management Engine (ME) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_mrc.py b/tools/binman/etype/intel_mrc.py
index ccbb046..bb8b26f 100644
--- a/tools/binman/etype/intel_mrc.py
+++ b/tools/binman/etype/intel_mrc.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_mrc(Entry_blob_ext):
- """Entry containing an Intel Memory Reference Code (MRC) file
+ """Intel Memory Reference Code (MRC) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_refcode.py b/tools/binman/etype/intel_refcode.py
index 5ead08b..9112730 100644
--- a/tools/binman/etype/intel_refcode.py
+++ b/tools/binman/etype/intel_refcode.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_refcode(Entry_blob_ext):
- """Entry containing an Intel Reference Code file
+ """Intel Reference Code file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_vbt.py b/tools/binman/etype/intel_vbt.py
index 2a98c12..8afd576 100644
--- a/tools/binman/etype/intel_vbt.py
+++ b/tools/binman/etype/intel_vbt.py
@@ -7,7 +7,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_vbt(Entry_blob_ext):
- """Entry containing an Intel Video BIOS Table (VBT) file
+ """Intel Video BIOS Table (VBT) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/intel_vga.py b/tools/binman/etype/intel_vga.py
index a103f1c..51e6465 100644
--- a/tools/binman/etype/intel_vga.py
+++ b/tools/binman/etype/intel_vga.py
@@ -8,7 +8,7 @@
from binman.etype.blob_ext import Entry_blob_ext
class Entry_intel_vga(Entry_blob_ext):
- """Entry containing an Intel Video Graphics Adaptor (VGA) file
+ """Intel Video Graphics Adaptor (VGA) file
Properties / Entry arguments:
- filename: Filename of file to read into entry
diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py
index 8fddc88..e9f8272 100644
--- a/tools/binman/etype/mkimage.py
+++ b/tools/binman/etype/mkimage.py
@@ -12,14 +12,14 @@ from dtoc import fdt_util
from patman import tools
class Entry_mkimage(Entry):
- """Entry containing a binary produced by mkimage
+ """Binary produced by mkimage
Properties / Entry arguments:
- datafile: Filename for -d argument
- args: Other arguments to pass
The data passed to mkimage is collected from subnodes of the mkimage node,
- e.g.:
+ e.g.::
mkimage {
args = "-n test -T imximage";
diff --git a/tools/binman/etype/scp.py b/tools/binman/etype/scp.py
index 93f8787..a9bee3c 100644
--- a/tools/binman/etype/scp.py
+++ b/tools/binman/etype/scp.py
@@ -7,7 +7,7 @@
from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
class Entry_scp(Entry_blob_named_by_arg):
- """Entry containing a System Control Processor (SCP) firmware blob
+ """System Control Processor (SCP) firmware blob
Properties / Entry arguments:
- scp-path: Filename of file to read into the entry, typically scp.bin
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 1ceadef..cce1500 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -22,11 +22,13 @@ from patman.tools import ToHexSize
class Entry_section(Entry):
"""Entry that contains other entries
- Properties / Entry arguments: (see binman README for more information)
+ Properties / Entry arguments: (see binman README for more information):
pad-byte: Pad byte to use when padding
sort-by-offset: True if entries should be sorted by offset, False if
- they must be in-order in the device tree description
+ they must be in-order in the device tree description
+
end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
+
skip-at-start: Number of bytes before the first entry starts. These
effectively adjust the starting offset of entries. For example,
if this is 16, then the first entry would start at 16. An entry
@@ -84,7 +86,8 @@ class Entry_section(Entry):
for node in self._node.subnodes:
if node.name.startswith('hash') or node.name.startswith('signature'):
continue
- entry = Entry.Create(self, node)
+ entry = Entry.Create(self, node,
+ expanded=self.GetImage().use_expanded)
entry.ReadNode()
entry.SetPrefix(self._name_prefix)
self._entries[node.name] = entry
@@ -126,12 +129,6 @@ class Entry_section(Entry):
return True
def ExpandEntries(self):
- """Expand out any entries which have calculated sub-entries
-
- Some entries are expanded out at runtime, e.g. 'files', which produces
- a section containing a list of files. Process these entries so that
- this information is added to the device tree.
- """
super().ExpandEntries()
for entry in self._entries.values():
entry.ExpandEntries()
diff --git a/tools/binman/etype/text.py b/tools/binman/etype/text.py
index a69c2a4..45dfcc4 100644
--- a/tools/binman/etype/text.py
+++ b/tools/binman/etype/text.py
@@ -25,7 +25,7 @@ class Entry_text(Entry):
<text>: The text to place in the entry (overrides the above mechanism).
This is useful when the text is constant.
- Example node:
+ Example node::
text {
size = <50>;
@@ -38,7 +38,7 @@ class Entry_text(Entry):
and binman will insert that string into the entry.
- It is also possible to put the string directly in the node:
+ It is also possible to put the string directly in the node::
text {
size = <8>;
@@ -46,7 +46,7 @@ class Entry_text(Entry):
message = "a message directly in the node"
};
- or just:
+ or just::
text {
size = <8>;
diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py
index 4767197..d2eaba6 100644
--- a/tools/binman/etype/u_boot.py
+++ b/tools/binman/etype/u_boot.py
@@ -2,7 +2,7 @@
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
-# Entry-type module for U-Boot binary
+# Entry-type module for the expanded U-Boot binary
#
from binman.entry import Entry
@@ -16,14 +16,16 @@ class Entry_u_boot(Entry_blob):
This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. The binary typically includes a device tree
- blob at the end of it. Use u_boot_nodtb if you want to package the device
- tree separately.
+ blob at the end of it.
U-Boot can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (fdt)'
in the binman README for more information.
+
+ Note that this entry is automatically replaced with u-boot-expanded unless
+ --no-expanded is used.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
diff --git a/tools/binman/etype/u_boot_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py
index 66a9db5..554b3b2 100644
--- a/tools/binman/etype/u_boot_dtb_with_ucode.py
+++ b/tools/binman/etype/u_boot_dtb_with_ucode.py
@@ -19,9 +19,9 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
this process. This entry provides the U-Boot device-tree file, which
contains the microcode. If the microcode is not being collated into one
place then the offset and size of the microcode is recorded by this entry,
- for use by u_boot_with_ucode_ptr. If it is being collated, then this
+ for use by u-boot-with-ucode_ptr. If it is being collated, then this
entry deletes the microcode from the device tree (to save space) and makes
- it available to u_boot_ucode.
+ it available to u-boot-ucode.
"""
def __init__(self, section, etype, node):
# Put this here to allow entry-docs and help to work without libfdt
diff --git a/tools/binman/etype/u_boot_expanded.py b/tools/binman/etype/u_boot_expanded.py
new file mode 100644
index 0000000..8797824
--- /dev/null
+++ b/tools/binman/etype/u_boot_expanded.py
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for U-Boot binary
+#
+
+from binman.etype.blob_phase import Entry_blob_phase
+
+class Entry_u_boot_expanded(Entry_blob_phase):
+ """U-Boot flat binary broken out into its component parts
+
+ This is a section containing the U-Boot binary and a devicetree. Using this
+ entry type automatically creates this section, with the following entries
+ in it:
+
+ u-boot-nodtb
+ u-boot-dtb
+
+ Having the devicetree separate allows binman to update it in the final
+ image, so that the entries positions are provided to the running U-Boot.
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node, 'u-boot', 'u-boot-dtb', False)
diff --git a/tools/binman/etype/u_boot_nodtb.py b/tools/binman/etype/u_boot_nodtb.py
index e84df49..347ba7d 100644
--- a/tools/binman/etype/u_boot_nodtb.py
+++ b/tools/binman/etype/u_boot_nodtb.py
@@ -12,13 +12,13 @@ class Entry_u_boot_nodtb(Entry_blob):
"""U-Boot flat binary without device tree appended
Properties / Entry arguments:
- - filename: Filename of u-boot.bin (default 'u-boot-nodtb.bin')
+ - filename: Filename to include (default 'u-boot-nodtb.bin')
This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. It does not include a device tree blob at
- the end of it so normally cannot work without it. You can add a u_boot_dtb
- entry after this one, or use a u_boot entry instead (which contains both
- U-Boot and the device tree).
+ the end of it so normally cannot work without it. You can add a u-boot-dtb
+ entry after this one, or use a u-boot entry instead, normally expands to a
+ section containing u-boot and u-boot-dtb
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py
index d66e461..1c39f98 100644
--- a/tools/binman/etype/u_boot_spl.py
+++ b/tools/binman/etype/u_boot_spl.py
@@ -30,6 +30,9 @@ class Entry_u_boot_spl(Entry_blob):
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
binman uses that to look up symbols to write into the SPL binary.
+
+ Note that this entry is automatically replaced with u-boot-spl-expanded
+ unless --no-expanded is used.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py
index df15cd2..18c5596 100644
--- a/tools/binman/etype/u_boot_spl_bss_pad.py
+++ b/tools/binman/etype/u_boot_spl_bss_pad.py
@@ -18,13 +18,16 @@ class Entry_u_boot_spl_bss_pad(Entry_blob):
Properties / Entry arguments:
None
- This is similar to u_boot_spl except that padding is added after the SPL
- binary to cover the BSS (Block Started by Symbol) region. This region holds
- the various used by SPL. It is set to 0 by SPL when it starts up. If you
- want to append data to the SPL image (such as a device tree file), you must
- pad out the BSS region to avoid the data overlapping with U-Boot variables.
- This entry is useful in that case. It automatically pads out the entry size
- to cover both the code, data and BSS.
+ This holds the padding added after the SPL binary to cover the BSS (Block
+ Started by Symbol) region. This region holds the various variables used by
+ SPL. It is set to 0 by SPL when it starts up. If you want to append data to
+ the SPL image (such as a device tree file), you must pad out the BSS region
+ to avoid the data overlapping with U-Boot variables. This entry is useful in
+ that case. It automatically pads out the entry size to cover both the code,
+ data and BSS.
+
+ The contents of this entry will a certain number of zero bytes, determined
+ by __bss_size
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
binman uses that to look up the BSS address.
diff --git a/tools/binman/etype/u_boot_spl_expanded.py b/tools/binman/etype/u_boot_spl_expanded.py
new file mode 100644
index 0000000..8e138e6
--- /dev/null
+++ b/tools/binman/etype/u_boot_spl_expanded.py
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for expanded U-Boot SPL binary
+#
+
+from patman import tout
+
+from binman import state
+from binman.etype.blob_phase import Entry_blob_phase
+
+class Entry_u_boot_spl_expanded(Entry_blob_phase):
+ """U-Boot SPL flat binary broken out into its component parts
+
+ Properties / Entry arguments:
+ - spl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+ select)
+
+ This is a section containing the U-Boot binary, BSS padding if needed and a
+ devicetree. Using this entry type automatically creates this section, with
+ the following entries in it:
+
+ u-boot-spl-nodtb
+ u-boot-spl-bss-pad
+ u-boot-dtb
+
+ Having the devicetree separate allows binman to update it in the final
+ image, so that the entries positions are provided to the running U-Boot.
+
+ This entry is selected based on the value of the 'spl-dtb' entryarg. If
+ this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+ """
+ def __init__(self, section, etype, node):
+ bss_pad = state.GetEntryArgBool('spl-bss-pad')
+ super().__init__(section, etype, node, 'u-boot-spl', 'u-boot-spl-dtb',
+ bss_pad)
+
+ @classmethod
+ def UseExpanded(cls, node, etype, new_etype):
+ val = state.GetEntryArgBool('spl-dtb')
+ tout.DoOutput(tout.INFO if val else tout.DETAIL,
+ "Node '%s': etype '%s': %s %sselected" %
+ (node.path, etype, new_etype, '' if val else 'not '))
+ return val
diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py
index c154cfd..316b381 100644
--- a/tools/binman/etype/u_boot_spl_nodtb.py
+++ b/tools/binman/etype/u_boot_spl_nodtb.py
@@ -5,6 +5,7 @@
# Entry-type module for 'u-boot-spl-nodtb.bin'
#
+from binman import elf
from binman.entry import Entry
from binman.etype.blob import Entry_blob
@@ -12,17 +13,30 @@ class Entry_u_boot_spl_nodtb(Entry_blob):
"""SPL binary without device tree appended
Properties / Entry arguments:
- - filename: Filename of spl/u-boot-spl-nodtb.bin (default
- 'spl/u-boot-spl-nodtb.bin')
+ - filename: Filename to include (default 'spl/u-boot-spl-nodtb.bin')
This is the U-Boot SPL binary, It does not include a device tree blob at
the end of it so may not be able to work without it, assuming SPL needs
- a device tree to operation on your platform. You can add a u_boot_spl_dtb
- entry after this one, or use a u_boot_spl entry instead (which contains
- both SPL and the device tree).
+ a device tree to operate on your platform. You can add a u-boot-spl-dtb
+ entry after this one, or use a u-boot-spl entry instead' which normally
+ expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
+ u-boot-spl-dtb
+
+ SPL can access binman symbols at runtime. See:
+
+ 'Access to binman entry offsets at run time (symbols)'
+
+ in the binman README for more information.
+
+ The ELF file 'spl/u-boot-spl' must also be available for this to work, since
+ binman uses that to look up symbols to write into the SPL binary.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
+ self.elf_fname = 'spl/u-boot-spl'
def GetDefaultFilename(self):
return 'spl/u-boot-spl-nodtb.bin'
+
+ def WriteSymbols(self, section):
+ elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage())
diff --git a/tools/binman/etype/u_boot_tpl.py b/tools/binman/etype/u_boot_tpl.py
index 02287ab..95d9bd6 100644
--- a/tools/binman/etype/u_boot_tpl.py
+++ b/tools/binman/etype/u_boot_tpl.py
@@ -30,6 +30,9 @@ class Entry_u_boot_tpl(Entry_blob):
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
binman uses that to look up symbols to write into the TPL binary.
+
+ Note that this entry is automatically replaced with u-boot-tpl-expanded
+ unless --no-expanded is used.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
diff --git a/tools/binman/etype/u_boot_tpl_bss_pad.py b/tools/binman/etype/u_boot_tpl_bss_pad.py
new file mode 100644
index 0000000..521b24a
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_bss_pad.py
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for BSS padding for tpl/u-boot-tpl.bin. This padding
+# can be added after the TPL binary to ensure that anything concatenated
+# to it will appear to TPL to be at the end of BSS rather than the start.
+#
+
+from binman import elf
+from binman.entry import Entry
+from binman.etype.blob import Entry_blob
+from patman import tools
+
+class Entry_u_boot_tpl_bss_pad(Entry_blob):
+ """U-Boot TPL binary padded with a BSS region
+
+ Properties / Entry arguments:
+ None
+
+ This holds the padding added after the TPL binary to cover the BSS (Block
+ Started by Symbol) region. This region holds the various variables used by
+ TPL. It is set to 0 by TPL when it starts up. If you want to append data to
+ the TPL image (such as a device tree file), you must pad out the BSS region
+ to avoid the data overlapping with U-Boot variables. This entry is useful in
+ that case. It automatically pads out the entry size to cover both the code,
+ data and BSS.
+
+ The contents of this entry will a certain number of zero bytes, determined
+ by __bss_size
+
+ The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
+ binman uses that to look up the BSS address.
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node)
+
+ def ObtainContents(self):
+ fname = tools.GetInputFilename('tpl/u-boot-tpl')
+ bss_size = elf.GetSymbolAddress(fname, '__bss_size')
+ if not bss_size:
+ self.Raise('Expected __bss_size symbol in tpl/u-boot-tpl')
+ self.SetContents(tools.GetBytes(0, bss_size))
+ return True
diff --git a/tools/binman/etype/u_boot_tpl_expanded.py b/tools/binman/etype/u_boot_tpl_expanded.py
new file mode 100644
index 0000000..15cdac4
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_expanded.py
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for expanded U-Boot TPL binary
+#
+
+from patman import tout
+
+from binman import state
+from binman.etype.blob_phase import Entry_blob_phase
+
+class Entry_u_boot_tpl_expanded(Entry_blob_phase):
+ """U-Boot TPL flat binary broken out into its component parts
+
+ Properties / Entry arguments:
+ - tpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+ select)
+
+ This is a section containing the U-Boot binary, BSS padding if needed and a
+ devicetree. Using this entry type automatically creates this section, with
+ the following entries in it:
+
+ u-boot-tpl-nodtb
+ u-boot-tpl-bss-pad
+ u-boot-dtb
+
+ Having the devicetree separate allows binman to update it in the final
+ image, so that the entries positions are provided to the running U-Boot.
+
+ This entry is selected based on the value of the 'tpl-dtb' entryarg. If
+ this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+ """
+ def __init__(self, section, etype, node):
+ bss_pad = state.GetEntryArgBool('tpl-bss-pad')
+ super().__init__(section, etype, node, 'u-boot-tpl', 'u-boot-tpl-dtb',
+ bss_pad)
+
+ @classmethod
+ def UseExpanded(cls, node, etype, new_etype):
+ val = state.GetEntryArgBool('tpl-dtb')
+ tout.DoOutput(tout.INFO if val else tout.DETAIL,
+ "Node '%s': etype '%s': %s %sselected" %
+ (node.path, etype, new_etype, '' if val else 'not '))
+ return val
diff --git a/tools/binman/etype/u_boot_tpl_nodtb.py b/tools/binman/etype/u_boot_tpl_nodtb.py
new file mode 100644
index 0000000..98f3853
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_nodtb.py
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2021 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for 'u-boot-tpl-nodtb.bin'
+#
+
+from binman import elf
+from binman.entry import Entry
+from binman.etype.blob import Entry_blob
+
+class Entry_u_boot_tpl_nodtb(Entry_blob):
+ """TPL binary without device tree appended
+
+ Properties / Entry arguments:
+ - filename: Filename to include (default 'tpl/u-boot-tpl-nodtb.bin')
+
+ This is the U-Boot TPL binary, It does not include a device tree blob at
+ the end of it so may not be able to work without it, assuming TPL needs
+ a device tree to operate on your platform. You can add a u-boot-tpl-dtb
+ entry after this one, or use a u-boot-tpl entry instead, which normally
+ expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
+ u-boot-tpl-dtb
+
+ TPL can access binman symbols at runtime. See:
+
+ 'Access to binman entry offsets at run time (symbols)'
+
+ in the binman README for more information.
+
+ The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
+ binman uses that to look up symbols to write into the TPL binary.
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node)
+ self.elf_fname = 'tpl/u-boot-tpl'
+
+ def GetDefaultFilename(self):
+ return 'tpl/u-boot-tpl-nodtb.bin'
+
+ def WriteSymbols(self, section):
+ elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage())
diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py
index 92d2fc6..20be22a 100644
--- a/tools/binman/etype/u_boot_with_ucode_ptr.py
+++ b/tools/binman/etype/u_boot_with_ucode_ptr.py
@@ -26,7 +26,7 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
See Entry_u_boot_ucode for full details of the three entries involved in
this process. This entry updates U-Boot with the offset and size of the
microcode, to allow early x86 boot code to find it without doing anything
- complicated. Otherwise it is the same as the u_boot entry.
+ complicated. Otherwise it is the same as the u-boot entry.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 814e91d..81c213a 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -305,7 +305,8 @@ class TestFunctional(unittest.TestCase):
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
entry_args=None, images=None, use_real_dtb=False,
- verbosity=None, allow_missing=False, extra_indirs=None):
+ use_expanded=False, verbosity=None, allow_missing=False,
+ extra_indirs=None):
"""Run binman with a given test file
Args:
@@ -322,6 +323,8 @@ class TestFunctional(unittest.TestCase):
the u-boot-dtb entry. Normally this is not needed and the
test contents (the U_BOOT_DTB_DATA string) can be used.
But in some test we need the real contents.
+ use_expanded: True to use expanded entries where available, e.g.
+ 'u-boot-expanded' instead of 'u-boot'
verbosity: Verbosity level to use (0-3, None=don't set it)
allow_missing: Set the '--allow-missing' flag so that missing
external binaries just produce a warning instead of an error
@@ -344,6 +347,8 @@ class TestFunctional(unittest.TestCase):
args.append('-u')
if not use_real_dtb:
args.append('--fake-dtb')
+ if not use_expanded:
+ args.append('--no-expanded')
if entry_args:
for arg, value in entry_args.items():
args.append('-a%s=%s' % (arg, value))
@@ -403,9 +408,9 @@ class TestFunctional(unittest.TestCase):
dtb.Pack()
return dtb.GetContents()
- def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
- update_dtb=False, entry_args=None, reset_dtbs=True,
- extra_indirs=None):
+ def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
+ map=False, update_dtb=False, entry_args=None,
+ reset_dtbs=True, extra_indirs=None):
"""Run binman and return the resulting image
This runs binman with a given test file and then reads the resulting
@@ -420,6 +425,8 @@ class TestFunctional(unittest.TestCase):
the u-boot-dtb entry. Normally this is not needed and the
test contents (the U_BOOT_DTB_DATA string) can be used.
But in some test we need the real contents.
+ use_expanded: True to use expanded entries where available, e.g.
+ 'u-boot-expanded' instead of 'u-boot'
map: True to output map files for the images
update_dtb: Update the offset and size of each entry in the device
tree before packing it into the image
@@ -454,7 +461,7 @@ class TestFunctional(unittest.TestCase):
try:
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
entry_args=entry_args, use_real_dtb=use_real_dtb,
- extra_indirs=extra_indirs)
+ use_expanded=use_expanded, extra_indirs=extra_indirs)
self.assertEqual(0, retcode)
out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
@@ -624,7 +631,7 @@ class TestFunctional(unittest.TestCase):
def testFullHelp(self):
"""Test that the full help is displayed with -H"""
result = self._RunBinman('-H')
- help_file = os.path.join(self._binman_dir, 'README')
+ help_file = os.path.join(self._binman_dir, 'README.rst')
# Remove possible extraneous strings
extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
gothelp = result.stdout.replace(extra, '')
@@ -637,7 +644,7 @@ class TestFunctional(unittest.TestCase):
try:
command.test_result = command.CommandResult()
result = self._DoBinman('-H')
- help_file = os.path.join(self._binman_dir, 'README')
+ help_file = os.path.join(self._binman_dir, 'README.rst')
finally:
command.test_result = None
@@ -652,7 +659,7 @@ class TestFunctional(unittest.TestCase):
"""Test that we can run it with a specific board"""
self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
- result = self._DoBinman('build', '-b', 'sandbox')
+ result = self._DoBinman('build', '-n', '-b', 'sandbox')
self.assertEqual(0, result)
def testNeedBoard(self):
@@ -1337,21 +1344,43 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
- def testSymbols(self):
- """Test binman can assign symbols embedded in U-Boot"""
+ def checkSymbols(self, dts, base_data, u_boot_offset):
+ """Check the image contains the expected symbol values
+
+ Args:
+ dts: Device tree file to use for test
+ base_data: Data before and after 'u-boot' section
+ u_boot_offset: Offset of 'u-boot' section in image
+ """
elf_fname = self.ElfTestFile('u_boot_binman_syms')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
- self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
+ self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
+ addr)
self._SetupSplElf('u_boot_binman_syms')
- data = self._DoReadFile('053_symbols.dts')
- sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
- expected = (sym_values + U_BOOT_SPL_DATA[20:] +
+ data = self._DoReadFile(dts)
+ # The image should contain the symbols from u_boot_binman_syms.c
+ # Note that image_pos is adjusted by the base address of the image,
+ # which is 0x10 in our test image
+ sym_values = struct.pack('<LQLL', 0x00,
+ u_boot_offset + len(U_BOOT_DATA),
+ 0x10 + u_boot_offset, 0x04)
+ expected = (sym_values + base_data[20:] +
tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
- U_BOOT_SPL_DATA[20:])
+ base_data[20:])
self.assertEqual(expected, data)
+ def testSymbols(self):
+ """Test binman can assign symbols embedded in U-Boot"""
+ self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
+
+ def testSymbolsNoDtb(self):
+ """Test binman can assign symbols embedded in U-Boot SPL"""
+ self.checkSymbols('192_symbols_nodtb.dts',
+ U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
+ 0x38)
+
def testPackUnitAddress(self):
"""Test that we support multiple binaries with the same name"""
data = self._DoReadFile('054_unit_address.dts')
@@ -4186,18 +4215,7 @@ class TestFunctional(unittest.TestCase):
def testSymbolsSubsection(self):
"""Test binman can assign symbols from a subsection"""
- elf_fname = self.ElfTestFile('u_boot_binman_syms')
- syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
- addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
- self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
-
- self._SetupSplElf('u_boot_binman_syms')
- data = self._DoReadFile('187_symbols_sub.dts')
- sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
- expected = (sym_values + U_BOOT_SPL_DATA[20:] +
- tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
- U_BOOT_SPL_DATA[20:])
- self.assertEqual(expected, data)
+ self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
def testReadImageEntryArg(self):
"""Test reading an image that would need an entry arg to generate"""
@@ -4245,6 +4263,202 @@ class TestFunctional(unittest.TestCase):
self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
+ def testTplNoDtb(self):
+ """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
+ data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
+ self.assertEqual(U_BOOT_TPL_NODTB_DATA,
+ data[:len(U_BOOT_TPL_NODTB_DATA)])
+
+ def testTplBssPad(self):
+ """Test that we can pad TPL's BSS with zeros"""
+ # ELF file with a '__bss_size' symbol
+ self._SetupTplElf()
+ data = self._DoReadFile('193_tpl_bss_pad.dts')
+ self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
+ data)
+
+ def testTplBssPadMissing(self):
+ """Test that a missing symbol is detected"""
+ self._SetupTplElf('u_boot_ucode_ptr')
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('193_tpl_bss_pad.dts')
+ self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
+ str(e.exception))
+
+ def checkDtbSizes(self, data, pad_len, start):
+ """Check the size arguments in a dtb embedded in an image
+
+ Args:
+ data: The image data
+ pad_len: Length of the pad section in the image, in bytes
+ start: Start offset of the devicetree to examine, within the image
+
+ Returns:
+ Size of the devicetree in bytes
+ """
+ dtb_data = data[start:]
+ dtb = fdt.Fdt.FromData(dtb_data)
+ fdt_size = dtb.GetFdtObj().totalsize()
+ dtb.Scan()
+ props = self._GetPropTree(dtb, 'size')
+ self.assertEqual({
+ 'size': len(data),
+ 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
+ 'u-boot-spl/u-boot-spl-dtb:size': 801,
+ 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
+ 'u-boot-spl:size': 860,
+ 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
+ 'u-boot/u-boot-dtb:size': 781,
+ 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
+ 'u-boot:size': 827,
+ }, props)
+ return fdt_size
+
+ def testExpanded(self):
+ """Test that an expanded entry type is selected when needed"""
+ self._SetupSplElf()
+ self._SetupTplElf()
+
+ # SPL has a devicetree, TPL does not
+ entry_args = {
+ 'spl-dtb': '1',
+ 'spl-bss-pad': 'y',
+ 'tpl-dtb': '',
+ }
+ self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
+ entry_args=entry_args)
+ image = control.images['image']
+ entries = image.GetEntries()
+ self.assertEqual(3, len(entries))
+
+ # First, u-boot, which should be expanded into u-boot-nodtb and dtb
+ self.assertIn('u-boot', entries)
+ entry = entries['u-boot']
+ self.assertEqual('u-boot-expanded', entry.etype)
+ subent = entry.GetEntries()
+ self.assertEqual(2, len(subent))
+ self.assertIn('u-boot-nodtb', subent)
+ self.assertIn('u-boot-dtb', subent)
+
+ # Second, u-boot-spl, which should be expanded into three parts
+ self.assertIn('u-boot-spl', entries)
+ entry = entries['u-boot-spl']
+ self.assertEqual('u-boot-spl-expanded', entry.etype)
+ subent = entry.GetEntries()
+ self.assertEqual(3, len(subent))
+ self.assertIn('u-boot-spl-nodtb', subent)
+ self.assertIn('u-boot-spl-bss-pad', subent)
+ self.assertIn('u-boot-spl-dtb', subent)
+
+ # Third, u-boot-tpl, which should be not be expanded, since TPL has no
+ # devicetree
+ self.assertIn('u-boot-tpl', entries)
+ entry = entries['u-boot-tpl']
+ self.assertEqual('u-boot-tpl', entry.etype)
+ self.assertEqual(None, entry.GetEntries())
+
+ def testExpandedTpl(self):
+ """Test that an expanded entry type is selected for TPL when needed"""
+ self._SetupTplElf()
+
+ entry_args = {
+ 'tpl-bss-pad': 'y',
+ 'tpl-dtb': 'y',
+ }
+ self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
+ entry_args=entry_args)
+ image = control.images['image']
+ entries = image.GetEntries()
+ self.assertEqual(1, len(entries))
+
+ # We only have u-boot-tpl, which be expanded
+ self.assertIn('u-boot-tpl', entries)
+ entry = entries['u-boot-tpl']
+ self.assertEqual('u-boot-tpl-expanded', entry.etype)
+ subent = entry.GetEntries()
+ self.assertEqual(3, len(subent))
+ self.assertIn('u-boot-tpl-nodtb', subent)
+ self.assertIn('u-boot-tpl-bss-pad', subent)
+ self.assertIn('u-boot-tpl-dtb', subent)
+
+ def testExpandedNoPad(self):
+ """Test an expanded entry without BSS pad enabled"""
+ self._SetupSplElf()
+ self._SetupTplElf()
+
+ # SPL has a devicetree, TPL does not
+ entry_args = {
+ 'spl-dtb': 'something',
+ 'spl-bss-pad': 'n',
+ 'tpl-dtb': '',
+ }
+ self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
+ entry_args=entry_args)
+ image = control.images['image']
+ entries = image.GetEntries()
+
+ # Just check u-boot-spl, which should be expanded into two parts
+ self.assertIn('u-boot-spl', entries)
+ entry = entries['u-boot-spl']
+ self.assertEqual('u-boot-spl-expanded', entry.etype)
+ subent = entry.GetEntries()
+ self.assertEqual(2, len(subent))
+ self.assertIn('u-boot-spl-nodtb', subent)
+ self.assertIn('u-boot-spl-dtb', subent)
+
+ def testExpandedTplNoPad(self):
+ """Test that an expanded entry type with padding disabled in TPL"""
+ self._SetupTplElf()
+
+ entry_args = {
+ 'tpl-bss-pad': '',
+ 'tpl-dtb': 'y',
+ }
+ self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
+ entry_args=entry_args)
+ image = control.images['image']
+ entries = image.GetEntries()
+ self.assertEqual(1, len(entries))
+
+ # We only have u-boot-tpl, which be expanded
+ self.assertIn('u-boot-tpl', entries)
+ entry = entries['u-boot-tpl']
+ self.assertEqual('u-boot-tpl-expanded', entry.etype)
+ subent = entry.GetEntries()
+ self.assertEqual(2, len(subent))
+ self.assertIn('u-boot-tpl-nodtb', subent)
+ self.assertIn('u-boot-tpl-dtb', subent)
+
+ def testFdtInclude(self):
+ """Test that an Fdt is update within all binaries"""
+ self._SetupSplElf()
+ self._SetupTplElf()
+
+ # SPL has a devicetree, TPL does not
+ self.maxDiff = None
+ entry_args = {
+ 'spl-dtb': '1',
+ 'spl-bss-pad': 'y',
+ 'tpl-dtb': '',
+ }
+ # Build the image. It includes two separate devicetree binaries, each
+ # with their own contents, but all contain the binman definition.
+ data = self._DoReadFileDtb(
+ '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
+ update_dtb=True, entry_args=entry_args)[0]
+ pad_len = 10
+
+ # Check the U-Boot dtb
+ start = len(U_BOOT_NODTB_DATA)
+ fdt_size = self.checkDtbSizes(data, pad_len, start)
+
+ # Now check SPL
+ start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
+ fdt_size = self.checkDtbSizes(data, pad_len, start)
+
+ # TPL has no devicetree
+ start += fdt_size + len(U_BOOT_TPL_DATA)
+ self.assertEqual(len(data), start)
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index e949435..10778f4 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -47,9 +47,23 @@ class Image(section.Entry_section):
exception). This should be used if the Image is being loaded from
a file rather than generated. In that case we obviously don't need
the entry arguments since the contents already exists.
+ use_expanded: True if we are updating the FDT wth entry offsets, etc.
+ and should use the expanded versions of the U-Boot entries.
+ Any entry type that includes a devicetree must put it in a
+ separate entry so that it will be updated. For example. 'u-boot'
+ normally just picks up 'u-boot.bin' which includes the
+ devicetree, but this is not updateable, since it comes into
+ binman as one piece and binman doesn't know that it is actually
+ an executable followed by a devicetree. Of course it could be
+ taught this, but then when reading an image (e.g. 'binman ls')
+ it may need to be able to split the devicetree out of the image
+ in order to determine the location of things. Instead we choose
+ to ignore 'u-boot-bin' in this case, and build it ourselves in
+ binman with 'u-boot-dtb.bin' and 'u-boot.dtb'. See
+ Entry_u_boot_expanded and Entry_blob_phase for details.
"""
def __init__(self, name, node, copy_to_orig=True, test=False,
- ignore_missing=False):
+ ignore_missing=False, use_expanded=False):
super().__init__(None, 'section', node, test=test)
self.copy_to_orig = copy_to_orig
self.name = 'main-section'
@@ -59,6 +73,7 @@ class Image(section.Entry_section):
self.fdtmap_data = None
self.allow_repack = False
self._ignore_missing = ignore_missing
+ self.use_expanded = use_expanded
if not test:
self.ReadNode()
diff --git a/tools/binman/index.rst b/tools/binman/index.rst
new file mode 100644
index 0000000..6eef7b5
--- /dev/null
+++ b/tools/binman/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Binman
+======
+
+.. toctree::
+ :maxdepth: 2
+
+ README
diff --git a/tools/binman/setup.py b/tools/binman/setup.py
index fe408ed..5ed94ab 100644
--- a/tools/binman/setup.py
+++ b/tools/binman/setup.py
@@ -7,6 +7,6 @@ setup(name='binman',
scripts=['binman'],
packages=['binman', 'binman.etype'],
package_dir={'binman': ''},
- package_data={'binman': ['README', 'README.entries']},
+ package_data={'binman': ['README.rst', 'entries.rst']},
classifiers=['Environment :: Console',
'Topic :: Software Development :: Embedded Systems'])
diff --git a/tools/binman/state.py b/tools/binman/state.py
index bb3e36e..dfb1760 100644
--- a/tools/binman/state.py
+++ b/tools/binman/state.py
@@ -13,15 +13,20 @@ import os
from patman import tools
from patman import tout
+# Map an dtb etype to its expected filename
+DTB_TYPE_FNAME = {
+ 'u-boot-spl-dtb': 'spl/u-boot-spl.dtb',
+ 'u-boot-tpl-dtb': 'tpl/u-boot-tpl.dtb',
+ }
+
# Records the device-tree files known to binman, keyed by entry type (e.g.
# 'u-boot-spl-dtb'). These are the output FDT files, which can be updated by
# binman. They have been copied to <xxx>.out files.
#
-# key: entry type
+# key: entry type (e.g. 'u-boot-dtb)
# value: tuple:
# Fdt object
# Filename
-# Entry object, or None if not known
output_fdt_info = {}
# Prefix to add to an fdtmap path to turn it into a path to the /binman node
@@ -118,11 +123,11 @@ def UpdateFdtContents(etype, data):
etype: Entry type (e.g. 'u-boot-dtb')
data: Data to replace the DTB with
"""
- dtb, fname, entry = output_fdt_info[etype]
+ dtb, fname = output_fdt_info[etype]
dtb_fname = dtb.GetFilename()
tools.WriteFile(dtb_fname, data)
dtb = fdt.FdtScan(dtb_fname)
- output_fdt_info[etype] = [dtb, fname, entry]
+ output_fdt_info[etype] = [dtb, fname]
def SetEntryArgs(args):
"""Set the value of the entry args
@@ -136,12 +141,16 @@ def SetEntryArgs(args):
global entry_args
entry_args = {}
+ tout.Debug('Processing entry args:')
if args:
for arg in args:
m = re.match('([^=]*)=(.*)', arg)
if not m:
raise ValueError("Invalid entry arguemnt '%s'" % arg)
- entry_args[m.group(1)] = m.group(2)
+ name, value = m.groups()
+ tout.Debug(' %20s = %s' % (name, value))
+ entry_args[name] = value
+ tout.Debug('Processing entry args done')
def GetEntryArg(name):
"""Get the value of an entry argument
@@ -154,6 +163,19 @@ def GetEntryArg(name):
"""
return entry_args.get(name)
+def GetEntryArgBool(name):
+ """Get the value of an entry argument as a boolean
+
+ Args:
+ name: Name of argument to retrieve
+
+ Returns:
+ False if the entry argument is consider False (empty, '0' or 'n'), else
+ True
+ """
+ val = GetEntryArg(name)
+ return val and val not in ['n', '0']
+
def Prepare(images, dtb):
"""Get device tree files ready for use
@@ -177,22 +199,22 @@ def Prepare(images, dtb):
main_dtb = dtb
output_fdt_info.clear()
fdt_path_prefix = ''
- output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb', None]
- output_fdt_info['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb', None]
- output_fdt_info['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb', None]
- if not use_fake_dtb:
+ output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb']
+ if use_fake_dtb:
+ for etype, fname in DTB_TYPE_FNAME.items():
+ output_fdt_info[etype] = [dtb, fname]
+ else:
fdt_set = {}
- for image in images.values():
- fdt_set.update(image.GetFdts())
- for etype, other in fdt_set.items():
- entry, other_fname = other
- infile = tools.GetInputFilename(other_fname)
- other_fname_dtb = fdt_util.EnsureCompiled(infile)
- out_fname = tools.GetOutputFilename('%s.out' %
- os.path.split(other_fname)[1])
- tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
- other_dtb = fdt.FdtScan(out_fname)
- output_fdt_info[etype] = [other_dtb, out_fname, entry]
+ for etype, fname in DTB_TYPE_FNAME.items():
+ infile = tools.GetInputFilename(fname, allow_missing=True)
+ if infile and os.path.exists(infile):
+ fname_dtb = fdt_util.EnsureCompiled(infile)
+ out_fname = tools.GetOutputFilename('%s.out' %
+ os.path.split(fname)[1])
+ tools.WriteFile(out_fname, tools.ReadFile(fname_dtb))
+ other_dtb = fdt.FdtScan(out_fname)
+ output_fdt_info[etype] = [other_dtb, out_fname]
+
def PrepareFromLoadedData(image):
"""Get device tree files ready for use with a loaded image
@@ -215,7 +237,7 @@ def PrepareFromLoadedData(image):
tout.Info('Preparing device trees')
output_fdt_info.clear()
fdt_path_prefix = ''
- output_fdt_info['fdtmap'] = [image.fdtmap_dtb, 'u-boot.dtb', None]
+ output_fdt_info['fdtmap'] = [image.fdtmap_dtb, 'u-boot.dtb']
main_dtb = None
tout.Info(" Found device tree type 'fdtmap' '%s'" % image.fdtmap_dtb.name)
for etype, value in image.GetFdts().items():
@@ -233,7 +255,7 @@ def PrepareFromLoadedData(image):
if 'multiple-images' in image_node.props:
image_node = dtb.GetNode('/binman/%s' % image.image_node)
fdt_path_prefix = image_node.path
- output_fdt_info[etype] = [dtb, None, entry]
+ output_fdt_info[etype] = [dtb, None]
tout.Info(" FDT path prefix '%s'" % fdt_path_prefix)
@@ -268,12 +290,11 @@ def GetUpdateNodes(node, for_repack=False):
is node, SPL and TPL)
"""
yield node
- for dtb, fname, entry in output_fdt_info.values():
+ for entry_type, (dtb, fname) in output_fdt_info.items():
if dtb != node.GetFdt():
- if for_repack and entry.etype != 'u-boot-dtb':
+ if for_repack and entry_type != 'u-boot-dtb':
continue
other_node = dtb.GetNode(fdt_path_prefix + node.path)
- #print(' try', fdt_path_prefix + node.path, other_node)
if other_node:
yield other_node
diff --git a/tools/binman/test/053_symbols.dts b/tools/binman/test/053_symbols.dts
index 8af5751..2965809 100644
--- a/tools/binman/test/053_symbols.dts
+++ b/tools/binman/test/053_symbols.dts
@@ -10,7 +10,7 @@
};
u-boot {
- offset = <24>;
+ offset = <0x18>;
};
u-boot-spl2 {
diff --git a/tools/binman/test/149_symbols_tpl.dts b/tools/binman/test/149_symbols_tpl.dts
index dfc84af..0a4ab3f 100644
--- a/tools/binman/test/149_symbols_tpl.dts
+++ b/tools/binman/test/149_symbols_tpl.dts
@@ -21,7 +21,6 @@
section {
u-boot-tpl {
- type = "u-boot-tpl";
};
};
};
diff --git a/tools/binman/test/155_symbols_tpl_x86.dts b/tools/binman/test/155_symbols_tpl_x86.dts
index 72ca447..9d7dc51 100644
--- a/tools/binman/test/155_symbols_tpl_x86.dts
+++ b/tools/binman/test/155_symbols_tpl_x86.dts
@@ -24,7 +24,6 @@
section {
u-boot-tpl {
- type = "u-boot-tpl";
};
};
};
diff --git a/tools/binman/test/192_symbols_nodtb.dts b/tools/binman/test/192_symbols_nodtb.dts
new file mode 100644
index 0000000..5c900d6
--- /dev/null
+++ b/tools/binman/test/192_symbols_nodtb.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl-nodtb {
+ };
+ u-boot-spl-dtb {
+ };
+
+ u-boot {
+ offset = <0x38>;
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl-nodtb";
+ };
+ u-boot-spl-dtb2 {
+ type = "u-boot-spl-dtb";
+ };
+ };
+};
diff --git a/tools/binman/test/192_u_boot_tpl_nodtb.dts b/tools/binman/test/192_u_boot_tpl_nodtb.dts
new file mode 100644
index 0000000..94cef39
--- /dev/null
+++ b/tools/binman/test/192_u_boot_tpl_nodtb.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot-tpl-nodtb {
+ };
+ };
+};
diff --git a/tools/binman/test/193_tpl_bss_pad.dts b/tools/binman/test/193_tpl_bss_pad.dts
new file mode 100644
index 0000000..f5c2db0
--- /dev/null
+++ b/tools/binman/test/193_tpl_bss_pad.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot-tpl {
+ };
+
+ u-boot-tpl-bss-pad {
+ };
+
+ u-boot {
+ };
+ };
+};
diff --git a/tools/binman/test/194_fdt_incl.dts b/tools/binman/test/194_fdt_incl.dts
new file mode 100644
index 0000000..b14c8ff
--- /dev/null
+++ b/tools/binman/test/194_fdt_incl.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ u-boot-spl {
+ };
+ u-boot-tpl {
+ };
+ };
+};
diff --git a/tools/binman/test/195_fdt_incl_tpl.dts b/tools/binman/test/195_fdt_incl_tpl.dts
new file mode 100644
index 0000000..3756ac4
--- /dev/null
+++ b/tools/binman/test/195_fdt_incl_tpl.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot-tpl {
+ };
+ };
+};
diff --git a/tools/binman/test/u_boot_binman_syms.c b/tools/binman/test/u_boot_binman_syms.c
index 4520b31..37fc339 100644
--- a/tools/binman/test/u_boot_binman_syms.c
+++ b/tools/binman/test/u_boot_binman_syms.c
@@ -8,7 +8,7 @@
#define CONFIG_BINMAN
#include <binman_sym.h>
-binman_sym_declare(unsigned long, u_boot_spl, offset);
+binman_sym_declare(unsigned long, u_boot_spl_any, offset);
binman_sym_declare(unsigned long long, u_boot_spl2, offset);
binman_sym_declare(unsigned long, u_boot_any, image_pos);
binman_sym_declare(unsigned long, u_boot_any, size);
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index b7abaed..b5c449e 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -52,6 +52,20 @@ TYPE_NAMES = {
STRUCT_PREFIX = 'dtd_'
VAL_PREFIX = 'dtv_'
+# Properties which are considered to be phandles
+# key: property name
+# value: name of associated #cells property in the target node
+#
+# New phandle properties must be added here; otherwise they will come through as
+# simple integers and finding devices by phandle will not work.
+# Any property that ends with one of these (e.g. 'cd-gpios') will be considered
+# a phandle property.
+PHANDLE_PROPS = {
+ 'clocks': '#clock-cells',
+ 'gpios': '#gpio-cells',
+ 'sandbox,emul': '#emul-cells',
+ }
+
class Ftype(IntEnum):
SOURCE, HEADER = range(2)
@@ -136,8 +150,10 @@ class DtbPlatdata():
from the U-Boot source code
_fdt: Fdt object, referencing the device tree
_dtb_fname: Filename of the input device tree binary file
- _valid_nodes: A list of Node object with compatible strings. The list
- is ordered by conv_name_to_c(node.name)
+ _valid_nodes_unsorted: A list of Node object with compatible strings,
+ ordered by devicetree node order
+ _valid_nodes: A list of Node object with compatible strings, ordered by
+ conv_name_to_c(node.name)
_include_disabled: true to include nodes marked status = "disabled"
_outfile: The current output file (sys.stdout or a real file)
_lines: Stashed list of output lines for outputting in the future
@@ -149,18 +165,25 @@ class DtbPlatdata():
key (str): Field name
value: Prop object with field information
_basedir (str): Base directory of source tree
+ _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
+ the selected devices (see _valid_node), in alphabetical order
+ _instantiate: Instantiate devices so they don't need to be bound at
+ run-time
"""
- def __init__(self, scan, dtb_fname, include_disabled):
+ def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
self._scan = scan
self._fdt = None
self._dtb_fname = dtb_fname
self._valid_nodes = None
+ self._valid_nodes_unsorted = None
self._include_disabled = include_disabled
self._outfile = None
self._lines = []
self._dirnames = [None] * len(Ftype)
self._struct_data = collections.OrderedDict()
self._basedir = None
+ self._valid_uclasses = None
+ self._instantiate = instantiate
def setup_output_dirs(self, output_dirs):
"""Set up the output directories
@@ -223,6 +246,7 @@ class DtbPlatdata():
"""
if self._outfile != sys.stdout:
self._outfile.close()
+ self._outfile = None
def out(self, line):
"""Output a string to the output file
@@ -281,7 +305,11 @@ class DtbPlatdata():
ValueError: if the phandle cannot be parsed or the required property
is not present
"""
- if prop.name in ['clocks', 'cd-gpios']:
+ cells_prop = None
+ for name, cprop in PHANDLE_PROPS.items():
+ if prop.name.endswith(name):
+ cells_prop = cprop
+ if cells_prop:
if not isinstance(prop.value, list):
prop.value = [prop.value]
val = prop.value
@@ -301,14 +329,10 @@ class DtbPlatdata():
if not target:
raise ValueError("Cannot parse '%s' in node '%s'" %
(prop.name, node_name))
- cells = None
- for prop_name in ['#clock-cells', '#gpio-cells']:
- cells = target.props.get(prop_name)
- if cells:
- break
+ cells = target.props.get(cells_prop)
if not cells:
raise ValueError("Node '%s' has no cells property" %
- (target.name))
+ target.name)
num_args = fdt_util.fdt32_to_cpu(cells.value)
max_args = max(max_args, num_args)
args.append(num_args)
@@ -324,38 +348,84 @@ class DtbPlatdata():
"""
self._fdt = fdt.FdtScan(self._dtb_fname)
- def scan_node(self, root, valid_nodes):
+ def scan_node(self, node, valid_nodes):
"""Scan a node and subnodes to build a tree of node and phandle info
- This adds each node to self._valid_nodes.
+ This adds each subnode to self._valid_nodes if it is enabled and has a
+ compatible string.
Args:
- root (Node): Root node for scan
+ node (Node): Node for scan for subnodes
valid_nodes (list of Node): List of Node objects to add to
"""
- for node in root.subnodes:
- if 'compatible' in node.props:
- status = node.props.get('status')
+ for subnode in node.subnodes:
+ if 'compatible' in subnode.props:
+ status = subnode.props.get('status')
if (not self._include_disabled and not status or
status.value != 'disabled'):
- valid_nodes.append(node)
+ valid_nodes.append(subnode)
# recurse to handle any subnodes
- self.scan_node(node, valid_nodes)
+ self.scan_node(subnode, valid_nodes)
- def scan_tree(self):
+ def scan_tree(self, add_root):
"""Scan the device tree for useful information
This fills in the following properties:
- _valid_nodes: A list of nodes we wish to consider include in the
- platform data
+ _valid_nodes_unsorted: A list of nodes we wish to consider include
+ in the platform data (in devicetree node order)
+ _valid_nodes: Sorted version of _valid_nodes_unsorted
+
+ Args:
+ add_root: True to add the root node also (which wouldn't normally
+ be added as it may not have a compatible string)
"""
+ root = self._fdt.GetRoot()
valid_nodes = []
- self.scan_node(self._fdt.GetRoot(), valid_nodes)
+ if add_root:
+ valid_nodes.append(root)
+ self.scan_node(root, valid_nodes)
+ self._valid_nodes_unsorted = valid_nodes
self._valid_nodes = sorted(valid_nodes,
key=lambda x: conv_name_to_c(x.name))
+
+ def prepare_nodes(self):
+ """Add extra properties to the nodes we are using
+
+ The following properties are added for use by dtoc:
+ idx: Index number of this node (0=first, etc.)
+ struct_name: Name of the struct dtd used by this node
+ var_name: C name for this node
+ child_devs: List of child devices for this node, each a None
+ child_refs: Dict of references for each child:
+ key: Position in child list (-1=head, 0=first, 1=second, ...
+ n-1=last, n=head)
+ seq: Sequence number of the device (unique within its uclass), or
+ -1 not not known yet
+ dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
+ driver: Driver record for this node, or None if not known
+ uclass: Uclass record for this node, or None if not known
+ uclass_seq: Position of this device within the uclass list (0=first,
+ n-1=last)
+ parent_seq: Position of this device within it siblings (0=first,
+ n-1=last)
+ parent_driver: Driver record of the node's parent, or None if none.
+ We don't use node.parent.driver since node.parent may not be in
+ the list of valid nodes
+ """
for idx, node in enumerate(self._valid_nodes):
node.idx = idx
+ node.struct_name, _ = self._scan.get_normalized_compat_name(node)
+ node.var_name = conv_name_to_c(node.name)
+ node.child_devs = []
+ node.child_refs = {}
+ node.seq = -1
+ node.dev_ref = None
+ node.driver = None
+ node.uclass = None
+ node.uclass_seq = None
+ node.parent_seq = None
+ node.parent_driver = None
@staticmethod
def get_num_cells(node):
@@ -434,7 +504,6 @@ class DtbPlatdata():
"""
structs = self._struct_data
for node in self._valid_nodes:
- node_name, _ = self._scan.get_normalized_compat_name(node)
fields = {}
# Get a list of all the valid properties in this node.
@@ -442,9 +511,9 @@ class DtbPlatdata():
if name not in PROP_IGNORE_LIST and name[0] != '#':
fields[name] = copy.deepcopy(prop)
- # If we've seen this node_name before, update the existing struct.
- if node_name in structs:
- struct = structs[node_name]
+ # If we've seen this struct_name before, update the existing struct
+ if node.struct_name in structs:
+ struct = structs[node.struct_name]
for name, prop in fields.items():
oldprop = struct.get(name)
if oldprop:
@@ -454,11 +523,10 @@ class DtbPlatdata():
# Otherwise store this as a new struct.
else:
- structs[node_name] = fields
+ structs[node.struct_name] = fields
for node in self._valid_nodes:
- node_name, _ = self._scan.get_normalized_compat_name(node)
- struct = structs[node_name]
+ struct = structs[node.struct_name]
for name, prop in node.props.items():
if name not in PROP_IGNORE_LIST and name[0] != '#':
prop.Widen(struct[name])
@@ -562,28 +630,145 @@ class DtbPlatdata():
self.buf(', '.join(vals[i:i + 8]))
self.buf('}')
- def _declare_device(self, var_name, struct_name, node_parent):
+ def _declare_device(self, node):
"""Add a device declaration to the output
This declares a U_BOOT_DRVINFO() for the device being processed
Args:
- var_name (str): C name for the node
- struct_name (str): Name for the dt struct associated with the node
- node_parent (Node): Parent of the node (or None if none)
+ node: Node to process
"""
- self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
- self.buf('\t.name\t\t= "%s",\n' % struct_name)
- self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
- self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
+ self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
+ self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+ self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+ self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
+ (VAL_PREFIX, node.var_name))
idx = -1
- if node_parent and node_parent in self._valid_nodes:
- idx = node_parent.idx
+ if node.parent and node.parent in self._valid_nodes:
+ idx = node.parent.idx
self.buf('\t.parent_idx\t= %d,\n' % idx)
self.buf('};\n')
self.buf('\n')
- def _output_prop(self, node, prop):
+ def prep_priv(self, struc, name, suffix, section='.priv_data'):
+ if not struc:
+ return None
+ var_name = '_%s%s' % (name, suffix)
+ hdr = self._scan._structs.get(struc)
+ if hdr:
+ self.buf('#include <%s>\n' % hdr.fname)
+ else:
+ print('Warning: Cannot find header file for struct %s' % struc)
+ attr = '__attribute__ ((section ("%s")))' % section
+ return var_name, struc, attr
+
+ def alloc_priv(self, info, name, extra, suffix='_priv'):
+ result = self.prep_priv(info, name, suffix)
+ if not result:
+ return None
+ var_name, struc, section = result
+ self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
+ (var_name, extra, struc.strip(), section))
+ return '%s_%s' % (var_name, extra)
+
+ def alloc_plat(self, info, name, extra, node):
+ result = self.prep_priv(info, name, '_plat')
+ if not result:
+ return None
+ var_name, struc, section = result
+ self.buf('struct %s %s\n\t%s_%s = {\n' %
+ (struc.strip(), section, var_name, extra))
+ self.buf('\t.dtplat = {\n')
+ for pname in sorted(node.props):
+ self._output_prop(node, node.props[pname], 2)
+ self.buf('\t},\n')
+ self.buf('};\n')
+ return '&%s_%s' % (var_name, extra)
+
+ def _declare_device_inst(self, node, parent_driver):
+ """Add a device instance declaration to the output
+
+ This declares a DM_DEVICE_INST() for the device being processed
+
+ Args:
+ node: Node to output
+ """
+ driver = node.driver
+ uclass = node.uclass
+ self.buf('\n')
+ num_lines = len(self._lines)
+ plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
+ node)
+ priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
+ parent_plat_name = None
+ parent_priv_name = None
+ if parent_driver:
+ # TODO: deal with uclass providing these values
+ parent_plat_name = self.alloc_priv(
+ parent_driver.child_plat, driver.name, node.var_name,
+ '_parent_plat')
+ parent_priv_name = self.alloc_priv(
+ parent_driver.child_priv, driver.name, node.var_name,
+ '_parent_priv')
+ uclass_plat_name = self.alloc_priv(
+ uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
+ uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
+ driver.name + '_uc', node.var_name)
+ for hdr in driver.headers:
+ self.buf('#include %s\n' % hdr)
+
+ # Add a blank line if we emitted any stuff above, for readability
+ if num_lines != len(self._lines):
+ self.buf('\n')
+
+ self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
+ self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
+ self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+ if plat_name:
+ self.buf('\t.plat_\t\t= %s,\n' % plat_name)
+ else:
+ self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+ if parent_plat_name:
+ self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
+ if uclass_plat_name:
+ self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
+ driver_date = None
+
+ if node != self._fdt.GetRoot():
+ compat_list = node.props['compatible'].value
+ if not isinstance(compat_list, list):
+ compat_list = [compat_list]
+ for compat in compat_list:
+ driver_data = driver.compat.get(compat)
+ if driver_data:
+ self.buf('\t.driver_data\t= %s,\n' % driver_data)
+ break
+
+ if node.parent and node.parent.parent:
+ self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
+ node.parent.var_name)
+ if priv_name:
+ self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+ self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
+
+ if uclass_priv_name:
+ self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
+ if parent_priv_name:
+ self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
+ self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
+ self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
+ if node.parent in self._valid_nodes:
+ self.list_node('sibling_node', node.parent.child_refs,
+ node.parent_seq)
+ # flags is left as 0
+
+ self.buf('\t.seq_ = %d,\n' % node.seq)
+
+ self.buf('};\n')
+ self.buf('\n')
+ return parent_plat_name
+
+ def _output_prop(self, node, prop, tabs=1):
"""Output a line containing the value of a struct member
Args:
@@ -593,7 +778,7 @@ class DtbPlatdata():
if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
return
member_name = conv_name_to_c(prop.name)
- self.buf('\t%s= ' % tab_to(3, '.' + member_name))
+ self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
# Special handling for lists
if isinstance(prop.value, list):
@@ -602,35 +787,269 @@ class DtbPlatdata():
self.buf(get_value(prop.type, prop.value))
self.buf(',\n')
- def _output_values(self, var_name, struct_name, node):
+ def _output_values(self, node):
"""Output the definition of a device's struct values
Args:
- var_name (str): C name for the node
- struct_name (str): Name for the dt struct associated with the node
- node (Node): Node being output
+ node (Node): Node to output
"""
self.buf('static struct %s%s %s%s = {\n' %
- (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
+ (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
for pname in sorted(node.props):
self._output_prop(node, node.props[pname])
self.buf('};\n')
- def output_node(self, node):
+ def list_head(self, head_member, node_member, node_refs, var_name):
+ self.buf('\t.%s\t= {\n' % head_member)
+ if node_refs:
+ last = node_refs[-1].dev_ref
+ first = node_refs[0].dev_ref
+ member = node_member
+ else:
+ last = 'DM_DEVICE_REF(%s)' % var_name
+ first = last
+ member = head_member
+ self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
+ self.buf('\t\t.next = &%s->%s,\n' % (first, member))
+ self.buf('\t},\n')
+
+ def list_node(self, member, node_refs, seq):
+ self.buf('\t.%s\t= {\n' % member)
+ self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
+ self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
+ self.buf('\t},\n')
+
+ def generate_uclasses(self):
+ if not self.check_instantiate(True):
+ return
+ self.out('\n')
+ self.out('#include <common.h>\n')
+ self.out('#include <dm.h>\n')
+ self.out('#include <dt-structs.h>\n')
+ self.out('\n')
+ self.buf('/*\n')
+ self.buf(
+ " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
+ uclass_list = self._valid_uclasses
+ for seq, uclass in enumerate(uclass_list):
+ self.buf(' * %3d: %s\n' % (seq, uclass.name))
+ self.buf(' *\n')
+ self.buf(' * Sequence numbers allocated in each uclass:\n')
+ for uclass in uclass_list:
+ if uclass.alias_num_to_node:
+ self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
+ for seq, node in uclass.alias_num_to_node.items():
+ self.buf(' * %d: %s\n' % (seq, node.path))
+ self.buf(' */\n')
+
+ uclass_node = {}
+ for seq, uclass in enumerate(uclass_list):
+ uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
+ uclass.name)
+ uclass_node[-1] = '&uclass_head'
+ uclass_node[len(uclass_list)] = '&uclass_head'
+ self.buf('\n')
+ self.buf('struct list_head %s = {\n' % 'uclass_head')
+ self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
+ self.buf('\t.next = %s,\n' % uclass_node[0])
+ self.buf('};\n')
+ self.buf('\n')
+
+ for seq, uclass in enumerate(uclass_list):
+ uc_drv = self._scan._uclass.get(uclass.uclass_id)
+
+ priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
+
+ self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
+ if priv_name:
+ self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+ self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
+ self.list_node('sibling_node', uclass_node, seq)
+ self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
+ self.buf('};\n')
+ self.buf('\n')
+ self.out(''.join(self.get_buf()))
+
+ def read_aliases(self):
+ """Read the aliases and attach the information to self._alias
+
+ Raises:
+ ValueError: The alias path is not found
+ """
+ alias_node = self._fdt.GetNode('/aliases')
+ if not alias_node:
+ return
+ re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
+ for prop in alias_node.props.values():
+ m_alias = re_num.match(prop.name)
+ if not m_alias:
+ raise ValueError("Cannot decode alias '%s'" % prop.name)
+ name, num = m_alias.groups()
+ node = self._fdt.GetNode(prop.value)
+ result = self._scan.add_uclass_alias(name, num, node)
+ if result is None:
+ raise ValueError("Alias '%s' path '%s' not found" %
+ (prop.name, prop.value))
+ elif result is False:
+ print("Could not find uclass for alias '%s'" % prop.name)
+
+ def generate_decl(self):
+ nodes_to_output = list(self._valid_nodes)
+
+ self.buf('#include <dm/device-internal.h>\n')
+ self.buf('#include <dm/uclass-internal.h>\n')
+ self.buf('\n')
+ self.buf(
+ '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
+ for node in nodes_to_output:
+ self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
+ self.buf('\n')
+
+ if self._instantiate:
+ self.buf(
+ '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
+ for node in nodes_to_output:
+ self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
+ self.buf('\n')
+
+ uclass_list = self._valid_uclasses
+
+ self.buf(
+ '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
+ for uclass in uclass_list:
+ self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
+
+ if self._instantiate:
+ self.buf('\n')
+ self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
+ for uclass in uclass_list:
+ self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
+ self.out(''.join(self.get_buf()))
+
+ def assign_seqs(self):
+ """Assign a sequence number to each node"""
+ for node in self._valid_nodes_unsorted:
+ seq = self._scan.assign_seq(node)
+ if seq is not None:
+ node.seq = seq
+
+ def process_nodes(self, need_drivers):
+ nodes_to_output = list(self._valid_nodes)
+
+ # Figure out which drivers we actually use
+ self._scan.mark_used(nodes_to_output)
+
+ for node in nodes_to_output:
+ node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
+ driver = self._scan.get_driver(node.struct_name)
+ if not driver:
+ if not need_drivers:
+ continue
+ raise ValueError("Cannot parse/find driver for '%s'" %
+ node.struct_name)
+ node.driver = driver
+ uclass = self._scan._uclass.get(driver.uclass_id)
+ if not uclass:
+ raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
+ (driver.uclass_id, node.struct_name))
+ node.uclass = uclass
+ node.uclass_seq = len(node.uclass.devs)
+ node.uclass.devs.append(node)
+ uclass.node_refs[node.uclass_seq] = \
+ '&%s->uclass_node' % node.dev_ref
+
+ parent_driver = None
+ if node.parent in self._valid_nodes:
+ parent_driver = self._scan.get_driver(node.parent.struct_name)
+ if not parent_driver:
+ if not need_drivers:
+ continue
+ raise ValueError(
+ "Cannot parse/find parent driver '%s' for '%s'" %
+ (node.parent.struct_name, node.struct_name))
+ node.parent_seq = len(node.parent.child_devs)
+ node.parent.child_devs.append(node)
+ node.parent.child_refs[node.parent_seq] = \
+ '&%s->sibling_node' % node.dev_ref
+ node.parent_driver = parent_driver
+
+ for node in nodes_to_output:
+ ref = '&%s->child_head' % node.dev_ref
+ node.child_refs[-1] = ref
+ node.child_refs[len(node.child_devs)] = ref
+
+ uclass_set = set()
+ for driver in self._scan._drivers.values():
+ if driver.used and driver.uclass:
+ uclass_set.add(driver.uclass)
+ self._valid_uclasses = sorted(list(uclass_set),
+ key=lambda uc: uc.uclass_id)
+
+ for seq, uclass in enumerate(uclass_set):
+ ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
+ uclass.node_refs[-1] = ref
+ uclass.node_refs[len(uclass.devs)] = ref
+
+ def output_node_plat(self, node):
+ """Output the C code for a node
+
+ Args:
+ node (fdt.Node): node to output
+ """
+ driver = node.driver
+ parent_driver = node.parent_driver
+
+ line1 = 'Node %s index %d' % (node.path, node.idx)
+ if driver:
+ self.buf('/*\n')
+ self.buf(' * %s\n' % line1)
+ self.buf(' * driver %s parent %s\n' % (driver.name,
+ parent_driver.name if parent_driver else 'None'))
+ self.buf(' */\n')
+ else:
+ self.buf('/* %s */\n' % line1)
+
+ self._output_values(node)
+ self._declare_device(node)
+
+ self.out(''.join(self.get_buf()))
+
+ def output_node_instance(self, node):
"""Output the C code for a node
Args:
node (fdt.Node): node to output
"""
- struct_name, _ = self._scan.get_normalized_compat_name(node)
- var_name = conv_name_to_c(node.name)
- self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
+ parent_driver = node.parent_driver
+
+ self.buf('/*\n')
+ self.buf(' * Node %s index %d\n' % (node.path, node.idx))
+ self.buf(' * driver %s parent %s\n' % (node.driver.name,
+ parent_driver.name if parent_driver else 'None'))
+ self.buf('*/\n')
- self._output_values(var_name, struct_name, node)
- self._declare_device(var_name, struct_name, node.parent)
+ if not node.driver.plat:
+ self._output_values(node)
+ self._declare_device_inst(node, parent_driver)
self.out(''.join(self.get_buf()))
+ def check_instantiate(self, require):
+ """Check if self._instantiate is set to the required value
+
+ If not, this outputs a message into the current file
+
+ Args:
+ require: True to require --instantiate, False to require that it not
+ be enabled
+ """
+ if require != self._instantiate:
+ self.out(
+ '/* This file is not used: --instantiate was %senabled */\n' %
+ ('not ' if require else ''))
+ return False
+ return True
+
def generate_plat(self):
"""Generate device defintions for the platform data
@@ -641,6 +1060,8 @@ class DtbPlatdata():
See the documentation in doc/driver-model/of-plat.rst for more
information.
"""
+ if not self.check_instantiate(False):
+ return
self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
self.out('#define DT_PLAT_C\n')
self.out('\n')
@@ -649,8 +1070,57 @@ class DtbPlatdata():
self.out('#include <dt-structs.h>\n')
self.out('\n')
- for node in self._valid_nodes:
- self.output_node(node)
+ if self._valid_nodes:
+ self.out('/*\n')
+ self.out(
+ " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
+ self.out(' *\n')
+ self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ for node in self._valid_nodes:
+ self.out(' * %3d: %-20s %-s\n' %
+ (node.idx, node.var_name, node.struct_name))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ self.out(' */\n')
+ self.out('\n')
+
+ for node in self._valid_nodes:
+ self.output_node_plat(node)
+
+ self.out(''.join(self.get_buf()))
+
+ def generate_device(self):
+ """Generate device instances
+
+ This writes out DM_DEVICE_INST() records for each device in the
+ build.
+
+ See the documentation in doc/driver-model/of-plat.rst for more
+ information.
+ """
+ if not self.check_instantiate(True):
+ return
+ self.out('#include <common.h>\n')
+ self.out('#include <dm.h>\n')
+ self.out('#include <dt-structs.h>\n')
+ self.out('\n')
+
+ if self._valid_nodes:
+ self.out('/*\n')
+ self.out(
+ " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
+ self.out(' *\n')
+ self.out(' * idx %-20s %-s\n' % ('udevice', 'driver'))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ for node in self._valid_nodes:
+ self.out(' * %3d: %-20s %-s\n' %
+ (node.idx, node.var_name, node.struct_name))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ self.out(' */\n')
+ self.out('\n')
+
+ for node in self._valid_nodes:
+ self.output_node_instance(node)
self.out(''.join(self.get_buf()))
@@ -659,6 +1129,9 @@ class DtbPlatdata():
# key: Command used to generate this file
# value: OutputFile for this command
OUTPUT_FILES = {
+ 'decl':
+ OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
+ 'Declares externs for all device/uclass instances'),
'struct':
OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
DtbPlatdata.generate_structs,
@@ -666,11 +1139,18 @@ OUTPUT_FILES = {
'platdata':
OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
'Declares the U_BOOT_DRIVER() records and platform data'),
+ 'device':
+ OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
+ 'Declares the DM_DEVICE_INST() records'),
+ 'uclass':
+ OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
+ 'Declares the uclass instances (struct uclass)'),
}
-def run_steps(args, dtb_file, include_disabled, output, output_dirs,
- warning_disabled=False, drivers_additional=None, basedir=None):
+def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
+ instantiate, warning_disabled=False, drivers_additional=None,
+ basedir=None, scan=None):
"""Run all the steps of the dtoc tool
Args:
@@ -681,12 +1161,22 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
output_dirs (tuple of str):
Directory to put C output files
Directory to put H output files
+ phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+ or 'tpl'. None if not known
+ instantiate: Instantiate devices so they don't need to be bound at
+ run-time
warning_disabled (bool): True to avoid showing warnings about missing
drivers
drivers_additional (list): List of additional drivers to use during
scanning
basedir (str): Base directory of U-Boot source code. Defaults to the
grandparent of this file's directory
+ scan (src_src.Scanner): Scanner from a previous run. This can help speed
+ up tests. Use None for normal operation
+
+ Returns:
+ DtbPlatdata object
+
Raises:
ValueError: if args has no command, or an unknown command
"""
@@ -695,15 +1185,24 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
if output and output_dirs and any(output_dirs):
raise ValueError('Must specify either output or output_dirs, not both')
- scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
- plat = DtbPlatdata(scan, dtb_file, include_disabled)
- scan.scan_drivers()
+ if not scan:
+ scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional,
+ phase)
+ scan.scan_drivers()
+ do_process = True
+ else:
+ do_process = False
+ plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
plat.scan_dtb()
- plat.scan_tree()
+ plat.scan_tree(add_root=instantiate)
+ plat.prepare_nodes()
plat.scan_reg_sizes()
plat.setup_output_dirs(output_dirs)
plat.scan_structs()
plat.scan_phandles()
+ plat.process_nodes(instantiate)
+ plat.read_aliases()
+ plat.assign_seqs()
cmds = args[0].split(',')
if 'all' in cmds:
@@ -718,3 +1217,4 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
plat.out_header(outfile)
outfile.method(plat)
plat.finish_output()
+ return plat
diff --git a/tools/dtoc/dtoc_test_scan_drivers.cxx b/tools/dtoc/dtoc_test_scan_drivers.cxx
deleted file mode 100644
index f448767..0000000
--- a/tools/dtoc/dtoc_test_scan_drivers.cxx
+++ /dev/null
@@ -1 +0,0 @@
-DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index b0ad0f3..93706de 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -53,6 +53,8 @@ def run_tests(processes, args):
sys.argv = [sys.argv[0]]
test_name = args and args[0] or None
+ test_dtoc.setup()
+
test_util.RunTestSuites(
result, debug=True, verbosity=1, test_preserve_dirs=False,
processes=processes, test_name=test_name, toolpath=[],
@@ -79,10 +81,14 @@ parser.add_option('-C', '--h-output-dir', action='store',
help='Select output directory for H files (defaults to --c-output-di)')
parser.add_option('-d', '--dtb-file', action='store',
help='Specify the .dtb input file')
+parser.add_option('-i', '--instantiate', action='store_true', default=False,
+ help='Instantiate devices to avoid needing device_bind()')
parser.add_option('--include-disabled', action='store_true',
help='Include disabled nodes')
parser.add_option('-o', '--output', action='store',
help='Select output filename')
+parser.add_option('-p', '--phase', type=str,
+ help='set phase of U-Boot this invocation is for (spl/tpl)')
parser.add_option('-P', '--processes', type=int,
help='set number of processes to use for running tests')
parser.add_option('-t', '--test', action='store_true', dest='test',
@@ -102,4 +108,5 @@ elif options.test_coverage:
else:
dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
options.output,
- [options.c_output_dir, options.h_output_dir])
+ [options.c_output_dir, options.h_output_dir],
+ options.phase, instantiate=options.instantiate)
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index f63c9fc..114212c 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -33,6 +33,8 @@ def conv_name_to_c(name):
new = new.replace('-', '_')
new = new.replace(',', '_')
new = new.replace('.', '_')
+ if new == '/':
+ return 'root'
return new
def get_compat_name(node):
@@ -54,15 +56,123 @@ class Driver:
Attributes:
name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
+ fname: Filename where the driver was found
+ uclass_id: Name of uclass, e.g. 'UCLASS_I2C'
+ compat: Driver data for each compatible string:
+ key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ fname: Filename where the driver was found
+ priv (str): struct name of the priv_auto member, e.g. 'serial_priv'
+ plat (str): struct name of the plat_auto member, e.g. 'serial_plat'
+ child_priv (str): struct name of the per_child_auto member,
+ e.g. 'pci_child_priv'
+ child_plat (str): struct name of the per_child_plat_auto member,
+ e.g. 'pci_child_plat'
+ used (bool): True if the driver is used by the structs being output
+ phase (str): Which phase of U-Boot to use this driver
+ headers (list): List of header files needed for this driver (each a str)
+ e.g. ['<asm/cpu.h>']
+ dups (list): Driver objects with the same name as this one, that were
+ found after this one
+ warn_dups (bool): True if the duplicates are not distinguisble using
+ the phase
+ uclass (Uclass): uclass for this driver
+ """
+ def __init__(self, name, fname):
+ self.name = name
+ self.fname = fname
+ self.uclass_id = None
+ self.compat = None
+ self.priv = ''
+ self.plat = ''
+ self.child_priv = ''
+ self.child_plat = ''
+ self.used = False
+ self.phase = ''
+ self.headers = []
+ self.dups = []
+ self.warn_dups = False
+ self.uclass = None
+
+ def __eq__(self, other):
+ return (self.name == other.name and
+ self.uclass_id == other.uclass_id and
+ self.compat == other.compat and
+ self.priv == other.priv and
+ self.plat == other.plat and
+ self.used == other.used)
+
+ def __repr__(self):
+ return ("Driver(name='%s', used=%s, uclass_id='%s', compat=%s, priv=%s)" %
+ (self.name, self.used, self.uclass_id, self.compat, self.priv))
+
+
+class UclassDriver:
+ """Holds information about a uclass driver
+
+ Attributes:
+ name: Uclass name, e.g. 'i2c' if the driver is for UCLASS_I2C
+ uclass_id: Uclass ID, e.g. 'UCLASS_I2C'
+ priv: struct name of the private data, e.g. 'i2c_priv'
+ per_dev_priv (str): struct name of the priv_auto member, e.g. 'spi_info'
+ per_dev_plat (str): struct name of the plat_auto member, e.g. 'i2c_chip'
+ per_child_priv (str): struct name of the per_child_auto member,
+ e.g. 'pci_child_priv'
+ per_child_plat (str): struct name of the per_child_plat_auto member,
+ e.g. 'pci_child_plat'
+ alias_num_to_node (dict): Aliases for this uclasses (for sequence
+ numbers)
+ key (int): Alias number, e.g. 2 for "pci2"
+ value (str): Node the alias points to
+ alias_path_to_num (dict): Convert a path to an alias number
+ key (str): Full path to node (e.g. '/soc/pci')
+ seq (int): Alias number, e.g. 2 for "pci2"
+ devs (list): List of devices in this uclass, each a Node
+ node_refs (dict): References in the linked list of devices:
+ key (int): Sequence number (0=first, n-1=last, -1=head, n=tail)
+ value (str): Reference to the device at that position
"""
def __init__(self, name):
self.name = name
+ self.uclass_id = None
+ self.priv = ''
+ self.per_dev_priv = ''
+ self.per_dev_plat = ''
+ self.per_child_priv = ''
+ self.per_child_plat = ''
+ self.alias_num_to_node = {}
+ self.alias_path_to_num = {}
+ self.devs = []
+ self.node_refs = {}
def __eq__(self, other):
- return self.name == other.name
+ return (self.name == other.name and
+ self.uclass_id == other.uclass_id and
+ self.priv == other.priv)
def __repr__(self):
- return "Driver(name='%s')" % self.name
+ return ("UclassDriver(name='%s', uclass_id='%s')" %
+ (self.name, self.uclass_id))
+
+ def __hash__(self):
+ # We can use the uclass ID since it is unique among uclasses
+ return hash(self.uclass_id)
+
+
+class Struct:
+ """Holds information about a struct definition
+
+ Attributes:
+ name: Struct name, e.g. 'fred' if the struct is 'struct fred'
+ fname: Filename containing the struct, in a format that C files can
+ include, e.g. 'asm/clk.h'
+ """
+ def __init__(self, name, fname):
+ self.name = name
+ self.fname =fname
+
+ def __repr__(self):
+ return ("Struct(name='%s', fname='%s')" % (self.name, self.fname))
class Scanner:
@@ -81,8 +191,22 @@ class Scanner:
_warning_disabled: true to disable warnings about driver names not found
_drivers_additional (list or str): List of additional drivers to use
during scanning
+ _of_match: Dict holding information about compatible strings
+ key: Name of struct udevice_id variable
+ value: Dict of compatible info in that variable:
+ key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ _compat_to_driver: Maps compatible strings to Driver
+ _uclass: Dict of uclass information
+ key: uclass name, e.g. 'UCLASS_I2C'
+ value: UClassDriver
+ _structs: Dict of all structs found in U-Boot:
+ key: Name of struct
+ value: Struct object
+ _phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+ or 'tpl'. None if not known
"""
- def __init__(self, basedir, warning_disabled, drivers_additional):
+ def __init__(self, basedir, warning_disabled, drivers_additional, phase=''):
"""Set up a new Scanner
"""
if not basedir:
@@ -94,6 +218,22 @@ class Scanner:
self._driver_aliases = {}
self._drivers_additional = drivers_additional or []
self._warning_disabled = warning_disabled
+ self._of_match = {}
+ self._compat_to_driver = {}
+ self._uclass = {}
+ self._structs = {}
+ self._phase = phase
+
+ def get_driver(self, name):
+ """Get a driver given its name
+
+ Args:
+ name (str): Driver name
+
+ Returns:
+ Driver: Driver or None if not found
+ """
+ return self._drivers.get(name)
def get_normalized_compat_name(self, node):
"""Get a node's normalized compat name
@@ -112,7 +252,10 @@ class Scanner:
In case of no match found, the return will be the same as
get_compat_name()
"""
- compat_list_c = get_compat_name(node)
+ if not node.parent:
+ compat_list_c = ['root_driver']
+ else:
+ compat_list_c = get_compat_name(node)
for compat_c in compat_list_c:
if not compat_c in self._drivers.keys():
@@ -131,10 +274,319 @@ class Scanner:
return compat_list_c[0], compat_list_c[1:]
+ def _parse_structs(self, fname, buff):
+ """Parse a H file to extract struct definitions contained within
+
+ This parses 'struct xx {' definitions to figure out what structs this
+ header defines.
+
+ Args:
+ buff (str): Contents of file
+ fname (str): Filename (to use when printing errors)
+ """
+ structs = {}
+
+ re_struct = re.compile('^struct ([a-z0-9_]+) {$')
+ re_asm = re.compile('../arch/[a-z0-9]+/include/asm/(.*)')
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ m_struct = re_struct.match(line)
+ if m_struct:
+ name = m_struct.group(1)
+ include_dir = os.path.join(self._basedir, 'include')
+ rel_fname = os.path.relpath(fname, include_dir)
+ m_asm = re_asm.match(rel_fname)
+ if m_asm:
+ rel_fname = 'asm/' + m_asm.group(1)
+ structs[name] = Struct(name, rel_fname)
+ self._structs.update(structs)
+
+ @classmethod
+ def _get_re_for_member(cls, member):
+ """_get_re_for_member: Get a compiled regular expression
+
+ Args:
+ member (str): Struct member name, e.g. 'priv_auto'
+
+ Returns:
+ re.Pattern: Compiled regular expression that parses:
+
+ .member = sizeof(struct fred),
+
+ and returns "fred" as group 1
+ """
+ return re.compile(r'^\s*.%s\s*=\s*sizeof\(struct\s+(.*)\),$' % member)
+
+ def _parse_uclass_driver(self, fname, buff):
+ """Parse a C file to extract uclass driver information contained within
+
+ This parses UCLASS_DRIVER() structs to obtain various pieces of useful
+ information.
+
+ It updates the following member:
+ _uclass: Dict of uclass information
+ key: uclass name, e.g. 'UCLASS_I2C'
+ value: UClassDriver
+
+ Args:
+ fname (str): Filename being parsed (used for warnings)
+ buff (str): Contents of file
+ """
+ uc_drivers = {}
+
+ # Collect the driver name and associated Driver
+ driver = None
+ re_driver = re.compile(r'^UCLASS_DRIVER\((.*)\)')
+
+ # Collect the uclass ID, e.g. 'UCLASS_SPI'
+ re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+ # Matches the header/size information for uclass-private data
+ re_priv = self._get_re_for_member('priv_auto')
+
+ # Set up parsing for the auto members
+ re_per_device_priv = self._get_re_for_member('per_device_auto')
+ re_per_device_plat = self._get_re_for_member('per_device_plat_auto')
+ re_per_child_priv = self._get_re_for_member('per_child_auto')
+ re_per_child_plat = self._get_re_for_member('per_child_plat_auto')
+
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ driver_match = re_driver.search(line)
+
+ # If we have seen UCLASS_DRIVER()...
+ if driver:
+ m_id = re_id.search(line)
+ m_priv = re_priv.match(line)
+ m_per_dev_priv = re_per_device_priv.match(line)
+ m_per_dev_plat = re_per_device_plat.match(line)
+ m_per_child_priv = re_per_child_priv.match(line)
+ m_per_child_plat = re_per_child_plat.match(line)
+ if m_id:
+ driver.uclass_id = m_id.group(1)
+ elif m_priv:
+ driver.priv = m_priv.group(1)
+ elif m_per_dev_priv:
+ driver.per_dev_priv = m_per_dev_priv.group(1)
+ elif m_per_dev_plat:
+ driver.per_dev_plat = m_per_dev_plat.group(1)
+ elif m_per_child_priv:
+ driver.per_child_priv = m_per_child_priv.group(1)
+ elif m_per_child_plat:
+ driver.per_child_plat = m_per_child_plat.group(1)
+ elif '};' in line:
+ if not driver.uclass_id:
+ raise ValueError(
+ "%s: Cannot parse uclass ID in driver '%s'" %
+ (fname, driver.name))
+ uc_drivers[driver.uclass_id] = driver
+ driver = None
+
+ elif driver_match:
+ driver_name = driver_match.group(1)
+ driver = UclassDriver(driver_name)
+
+ self._uclass.update(uc_drivers)
+
+ def _parse_driver(self, fname, buff):
+ """Parse a C file to extract driver information contained within
+
+ This parses U_BOOT_DRIVER() structs to obtain various pieces of useful
+ information.
+
+ It updates the following members:
+ _drivers - updated with new Driver records for each driver found
+ in the file
+ _of_match - updated with each compatible string found in the file
+ _compat_to_driver - Maps compatible string to Driver
+ _driver_aliases - Maps alias names to driver name
+
+ Args:
+ fname (str): Filename being parsed (used for warnings)
+ buff (str): Contents of file
+
+ Raises:
+ ValueError: Compatible variable is mentioned in .of_match in
+ U_BOOT_DRIVER() but not found in the file
+ """
+ # Dict holding information about compatible strings collected in this
+ # function so far
+ # key: Name of struct udevice_id variable
+ # value: Dict of compatible info in that variable:
+ # key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ of_match = {}
+
+ # Dict holding driver information collected in this function so far
+ # key: Driver name (C name as in U_BOOT_DRIVER(xxx))
+ # value: Driver
+ drivers = {}
+
+ # Collect the driver info
+ driver = None
+ re_driver = re.compile(r'^U_BOOT_DRIVER\((.*)\)')
+
+ # Collect the uclass ID, e.g. 'UCLASS_SPI'
+ re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+ # Collect the compatible string, e.g. 'rockchip,rk3288-grf'
+ compat = None
+ re_compat = re.compile(r'{\s*.compatible\s*=\s*"(.*)"\s*'
+ r'(,\s*.data\s*=\s*(\S*))?\s*},')
+
+ # This is a dict of compatible strings that were found:
+ # key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ compat_dict = {}
+
+ # Holds the var nane of the udevice_id list, e.g.
+ # 'rk3288_syscon_ids_noc' in
+ # static const struct udevice_id rk3288_syscon_ids_noc[] = {
+ ids_name = None
+ re_ids = re.compile(r'struct udevice_id (.*)\[\]\s*=')
+
+ # Matches the references to the udevice_id list
+ re_of_match = re.compile(
+ r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
+
+ re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
+ re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
+ re_alias = re.compile(r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)')
+
+ # Matches the struct name for priv, plat
+ re_priv = self._get_re_for_member('priv_auto')
+ re_plat = self._get_re_for_member('plat_auto')
+ re_child_priv = self._get_re_for_member('per_child_auto')
+ re_child_plat = self._get_re_for_member('per_child_plat_auto')
+
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ driver_match = re_driver.search(line)
+
+ # If this line contains U_BOOT_DRIVER()...
+ if driver:
+ m_id = re_id.search(line)
+ m_of_match = re_of_match.search(line)
+ m_priv = re_priv.match(line)
+ m_plat = re_plat.match(line)
+ m_cplat = re_child_plat.match(line)
+ m_cpriv = re_child_priv.match(line)
+ m_phase = re_phase.match(line)
+ m_hdr = re_hdr.match(line)
+ if m_priv:
+ driver.priv = m_priv.group(1)
+ elif m_plat:
+ driver.plat = m_plat.group(1)
+ elif m_cplat:
+ driver.child_plat = m_cplat.group(1)
+ elif m_cpriv:
+ driver.child_priv = m_cpriv.group(1)
+ elif m_id:
+ driver.uclass_id = m_id.group(1)
+ elif m_of_match:
+ compat = m_of_match.group(2)
+ elif m_phase:
+ driver.phase = m_phase.group(1)
+ elif m_hdr:
+ driver.headers.append(m_hdr.group(1))
+ elif '};' in line:
+ is_root = driver.name == 'root_driver'
+ if driver.uclass_id and (compat or is_root):
+ if not is_root:
+ if compat not in of_match:
+ raise ValueError(
+ "%s: Unknown compatible var '%s' (found: %s)" %
+ (fname, compat, ','.join(of_match.keys())))
+ driver.compat = of_match[compat]
+
+ # This needs to be deterministic, since a driver may
+ # have multiple compatible strings pointing to it.
+ # We record the one earliest in the alphabet so it
+ # will produce the same result on all machines.
+ for compat_id in of_match[compat]:
+ old = self._compat_to_driver.get(compat_id)
+ if not old or driver.name < old.name:
+ self._compat_to_driver[compat_id] = driver
+ drivers[driver.name] = driver
+ else:
+ # The driver does not have a uclass or compat string.
+ # The first is required but the second is not, so just
+ # ignore this.
+ pass
+ driver = None
+ ids_name = None
+ compat = None
+ compat_dict = {}
+
+ elif ids_name:
+ compat_m = re_compat.search(line)
+ if compat_m:
+ compat_dict[compat_m.group(1)] = compat_m.group(3)
+ elif '};' in line:
+ of_match[ids_name] = compat_dict
+ ids_name = None
+ elif driver_match:
+ driver_name = driver_match.group(1)
+ driver = Driver(driver_name, fname)
+ else:
+ ids_m = re_ids.search(line)
+ m_alias = re_alias.match(line)
+ if ids_m:
+ ids_name = ids_m.group(1)
+ elif m_alias:
+ self._driver_aliases[m_alias[2]] = m_alias[1]
+
+ # Make the updates based on what we found
+ for driver in drivers.values():
+ if driver.name in self._drivers:
+ orig = self._drivers[driver.name]
+ if self._phase:
+ # If the original driver matches our phase, use it
+ if orig.phase == self._phase:
+ orig.dups.append(driver)
+ continue
+
+ # Otherwise use the new driver, which is assumed to match
+ else:
+ # We have no way of distinguishing them
+ driver.warn_dups = True
+ driver.dups.append(orig)
+ self._drivers[driver.name] = driver
+ self._of_match.update(of_match)
+
def scan_driver(self, fname):
"""Scan a driver file to build a list of driver names and aliases
- This procedure will populate self._drivers and self._driver_aliases
+ It updates the following members:
+ _drivers - updated with new Driver records for each driver found
+ in the file
+ _of_match - updated with each compatible string found in the file
+ _compat_to_driver - Maps compatible string to Driver
+ _driver_aliases - Maps alias names to driver name
Args
fname: Driver filename to scan
@@ -147,23 +599,35 @@ class Scanner:
print("Skipping file '%s' due to unicode error" % fname)
return
- # The following re will search for driver names declared as
- # U_BOOT_DRIVER(driver_name)
- drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
+ # If this file has any U_BOOT_DRIVER() declarations, process it to
+ # obtain driver information
+ if 'U_BOOT_DRIVER' in buff:
+ self._parse_driver(fname, buff)
+ if 'UCLASS_DRIVER' in buff:
+ self._parse_uclass_driver(fname, buff)
- for driver in drivers:
- self._drivers[driver] = Driver(driver)
+ def scan_header(self, fname):
+ """Scan a header file to build a list of struct definitions
- # The following re will search for driver aliases declared as
- # DM_DRIVER_ALIAS(alias, driver_name)
- driver_aliases = re.findall(
- r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- buff)
+ It updates the following members:
+ _structs - updated with new Struct records for each struct found
+ in the file
- for alias in driver_aliases: # pragma: no cover
- if len(alias) != 2:
- continue
- self._driver_aliases[alias[1]] = alias[0]
+ Args
+ fname: header filename to scan
+ """
+ with open(fname, encoding='utf-8') as inf:
+ try:
+ buff = inf.read()
+ except UnicodeDecodeError:
+ # This seems to happen on older Python versions
+ print("Skipping file '%s' due to unicode error" % fname)
+ return
+
+ # If this file has any U_BOOT_DRIVER() declarations, process it to
+ # obtain driver information
+ if 'struct' in buff:
+ self._parse_structs(fname, buff)
def scan_drivers(self):
"""Scan the driver folders to build a list of driver names and aliases
@@ -171,11 +635,17 @@ class Scanner:
This procedure will populate self._drivers and self._driver_aliases
"""
for (dirpath, _, filenames) in os.walk(self._basedir):
+ rel_path = dirpath[len(self._basedir):]
+ if rel_path.startswith('/'):
+ rel_path = rel_path[1:]
+ if rel_path.startswith('build') or rel_path.startswith('.git'):
+ continue
for fname in filenames:
- if not fname.endswith('.c'):
- continue
- self.scan_driver(dirpath + '/' + fname)
-
+ pathname = dirpath + '/' + fname
+ if fname.endswith('.c'):
+ self.scan_driver(pathname)
+ elif fname.endswith('.h'):
+ self.scan_header(pathname)
for fname in self._drivers_additional:
if not isinstance(fname, str) or len(fname) == 0:
continue
@@ -183,3 +653,84 @@ class Scanner:
self.scan_driver(fname)
else:
self.scan_driver(self._basedir + '/' + fname)
+
+ # Get the uclass for each driver
+ # TODO: Can we just get the uclass for the ones we use, e.g. in
+ # mark_used()?
+ for driver in self._drivers.values():
+ driver.uclass = self._uclass.get(driver.uclass_id)
+
+ def mark_used(self, nodes):
+ """Mark the drivers associated with a list of nodes as 'used'
+
+ This takes a list of nodes, finds the driver for each one and marks it
+ as used.
+
+ If two used drivers have the same name, issue a warning.
+
+ Args:
+ nodes (list of None): Nodes that are in use
+ """
+ # Figure out which drivers we actually use
+ for node in nodes:
+ struct_name, _ = self.get_normalized_compat_name(node)
+ driver = self._drivers.get(struct_name)
+ if driver:
+ driver.used = True
+ if driver.dups and driver.warn_dups:
+ print("Warning: Duplicate driver name '%s' (orig=%s, dups=%s)" %
+ (driver.name, driver.fname,
+ ', '.join([drv.fname for drv in driver.dups])))
+
+ def add_uclass_alias(self, name, num, node):
+ """Add an alias to a uclass
+
+ Args:
+ name: Name of uclass, e.g. 'i2c'
+ num: Alias number, e.g. 2 for alias 'i2c2'
+ node: Node the alias points to, or None if None
+
+ Returns:
+ True if the node was added
+ False if the node was not added (uclass of that name not found)
+ None if the node could not be added because it was None
+ """
+ for uclass in self._uclass.values():
+ if uclass.name == name:
+ if node is None:
+ return None
+ uclass.alias_num_to_node[int(num)] = node
+ uclass.alias_path_to_num[node.path] = int(num)
+ return True
+ return False
+
+ def assign_seq(self, node):
+ """Figure out the sequence number for a node
+
+ This looks in the node's uclass and assigns a sequence number if needed,
+ based on the aliases and other nodes in that uclass.
+
+ It updates the uclass alias_path_to_num and alias_num_to_node
+
+ Args:
+ node (Node): Node object to look up
+ """
+ if node.driver and node.seq == -1 and node.uclass:
+ uclass = node.uclass
+ num = uclass.alias_path_to_num.get(node.path)
+ if num is not None:
+ return num
+ else:
+ # Dynamically allocate the next available value after all
+ # existing ones
+ if uclass.alias_num_to_node:
+ start = max(uclass.alias_num_to_node.keys())
+ else:
+ start = -1
+ for seq in range(start + 1, 1000):
+ if seq not in uclass.alias_num_to_node:
+ break
+ uclass.alias_path_to_num[node.path] = seq
+ uclass.alias_num_to_node[seq] = node
+ return seq
+ return None
diff --git a/tools/dtoc/dtoc_test.dts b/tools/dtoc/test/dtoc_test.dts
index b225948..b225948 100644
--- a/tools/dtoc/dtoc_test.dts
+++ b/tools/dtoc/test/dtoc_test.dts
diff --git a/tools/dtoc/dtoc_test_add_prop.dts b/tools/dtoc/test/dtoc_test_add_prop.dts
index fa296e5..fa296e5 100644
--- a/tools/dtoc/dtoc_test_add_prop.dts
+++ b/tools/dtoc/test/dtoc_test_add_prop.dts
diff --git a/tools/dtoc/dtoc_test_addr32.dts b/tools/dtoc/test/dtoc_test_addr32.dts
index 2390454..2390454 100644
--- a/tools/dtoc/dtoc_test_addr32.dts
+++ b/tools/dtoc/test/dtoc_test_addr32.dts
diff --git a/tools/dtoc/dtoc_test_addr32_64.dts b/tools/dtoc/test/dtoc_test_addr32_64.dts
index 7599d5b..7599d5b 100644
--- a/tools/dtoc/dtoc_test_addr32_64.dts
+++ b/tools/dtoc/test/dtoc_test_addr32_64.dts
diff --git a/tools/dtoc/dtoc_test_addr64.dts b/tools/dtoc/test/dtoc_test_addr64.dts
index 263d251..263d251 100644
--- a/tools/dtoc/dtoc_test_addr64.dts
+++ b/tools/dtoc/test/dtoc_test_addr64.dts
diff --git a/tools/dtoc/dtoc_test_addr64_32.dts b/tools/dtoc/test/dtoc_test_addr64_32.dts
index 85e4f5f..85e4f5f 100644
--- a/tools/dtoc/dtoc_test_addr64_32.dts
+++ b/tools/dtoc/test/dtoc_test_addr64_32.dts
diff --git a/tools/dtoc/test/dtoc_test_alias_bad.dts b/tools/dtoc/test/dtoc_test_alias_bad.dts
new file mode 100644
index 0000000..d4f502a
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4- = &i2c;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/tools/dtoc/test/dtoc_test_alias_bad_path.dts b/tools/dtoc/test/dtoc_test_alias_bad_path.dts
new file mode 100644
index 0000000..0beca4f
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad_path.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4 = "/does/not/exist";
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/tools/dtoc/test/dtoc_test_alias_bad_uc.dts b/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
new file mode 100644
index 0000000..ae64f5b
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ other1 = &testfdt_1;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/tools/dtoc/dtoc_test_aliases.dts b/tools/dtoc/test/dtoc_test_aliases.dts
index ae33716..ae33716 100644
--- a/tools/dtoc/dtoc_test_aliases.dts
+++ b/tools/dtoc/test/dtoc_test_aliases.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg.dts b/tools/dtoc/test/dtoc_test_bad_reg.dts
index 1312acb..1312acb 100644
--- a/tools/dtoc/dtoc_test_bad_reg.dts
+++ b/tools/dtoc/test/dtoc_test_bad_reg.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg2.dts b/tools/dtoc/test/dtoc_test_bad_reg2.dts
index 3e9efa4..3e9efa4 100644
--- a/tools/dtoc/dtoc_test_bad_reg2.dts
+++ b/tools/dtoc/test/dtoc_test_bad_reg2.dts
diff --git a/tools/dtoc/dtoc_test_driver_alias.dts b/tools/dtoc/test/dtoc_test_driver_alias.dts
index da7973b..da7973b 100644
--- a/tools/dtoc/dtoc_test_driver_alias.dts
+++ b/tools/dtoc/test/dtoc_test_driver_alias.dts
diff --git a/tools/dtoc/dtoc_test_empty.dts b/tools/dtoc/test/dtoc_test_empty.dts
index b225948..b225948 100644
--- a/tools/dtoc/dtoc_test_empty.dts
+++ b/tools/dtoc/test/dtoc_test_empty.dts
diff --git a/tools/dtoc/test/dtoc_test_inst.dts b/tools/dtoc/test/dtoc_test_inst.dts
new file mode 100644
index 0000000..b8177fc
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_inst.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4 = &i2c;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/tools/dtoc/dtoc_test_invalid_driver.dts b/tools/dtoc/test/dtoc_test_invalid_driver.dts
index 914ac3e..914ac3e 100644
--- a/tools/dtoc/dtoc_test_invalid_driver.dts
+++ b/tools/dtoc/test/dtoc_test_invalid_driver.dts
diff --git a/tools/dtoc/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
index a71acff..a71acff 100644
--- a/tools/dtoc/dtoc_test_phandle.dts
+++ b/tools/dtoc/test/dtoc_test_phandle.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad.dts b/tools/dtoc/test/dtoc_test_phandle_bad.dts
index a3ddc59..a3ddc59 100644
--- a/tools/dtoc/dtoc_test_phandle_bad.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_bad.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad2.dts b/tools/dtoc/test/dtoc_test_phandle_bad2.dts
index fe25f56..fe25f56 100644
--- a/tools/dtoc/dtoc_test_phandle_bad2.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_bad2.dts
diff --git a/tools/dtoc/dtoc_test_phandle_cd_gpios.dts b/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
index 241743e..241743e 100644
--- a/tools/dtoc/dtoc_test_phandle_cd_gpios.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
diff --git a/tools/dtoc/dtoc_test_phandle_reorder.dts b/tools/dtoc/test/dtoc_test_phandle_reorder.dts
index aa71d56..aa71d56 100644
--- a/tools/dtoc/dtoc_test_phandle_reorder.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_reorder.dts
diff --git a/tools/dtoc/dtoc_test_phandle_single.dts b/tools/dtoc/test/dtoc_test_phandle_single.dts
index aacd0b1..aacd0b1 100644
--- a/tools/dtoc/dtoc_test_phandle_single.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_single.dts
diff --git a/tools/dtoc/test/dtoc_test_scan_drivers.cxx b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
new file mode 100644
index 0000000..f370b89
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
@@ -0,0 +1,5 @@
+/* Aliases must be in driver files */
+U_BOOT_DRIVER(sandbox_gpio) {
+};
+
+DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
diff --git a/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/test/dtoc_test_simple.dts
index 1c87b89..d8ab861 100644
--- a/tools/dtoc/dtoc_test_simple.dts
+++ b/tools/dtoc/test/dtoc_test_simple.dts
@@ -45,12 +45,12 @@
};
i2c@0 {
- compatible = "sandbox,i2c-test";
+ compatible = "sandbox,i2c";
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <0>;
pmic@9 {
- compatible = "sandbox,pmic-test";
+ compatible = "sandbox,pmic";
u-boot,dm-pre-reloc;
reg = <9>;
low-power;
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index d961d67..1912a87 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -10,16 +10,19 @@ tool.
"""
import collections
+import copy
import glob
import os
import struct
import unittest
+from dtb_platdata import Ftype
from dtb_platdata import get_value
from dtb_platdata import tab_to
from dtoc import dtb_platdata
from dtoc import fdt
from dtoc import fdt_util
+from dtoc import src_scan
from dtoc.src_scan import conv_name_to_c
from dtoc.src_scan import get_compat_name
from patman import test_util
@@ -38,13 +41,23 @@ HEADER = '''/*
#include <stdbool.h>
#include <linux/libfdt.h>'''
-C_HEADER = '''/*
+DECL_HEADER = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares externs for all device/uclass instances.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+C_HEADER_PRE = '''/*
* DO NOT MODIFY
*
* Declares the U_BOOT_DRIVER() records and platform data.
* This was generated by dtoc from a .dtb (device tree binary) file.
*/
+'''
+C_HEADER = C_HEADER_PRE + '''
/* Allow use of U_BOOT_DRVINFO() in this file */
#define DT_PLAT_C
@@ -53,6 +66,21 @@ C_HEADER = '''/*
#include <dt-structs.h>
'''
+UCLASS_HEADER_COMMON = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the uclass instances (struct uclass).
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+UCLASS_HEADER = UCLASS_HEADER_COMMON + '''
+/* This file is not used: --instantiate was not enabled */
+'''
+
+# Scanner saved from a previous run of the tests (to speed things up)
+saved_scan = None
+
# This is a test so is allowed to access private things in the module it is
# testing
# pylint: disable=W0212
@@ -67,10 +95,23 @@ def get_dtb_file(dts_fname, capture_stderr=False):
Returns:
str: Filename of compiled file in output directory
"""
- return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, dts_fname),
+ return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, 'test', dts_fname),
capture_stderr=capture_stderr)
+def setup():
+ global saved_scan
+
+ # Disable warnings so that calls to get_normalized_compat_name() will not
+ # output things.
+ saved_scan = src_scan.Scanner(None, True, False)
+ saved_scan.scan_drivers()
+
+def copy_scan():
+ """Get a copy of saved_scan so that each test can start clean"""
+ return copy.deepcopy(saved_scan)
+
+
class TestDtoc(unittest.TestCase):
"""Tests for dtoc"""
@classmethod
@@ -112,15 +153,22 @@ class TestDtoc(unittest.TestCase):
self.assertEqual(expected, actual)
@staticmethod
- def run_test(args, dtb_file, output):
+ def run_test(args, dtb_file, output, instantiate=False):
"""Run a test using dtoc
Args:
args (list of str): List of arguments for dtoc
dtb_file (str): Filename of .dtb file
output (str): Filename of output file
+
+ Returns:
+ DtbPlatdata object
"""
- dtb_platdata.run_steps(args, dtb_file, False, output, [], True)
+ # Make a copy of the 'scan' object, since it includes uclasses and
+ # drivers, which get updated during execution.
+ return dtb_platdata.run_steps(
+ args, dtb_file, False, output, [], None, instantiate,
+ warning_disabled=True, scan=copy_scan())
def test_name(self):
"""Test conversion of device tree names to C identifiers"""
@@ -175,7 +223,10 @@ class TestDtoc(unittest.TestCase):
"""Test output from a device tree file with no nodes"""
dtb_file = get_dtb_file('dtoc_test_empty.dts')
output = tools.GetOutputFilename('output')
- self.run_test(['struct'], dtb_file, output)
+
+ # Run this one without saved_scan to complete test coverage
+ dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], None,
+ False)
with open(output) as infile:
lines = infile.read().splitlines()
self.assertEqual(HEADER.splitlines(), lines)
@@ -185,10 +236,62 @@ class TestDtoc(unittest.TestCase):
lines = infile.read().splitlines()
self.assertEqual(C_HEADER.splitlines() + [''], lines)
+ decl_text = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+extern U_BOOT_DRIVER(sandbox_i2c);
+extern U_BOOT_DRIVER(sandbox_pmic);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+extern UCLASS_DRIVER(i2c);
+extern UCLASS_DRIVER(misc);
+extern UCLASS_DRIVER(pmic);
+'''
+ decl_text_inst = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+extern U_BOOT_DRIVER(sandbox_i2c);
+extern U_BOOT_DRIVER(root_driver);
+extern U_BOOT_DRIVER(denx_u_boot_test_bus);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
+extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
+
+/* device declarations - these allow DM_DEVICE_REF() to be used */
+extern DM_DEVICE_INST(i2c);
+extern DM_DEVICE_INST(root);
+extern DM_DEVICE_INST(some_bus);
+extern DM_DEVICE_INST(spl_test);
+extern DM_DEVICE_INST(spl_test3);
+extern DM_DEVICE_INST(test);
+extern DM_DEVICE_INST(test0);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+extern UCLASS_DRIVER(i2c);
+extern UCLASS_DRIVER(misc);
+extern UCLASS_DRIVER(root);
+extern UCLASS_DRIVER(testbus);
+extern UCLASS_DRIVER(testfdt);
+
+/* uclass declarations - needed for DM_UCLASS_REF() */
+extern DM_UCLASS_INST(i2c);
+extern DM_UCLASS_INST(misc);
+extern DM_UCLASS_INST(root);
+extern DM_UCLASS_INST(testbus);
+extern DM_UCLASS_INST(testfdt);
+'''
struct_text = HEADER + '''
-struct dtd_sandbox_i2c_test {
+struct dtd_sandbox_i2c {
};
-struct dtd_sandbox_pmic_test {
+struct dtd_sandbox_pmic {
\tbool\t\tlow_power;
\tfdt64_t\t\treg[2];
};
@@ -205,31 +308,52 @@ struct dtd_sandbox_spl_test {
\tconst char *\tstringval;
};
'''
-
platdata_text = C_HEADER + '''
-/* Node /i2c@0 index 0 */
-static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: i2c_at_0 sandbox_i2c
+ * 1: pmic_at_9 sandbox_pmic
+ * 2: spl_test sandbox_spl_test
+ * 3: spl_test2 sandbox_spl_test
+ * 4: spl_test3 sandbox_spl_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /i2c@0 index 0
+ * driver sandbox_i2c parent None
+ */
+static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
};
U_BOOT_DRVINFO(i2c_at_0) = {
-\t.name\t\t= "sandbox_i2c_test",
-\t.plat\t= &dtv_i2c_at_0,
+\t.name\t\t= "sandbox_i2c",
+\t.plat\t\t= &dtv_i2c_at_0,
\t.plat_size\t= sizeof(dtv_i2c_at_0),
\t.parent_idx\t= -1,
};
-/* Node /i2c@0/pmic@9 index 1 */
-static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
+/*
+ * Node /i2c@0/pmic@9 index 1
+ * driver sandbox_pmic parent sandbox_i2c
+ */
+static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
\t.low_power\t\t= true,
\t.reg\t\t\t= {0x9, 0x0},
};
U_BOOT_DRVINFO(pmic_at_9) = {
-\t.name\t\t= "sandbox_pmic_test",
-\t.plat\t= &dtv_pmic_at_9,
+\t.name\t\t= "sandbox_pmic",
+\t.plat\t\t= &dtv_pmic_at_9,
\t.plat_size\t= sizeof(dtv_pmic_at_9),
\t.parent_idx\t= 0,
};
-/* Node /spl-test index 2 */
+/*
+ * Node /spl-test index 2
+ * driver sandbox_spl_test parent None
+ */
static struct dtd_sandbox_spl_test dtv_spl_test = {
\t.boolval\t\t= true,
\t.bytearray\t\t= {0x6, 0x0, 0x0},
@@ -244,12 +368,15 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
};
U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
\t.parent_idx\t= -1,
};
-/* Node /spl-test2 index 3 */
+/*
+ * Node /spl-test2 index 3
+ * driver sandbox_spl_test parent None
+ */
static struct dtd_sandbox_spl_test dtv_spl_test2 = {
\t.acpi_name\t\t= "\\\\_SB.GPO0",
\t.bytearray\t\t= {0x1, 0x23, 0x34},
@@ -263,12 +390,15 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
};
U_BOOT_DRVINFO(spl_test2) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test2,
+\t.plat\t\t= &dtv_spl_test2,
\t.plat_size\t= sizeof(dtv_spl_test2),
\t.parent_idx\t= -1,
};
-/* Node /spl-test3 index 4 */
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent None
+ */
static struct dtd_sandbox_spl_test dtv_spl_test3 = {
\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
\t\t0x0},
@@ -276,12 +406,406 @@ static struct dtd_sandbox_spl_test dtv_spl_test3 = {
};
U_BOOT_DRVINFO(spl_test3) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test3,
+\t.plat\t\t= &dtv_spl_test3,
\t.plat_size\t= sizeof(dtv_spl_test3),
\t.parent_idx\t= -1,
};
'''
+ uclass_text = UCLASS_HEADER
+ uclass_text_inst = '''
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * uclass declarations, ordered by 'struct uclass' linker_list idx:
+ * 0: i2c
+ * 1: misc
+ * 2: root
+ * 3: testbus
+ * 4: testfdt
+ *
+ * Sequence numbers allocated in each uclass:
+ * i2c: UCLASS_I2C
+ * 4: /i2c
+ * misc: UCLASS_MISC
+ * 0: /spl-test
+ * 1: /spl-test3
+ * root: UCLASS_ROOT
+ * 0: /
+ * testbus: UCLASS_TEST_BUS
+ * 2: /some-bus
+ * testfdt: UCLASS_TEST_FDT
+ * 1: /some-bus/test
+ * 2: /some-bus/test0
+ */
+
+struct list_head uclass_head = {
+ .prev = &DM_UCLASS_REF(testfdt)->sibling_node,
+ .next = &DM_UCLASS_REF(i2c)->sibling_node,
+};
+
+DM_UCLASS_INST(i2c) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(i2c),
+ .sibling_node = {
+ .prev = &uclass_head,
+ .next = &DM_UCLASS_REF(misc)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(i2c)->uclass_node,
+ .next = &DM_DEVICE_REF(i2c)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(misc) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(misc),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(i2c)->sibling_node,
+ .next = &DM_UCLASS_REF(root)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(spl_test3)->uclass_node,
+ .next = &DM_DEVICE_REF(spl_test)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(root) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(root),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(misc)->sibling_node,
+ .next = &DM_UCLASS_REF(testbus)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(root)->uclass_node,
+ .next = &DM_DEVICE_REF(root)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(testbus) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(testbus),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(root)->sibling_node,
+ .next = &DM_UCLASS_REF(testfdt)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(some_bus)->uclass_node,
+ .next = &DM_DEVICE_REF(some_bus)->uclass_node,
+ },
+};
+
+#include <dm/test.h>
+u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
+ __attribute__ ((section (".priv_data")));
+DM_UCLASS_INST(testfdt) = {
+ .priv_ = _testfdt_priv_,
+ .uc_drv = DM_UCLASS_DRIVER_REF(testfdt),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(testbus)->sibling_node,
+ .next = &uclass_head,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(test0)->uclass_node,
+ .next = &DM_DEVICE_REF(test)->uclass_node,
+ },
+};
+
+'''
+ device_text = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+/* This file is not used: --instantiate was not enabled */
+'''
+ device_text_inst = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * udevice declarations, ordered by 'struct udevice' linker_list position:
+ *
+ * idx udevice driver
+ * --- -------------------- --------------------
+ * 0: i2c sandbox_i2c
+ * 1: root root_driver
+ * 2: some_bus denx_u_boot_test_bus
+ * 3: spl_test sandbox_spl_test
+ * 4: spl_test3 sandbox_spl_test
+ * 5: test denx_u_boot_fdt_test
+ * 6: test0 denx_u_boot_fdt_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /i2c index 0
+ * driver sandbox_i2c parent root_driver
+*/
+static struct dtd_sandbox_i2c dtv_i2c = {
+\t.intval\t\t\t= 0x3,
+};
+
+#include <asm/i2c.h>
+u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <i2c.h>
+u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(i2c) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_i2c),
+\t.name\t\t= "sandbox_i2c",
+\t.plat_\t\t= &dtv_i2c,
+\t.priv_\t\t= _sandbox_i2c_priv_i2c,
+\t.uclass\t\t= DM_UCLASS_REF(i2c),
+\t.uclass_priv_ = _sandbox_i2c_uc_priv_i2c,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(i2c)->dev_head,
+\t\t.next = &DM_UCLASS_REF(i2c)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->child_head,
+\t\t.next = &DM_DEVICE_REF(i2c)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(root)->child_head,
+\t\t.next = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t},
+\t.seq_ = 4,
+};
+
+/*
+ * Node / index 1
+ * driver root_driver parent None
+*/
+static struct dtd_root_driver dtv_root = {
+};
+
+DM_DEVICE_INST(root) = {
+\t.driver\t\t= DM_DRIVER_REF(root_driver),
+\t.name\t\t= "root_driver",
+\t.plat_\t\t= &dtv_root,
+\t.uclass\t\t= DM_UCLASS_REF(root),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(root)->dev_head,
+\t\t.next = &DM_UCLASS_REF(root)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(i2c)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /some-bus index 2
+ * driver denx_u_boot_test_bus parent root_driver
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_test_bus_plat_some_bus = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x4,
+\t\t.ping_expect\t\t= 0x4,
+\t\t.reg\t\t\t= {0x3, 0x1},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <test.h>
+
+DM_DEVICE_INST(some_bus) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_test_bus),
+\t.name\t\t= "denx_u_boot_test_bus",
+\t.plat_\t\t= &_denx_u_boot_test_bus_plat_some_bus,
+\t.uclass_plat_\t= _denx_u_boot_test_bus_ucplat_some_bus,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
+\t.uclass\t\t= DM_UCLASS_REF(testbus),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
+\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(test)->sibling_node,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t},
+\t.seq_ = 2,
+};
+
+/*
+ * Node /spl-test index 3
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test = {
+\t.boolval\t\t= true,
+\t.intval\t\t\t= 0x1,
+};
+
+DM_DEVICE_INST(spl_test) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(misc)->dev_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test3 = {
+\t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
+\t.stringarray\t\t= "one",
+};
+
+DM_DEVICE_INST(spl_test3) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test3,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(misc)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(root)->child_head,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test index 5
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x5,
+\t\t.ping_expect\t\t= 0x5,
+\t\t.reg\t\t\t= {0x5, 0x0},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testfdt)->dev_head,
+\t\t.next = &DM_DEVICE_REF(test0)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->child_head,
+\t\t.next = &DM_DEVICE_REF(test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->sibling_node,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test0 index 6
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test0 = {
+\t.dtplat = {
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test0[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test0) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test0,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test0,
+\t.driver_data\t= DM_TEST_TYPE_SECOND,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test0,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test0,
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(testfdt)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(some_bus)->child_head,
+\t},
+\t.seq_ = 2,
+};
+
+'''
def test_simple(self):
"""Test output from some simple nodes with various types of data"""
@@ -299,10 +823,18 @@ U_BOOT_DRVINFO(spl_test3) = {
self._check_strings(self.platdata_text, data)
+ self.run_test(['decl'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.decl_text, data)
+
# Try the 'all' command
self.run_test(['all'], dtb_file, output)
data = tools.ReadFile(output, binary=False)
- self._check_strings(self.platdata_text + self.struct_text, data)
+ self._check_strings(
+ self.decl_text + self.device_text + self.platdata_text +
+ self.struct_text + self.uclass_text, data)
def test_driver_alias(self):
"""Test output from a device tree file with a driver alias"""
@@ -323,7 +855,19 @@ struct dtd_sandbox_gpio {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
-/* Node /gpios@0 index 0 */
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: gpios_at_0 sandbox_gpio
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /gpios@0 index 0
+ * driver sandbox_gpio parent None
+ */
static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
\t.gpio_bank_name\t\t= "a",
\t.gpio_controller\t= true,
@@ -331,7 +875,7 @@ static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
};
U_BOOT_DRVINFO(gpios_at_0) = {
\t.name\t\t= "sandbox_gpio",
-\t.plat\t= &dtv_gpios_at_0,
+\t.plat\t\t= &dtv_gpios_at_0,
\t.plat_size\t= sizeof(dtv_gpios_at_0),
\t.parent_idx\t= -1,
};
@@ -343,7 +887,9 @@ U_BOOT_DRVINFO(gpios_at_0) = {
dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
output = tools.GetOutputFilename('output')
with test_util.capture_sys_output() as _:
- dtb_platdata.run_steps(['struct'], dtb_file, False, output, [])
+ dtb_platdata.run_steps(
+ ['struct'], dtb_file, False, output, [], None, False,
+ scan=copy_scan())
with open(output) as infile:
data = infile.read()
self._check_strings(HEADER + '''
@@ -352,16 +898,27 @@ struct dtd_invalid {
''', data)
with test_util.capture_sys_output() as _:
- dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [])
+ dtb_platdata.run_steps(
+ ['platdata'], dtb_file, False, output, [], None, False,
+ scan=copy_scan())
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: spl_test invalid
+ * --- -------------------- --------------------
+ */
+
/* Node /spl-test index 0 */
static struct dtd_invalid dtv_spl_test = {
};
U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "invalid",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
\t.parent_idx\t= -1,
};
@@ -388,13 +945,26 @@ struct dtd_target {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle2_target target
+ * 1: phandle3_target target
+ * 2: phandle_source source
+ * 3: phandle_source2 source
+ * 4: phandle_target target
+ * --- -------------------- --------------------
+ */
+
/* Node /phandle2-target index 0 */
static struct dtd_target dtv_phandle2_target = {
\t.intval\t\t\t= 0x1,
};
U_BOOT_DRVINFO(phandle2_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
\t.parent_idx\t= -1,
};
@@ -405,7 +975,7 @@ static struct dtd_target dtv_phandle3_target = {
};
U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
@@ -420,7 +990,7 @@ static struct dtd_source dtv_phandle_source = {
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
\t.parent_idx\t= -1,
};
@@ -432,7 +1002,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -443,7 +1013,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -474,6 +1044,16 @@ struct dtd_target {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle_source2 source
+ * 1: phandle_target target
+ * --- -------------------- --------------------
+ */
+
/* Node /phandle-source2 index 0 */
static struct dtd_source dtv_phandle_source2 = {
\t.clocks\t\t\t= {
@@ -481,7 +1061,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -491,7 +1071,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -502,17 +1082,32 @@ U_BOOT_DRVINFO(phandle_target) = {
"""Test that phandle targets are generated when unsing cd-gpios"""
dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
output = tools.GetOutputFilename('output')
- dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True)
+ dtb_platdata.run_steps(
+ ['platdata'], dtb_file, False, output, [], None, False,
+ warning_disabled=True, scan=copy_scan())
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle2_target target
+ * 1: phandle3_target target
+ * 2: phandle_source source
+ * 3: phandle_source2 source
+ * 4: phandle_target target
+ * --- -------------------- --------------------
+ */
+
/* Node /phandle2-target index 0 */
static struct dtd_target dtv_phandle2_target = {
\t.intval\t\t\t= 0x1,
};
U_BOOT_DRVINFO(phandle2_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
\t.parent_idx\t= -1,
};
@@ -523,7 +1118,7 @@ static struct dtd_target dtv_phandle3_target = {
};
U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
@@ -538,7 +1133,7 @@ static struct dtd_source dtv_phandle_source = {
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
\t.parent_idx\t= -1,
};
@@ -550,7 +1145,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -561,7 +1156,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -611,13 +1206,24 @@ struct dtd_test3 {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x5678},
};
U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -628,7 +1234,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -639,7 +1245,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -666,13 +1272,23 @@ struct dtd_test2 {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * --- -------------------- --------------------
+ */
+
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x5678},
};
U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -683,7 +1299,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -713,13 +1329,24 @@ struct dtd_test3 {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x123400000000, 0x5678},
};
U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -730,7 +1357,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -741,7 +1368,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -771,13 +1398,24 @@ struct dtd_test3 {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x567800000000},
};
U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -788,7 +1426,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -799,7 +1437,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -845,24 +1483,40 @@ struct dtd_sandbox_spl_test {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
-/* Node /spl-test index 0 */
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: spl_test sandbox_spl_test
+ * 1: spl_test2 sandbox_spl_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /spl-test index 0
+ * driver sandbox_spl_test parent None
+ */
static struct dtd_sandbox_spl_test dtv_spl_test = {
\t.intval\t\t\t= 0x1,
};
U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
\t.parent_idx\t= -1,
};
-/* Node /spl-test2 index 1 */
+/*
+ * Node /spl-test2 index 1
+ * driver sandbox_spl_test parent None
+ */
static struct dtd_sandbox_spl_test dtv_spl_test2 = {
\t.intarray\t\t= 0x5,
};
U_BOOT_DRVINFO(spl_test2) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test2,
+\t.plat\t\t= &dtv_spl_test2,
\t.plat_size\t= sizeof(dtv_spl_test2),
\t.parent_idx\t= -1,
};
@@ -882,7 +1536,9 @@ U_BOOT_DRVINFO(spl_test2) = {
output = tools.GetOutputFilename('output')
self.run_test(['all'], dtb_file, output)
data = tools.ReadFile(output, binary=False)
- self._check_strings(self.platdata_text + self.struct_text, data)
+ self._check_strings(
+ self.decl_text + self.device_text + self.platdata_text +
+ self.struct_text + self.uclass_text, data)
def test_no_command(self):
"""Test running dtoc without a command"""
@@ -897,13 +1553,16 @@ U_BOOT_DRVINFO(spl_test2) = {
output = tools.GetOutputFilename('output')
with self.assertRaises(ValueError) as exc:
self.run_test(['invalid-cmd'], dtb_file, output)
- self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)",
- str(exc.exception))
+ self.assertIn(
+ "Unknown command 'invalid-cmd': (use: decl, device, platdata, struct, uclass)",
+ str(exc.exception))
def test_output_conflict(self):
"""Test a conflict between and output dirs and output file"""
with self.assertRaises(ValueError) as exc:
- dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True)
+ dtb_platdata.run_steps(
+ ['all'], None, False, 'out', ['cdir'], None, False,
+ warning_disabled=True, scan=copy_scan())
self.assertIn("Must specify either output or output_dirs, not both",
str(exc.exception))
@@ -919,11 +1578,249 @@ U_BOOT_DRVINFO(spl_test2) = {
fnames = glob.glob(outdir + '/*')
self.assertEqual(2, len(fnames))
- dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True)
+ dtb_platdata.run_steps(
+ ['all'], dtb_file, False, None, [outdir], None, False,
+ warning_disabled=True, scan=copy_scan())
fnames = glob.glob(outdir + '/*')
- self.assertEqual(4, len(fnames))
+ self.assertEqual(7, len(fnames))
leafs = set(os.path.basename(fname) for fname in fnames)
self.assertEqual(
- {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb'},
+ {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
+ 'dt-uclass.c', 'dt-decl.h', 'dt-device.c'},
leafs)
+
+ def setup_process_test(self):
+ """Set up a test of process_nodes()
+
+ This uses saved_scan but returns a deep copy of it, so it is safe to
+ modify it in these tests
+
+ Returns:
+ tuple:
+ DtbPlatdata: object to test
+ Scanner: scanner to use
+ """
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Take a copy before messing with it
+ scan = copy_scan()
+ plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+ plat.scan_dtb()
+ plat.scan_tree(False)
+ plat.prepare_nodes()
+ return plat, scan
+
+ def test_process_nodes(self):
+ """Test processing nodes to add various info"""
+ plat, scan = self.setup_process_test()
+ plat.process_nodes(True)
+
+ i2c_node = plat._fdt.GetNode('/i2c@0')
+ pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
+ pmic = scan._drivers['sandbox_pmic']
+ i2c = scan._drivers['sandbox_i2c']
+ self.assertEqual('DM_DEVICE_REF(pmic_at_9)', pmic_node.dev_ref)
+ self.assertEqual(pmic, pmic_node.driver)
+ self.assertEqual(i2c_node, pmic_node.parent)
+ self.assertEqual(i2c, pmic_node.parent_driver)
+
+ # The pmic is the only child
+ self.assertEqual(pmic_node.parent_seq, 0)
+ self.assertEqual([pmic_node], i2c_node.child_devs)
+
+ # Start and end of the list should be the child_head
+ ref = '&DM_DEVICE_REF(i2c_at_0)->child_head'
+ self.assertEqual(
+ {-1: ref, 0: '&DM_DEVICE_REF(pmic_at_9)->sibling_node', 1: ref},
+ i2c_node.child_refs)
+
+ def test_process_nodes_bad_parent(self):
+ # Pretend that i2c has a parent (the pmic) and delete that driver
+ plat, scan = self.setup_process_test()
+
+ i2c_node = plat._fdt.GetNode('/i2c@0')
+ pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
+ del scan._drivers['sandbox_pmic']
+ i2c_node.parent = pmic_node
+
+ # Process twice, the second time to generate an exception
+ plat.process_nodes(False)
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn(
+ "Cannot parse/find parent driver 'sandbox_pmic' for 'sandbox_i2c",
+ str(exc.exception))
+
+ def test_process_nodes_bad_node(self):
+ plat, scan = self.setup_process_test()
+
+ # Now remove the pmic driver
+ del scan._drivers['sandbox_pmic']
+
+ # Process twice, the second time to generate an exception
+ plat.process_nodes(False)
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
+ str(exc.exception))
+
+ def test_process_nodes_bad_uclass(self):
+ plat, scan = self.setup_process_test()
+
+ self.assertIn('UCLASS_I2C', scan._uclass)
+ del scan._uclass['UCLASS_I2C']
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn("Cannot parse/find uclass 'UCLASS_I2C' for driver 'sandbox_i2c'",
+ str(exc.exception))
+
+ def test_process_nodes_used(self):
+ """Test processing nodes to add various info"""
+ plat, scan = self.setup_process_test()
+ plat.process_nodes(True)
+
+ pmic = scan._drivers['sandbox_pmic']
+ self.assertTrue(pmic.used)
+
+ gpio = scan._drivers['sandbox_gpio']
+ self.assertFalse(gpio.used)
+
+ def test_alias_read(self):
+ """Test obtaining aliases"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+ plat = self.run_test(['struct'], dtb_file, output)
+
+ scan = plat._scan
+ testfdt_node = plat._fdt.GetNode('/some-bus/test')
+ test0_node = plat._fdt.GetNode('/some-bus/test0')
+ self.assertIn('UCLASS_TEST_FDT', scan._uclass)
+ uc = scan._uclass['UCLASS_TEST_FDT']
+ self.assertEqual({1: testfdt_node, 2: test0_node},
+ uc.alias_num_to_node)
+ self.assertEqual({'/some-bus/test': 1, '/some-bus/test0': 2},
+ uc.alias_path_to_num)
+
+ # Try adding an alias that doesn't exist
+ self.assertFalse(scan.add_uclass_alias('fred', 3, None))
+
+ # Try adding an alias for a missing node
+ self.assertIsNone(scan.add_uclass_alias('testfdt', 3, None))
+
+ def test_alias_read_bad(self):
+ """Test invalid alias property name"""
+ dtb_file = get_dtb_file('dtoc_test_alias_bad.dts')
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Cannot decode alias 'i2c4-'", str(exc.exception))
+
+ def test_alias_read_bad_path(self):
+ """Test alias pointing to a non-existent node"""
+ # This line may produce a warning, so capture it:
+ # Warning (alias_paths): /aliases:i2c4: aliases property is not a valid
+ # node (/does/not/exist)
+ dtb_file = get_dtb_file('dtoc_test_alias_bad_path.dts', True)
+
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Alias 'i2c4' path '/does/not/exist' not found",
+ str(exc.exception))
+
+ def test_alias_read_bad_uclass(self):
+ """Test alias for a uclass that doesn't exist"""
+ dtb_file = get_dtb_file('dtoc_test_alias_bad_uc.dts')
+ output = tools.GetOutputFilename('output')
+ with test_util.capture_sys_output() as (stdout, _):
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertEqual("Could not find uclass for alias 'other1'",
+ stdout.getvalue().strip())
+
+ def test_sequence(self):
+ """Test assignment of sequence numnbers"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+ plat = self.run_test(['struct'], dtb_file, output)
+
+ scan = plat._scan
+ testfdt = plat._fdt.GetNode('/some-bus/test')
+ self.assertEqual(1, testfdt.seq)
+ i2c = plat._fdt.GetNode('/i2c')
+
+ # For now this uclass is not compiled in, so no sequence is assigned
+ self.assertEqual(4, i2c.seq)
+ spl = plat._fdt.GetNode('/spl-test')
+ self.assertEqual(0, spl.seq)
+
+ def test_process_root(self):
+ """Test assignment of sequence numnbers"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Take a copy before messing with it
+ scan = copy_scan()
+ plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+ plat.scan_dtb()
+ root = plat._fdt.GetRoot()
+
+ plat.scan_tree(False)
+ self.assertNotIn(root, plat._valid_nodes)
+
+ plat.scan_tree(True)
+ self.assertIn(root, plat._valid_nodes)
+ self.assertEqual('root_driver',
+ scan.get_normalized_compat_name(root)[0])
+
+ def test_simple_inst(self):
+ """Test output from some simple nodes with instantiate enabled"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+
+ self.run_test(['decl'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.decl_text_inst, data)
+
+ self.run_test(['platdata'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(C_HEADER_PRE + '''
+/* This file is not used: --instantiate was enabled */
+''', data)
+
+ self.run_test(['uclass'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
+
+ self.run_test(['device'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.device_text_inst, data)
+
+ def test_inst_no_hdr(self):
+ """Test dealing with a struct tsssshat has no header"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Run it once to set everything up
+ plat = self.run_test(['decl'], dtb_file, output, True)
+ scan = plat._scan
+
+ # Restart the output file and delete any record of the uclass' struct
+ plat.setup_output(Ftype.SOURCE, output)
+ del scan._structs['dm_test_uc_priv']
+
+ # Now generate the uclasses, which should provide a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ plat.generate_uclasses()
+ self.assertEqual(
+ 'Warning: Cannot find header file for struct dm_test_uc_priv',
+ stdout.getvalue().strip())
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index e8fbbd5..1c3a8a2 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -48,6 +48,17 @@ def _GetPropertyValue(dtb, node, prop_name):
data = dtb.GetContents()[offset:offset + len(prop.value)]
return prop, [chr(x) for x in data]
+def find_dtb_file(dts_fname):
+ """Locate a test file in the test/ directory
+
+ Args:
+ dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
+
+ Returns:
+ str: Path to the test filename
+ """
+ return os.path.join('tools/dtoc/test', dts_fname)
+
class TestFdt(unittest.TestCase):
"""Tests for the Fdt module
@@ -64,7 +75,7 @@ class TestFdt(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
def testFdt(self):
"""Test that we can open an Fdt"""
@@ -141,7 +152,7 @@ class TestNode(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
def testOffset(self):
@@ -203,7 +214,7 @@ class TestNode(unittest.TestCase):
def testLookupPhandle(self):
"""Test looking up a single phandle"""
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
prop = node.props['clocks']
target = dtb.GetNode('/phandle-target')
@@ -222,7 +233,7 @@ class TestProp(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
self.fdt = self.dtb.GetFdtObj()
@@ -230,7 +241,7 @@ class TestProp(unittest.TestCase):
self.assertEqual(None, self.dtb.GetNode('missing'))
def testPhandle(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
prop = node.props['clocks']
self.assertTrue(fdt32_to_cpu(prop.value) > 0)
@@ -488,7 +499,7 @@ class TestFdtUtil(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
def testGetInt(self):
@@ -531,7 +542,7 @@ class TestFdtUtil(unittest.TestCase):
str(e.exception))
def testGetPhandleList(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
node = dtb.GetNode('/phandle-source')
@@ -551,7 +562,7 @@ class TestFdtUtil(unittest.TestCase):
self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
- dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
+ dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
node1 = dtb2.GetNode('/test1')
val = node1.props['reg'].value
self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
@@ -565,7 +576,7 @@ class TestFdtUtil(unittest.TestCase):
def testEnsureCompiled(self):
"""Test a degenerate case of this function (file already compiled)"""
- dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
def testEnsureCompiledTmpdir(self):
@@ -574,7 +585,7 @@ class TestFdtUtil(unittest.TestCase):
old_outdir = tools.outdir
tools.outdir= None
tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
- dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
tmpdir)
self.assertEqual(tmpdir, os.path.dirname(dtb))
shutil.rmtree(tmpdir)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 7d68653..0af86dc 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -7,6 +7,7 @@
This includes unit tests for scanning of the source code
"""
+import copy
import os
import shutil
import tempfile
@@ -17,6 +18,20 @@ from dtoc import src_scan
from patman import test_util
from patman import tools
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
+
+class FakeNode:
+ """Fake Node object for testing"""
+ def __init__(self):
+ self.name = None
+ self.props = {}
+
+class FakeProp:
+ """Fake Prop object for testing"""
+ def __init__(self):
+ self.name = None
+ self.value = None
+
# This is a test so is allowed to access private things in the module it is
# testing
# pylint: disable=W0212
@@ -44,7 +59,8 @@ class TestSrcScan(unittest.TestCase):
def test_additional(self):
"""Test with additional drivers to scan"""
scan = src_scan.Scanner(
- None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
+ None, True,
+ [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
scan.scan_drivers()
self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
self.assertEqual('sandbox_gpio',
@@ -69,10 +85,22 @@ class TestSrcScan(unittest.TestCase):
def test_driver(self):
"""Test the Driver class"""
- drv1 = src_scan.Driver('fred')
- drv2 = src_scan.Driver('mary')
- drv3 = src_scan.Driver('fred')
- self.assertEqual("Driver(name='fred')", str(drv1))
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv1 = src_scan.Driver('fred', 'fred.c')
+ drv2 = src_scan.Driver('mary', 'mary.c')
+ drv3 = src_scan.Driver('fred', 'fred.c')
+ drv1.uclass_id = i2c
+ drv1.compat = compat
+ drv2.uclass_id = i2c
+ drv2.compat = compat
+ drv3.uclass_id = i2c
+ drv3.compat = compat
+ self.assertEqual(
+ "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
+ "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
+ "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
self.assertEqual(drv1, drv3)
self.assertNotEqual(drv1, drv2)
self.assertNotEqual(drv2, drv3)
@@ -91,7 +119,9 @@ class TestSrcScan(unittest.TestCase):
fname_list = []
add_file('fname.c')
+ add_file('.git/ignoreme.c')
add_file('dir/fname2.c')
+ add_file('build-sandbox/ignoreme2.c')
# Mock out scan_driver and check that it is called with the
# expected files
@@ -101,7 +131,362 @@ class TestSrcScan(unittest.TestCase):
self.assertEqual(2, len(mocked.mock_calls))
self.assertEqual(mock.call(fname_list[0]),
mocked.mock_calls[0])
- self.assertEqual(mock.call(fname_list[1]),
+ # .git file should be ignored
+ self.assertEqual(mock.call(fname_list[2]),
mocked.mock_calls[1])
finally:
shutil.rmtree(indir)
+
+ def test_scan(self):
+ """Test scanning of a driver"""
+ fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
+ buff = tools.ReadFile(fname, False)
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver(fname, buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114',
+ 'nvidia,tegra20-i2c': 'TYPE_STD',
+ 'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
+ self.assertEqual('i2c_bus', drv.priv)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_normalized_name(self):
+ """Test operation of get_normalized_compat_name()"""
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'rockchip,rk3288-grf'
+ node = FakeNode()
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ scan = src_scan.Scanner(None, False, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+ self.assertEqual(
+ 'WARNING: the driver rockchip_rk3288_grf was not found in the driver list',
+ stdout.getvalue().strip())
+
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv = src_scan.Driver('fred', 'fred.c')
+ drv.uclass_id = i2c
+ drv.compat = compat
+ scan._drivers['rockchip_rk3288_grf'] = drv
+
+ scan._driver_aliases['rockchip_rk3288_srf'] = 'rockchip_rk3288_grf'
+
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+
+ prop.value = 'rockchip,rk3288-srf'
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual(['rockchip_rk3288_srf'], aliases)
+
+ def test_scan_errors(self):
+ """Test detection of scanning errors"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids2[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = tegra_i2c_ids,
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_driver('file.c', buff)
+ self.assertIn(
+ "file.c: Unknown compatible var 'tegra_i2c_ids' (found: tegra_i2c_ids2)",
+ str(exc.exception))
+
+ def test_of_match(self):
+ """Test detection of of_match_ptr() member"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = of_match_ptr(tegra_i2c_ids),
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('', drv.phase)
+ self.assertEqual([], drv.headers)
+
+ def test_priv(self):
+ """Test collection of struct info from drivers"""
+ buff = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(testing) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ .priv_auto = sizeof(struct some_priv),
+ .plat_auto = sizeof(struct some_plat),
+ .per_child_auto = sizeof(struct some_cpriv),
+ .per_child_plat_auto = sizeof(struct some_cplat),
+ DM_PHASE(tpl)
+ DM_HEADER(<i2c.h>)
+ DM_HEADER(<asm/clk.h>)
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('testing', scan._drivers)
+ drv = scan._drivers['testing']
+ self.assertEqual('testing', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114'}, drv.compat)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('some_plat', drv.plat)
+ self.assertEqual('some_cpriv', drv.child_priv)
+ self.assertEqual('some_cplat', drv.child_plat)
+ self.assertEqual('tpl', drv.phase)
+ self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_uclass_scan(self):
+ """Test collection of uclass-driver info"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .id = UCLASS_I2C,
+ .name = "i2c",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .priv_auto = sizeof(struct some_priv),
+ .per_device_auto = sizeof(struct per_dev_priv),
+ .per_device_plat_auto = sizeof(struct per_dev_plat),
+ .per_child_auto = sizeof(struct per_child_priv),
+ .per_child_plat_auto = sizeof(struct per_child_plat),
+ .child_post_bind = i2c_child_post_bind,
+};
+
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn('UCLASS_I2C', scan._uclass)
+ drv = scan._uclass['UCLASS_I2C']
+ self.assertEqual('i2c', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('per_dev_priv', drv.per_dev_priv)
+ self.assertEqual('per_dev_plat', drv.per_dev_plat)
+ self.assertEqual('per_child_priv', drv.per_child_priv)
+ self.assertEqual('per_child_plat', drv.per_child_plat)
+ self.assertEqual(1, len(scan._uclass))
+
+ drv2 = copy.deepcopy(drv)
+ self.assertEqual(drv, drv2)
+ drv2.priv = 'other_priv'
+ self.assertNotEqual(drv, drv2)
+
+ # The hashes only depend on the uclass ID, so should be equal
+ self.assertEqual(drv.__hash__(), drv2.__hash__())
+
+ self.assertEqual("UclassDriver(name='i2c', uclass_id='UCLASS_I2C')",
+ str(drv))
+
+ def test_uclass_scan_errors(self):
+ """Test detection of uclass scanning errors"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .name = "i2c",
+};
+
+'''
+ scan = src_scan.Scanner(None, False, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
+ str(exc.exception))
+
+ def test_struct_scan(self):
+ """Test collection of struct info"""
+ buff = '''
+/* some comment */
+struct some_struct1 {
+ struct i2c_msg *msgs;
+ uint nmsgs;
+};
+'''
+ scan = src_scan.Scanner(None, False, None)
+ scan._basedir = os.path.join(OUR_PATH, '..', '..')
+ scan._parse_structs('arch/arm/include/asm/file.h', buff)
+ self.assertIn('some_struct1', scan._structs)
+ struc = scan._structs['some_struct1']
+ self.assertEqual('some_struct1', struc.name)
+ self.assertEqual('asm/file.h', struc.fname)
+
+ buff = '''
+/* another comment */
+struct another_struct {
+ int speed_hz;
+ int max_transaction_bytes;
+};
+'''
+ scan._parse_structs('include/file2.h', buff)
+ self.assertIn('another_struct', scan._structs)
+ struc = scan._structs['another_struct']
+ self.assertEqual('another_struct', struc.name)
+ self.assertEqual('file2.h', struc.fname)
+
+ self.assertEqual(2, len(scan._structs))
+
+ self.assertEqual("Struct(name='another_struct', fname='file2.h')",
+ str(struc))
+
+ def test_struct_scan_errors(self):
+ """Test scanning a header file with an invalid unicode file"""
+ output = tools.GetOutputFilename('output.h')
+ tools.WriteFile(output, b'struct this is a test \x81 of bad unicode')
+
+ scan = src_scan.Scanner(None, False, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.scan_header(output)
+ self.assertIn('due to unicode error', stdout.getvalue())
+
+ def setup_dup_drivers(self, name, phase=''):
+ """Set up for a duplcate test
+
+ Returns:
+ tuple:
+ Scanner to use
+ Driver record for first driver
+ Text of second driver declaration
+ Node for driver 1
+ """
+ driver1 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ %s
+};
+''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
+ driver2 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-dvc" },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_RAM,
+ .of_match = test_ids,
+};
+''' % name
+ scan = src_scan.Scanner(None, False, None, phase)
+ scan._parse_driver('file1.c', driver1)
+ self.assertIn(name, scan._drivers)
+ drv1 = scan._drivers[name]
+
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'nvidia,tegra114-i2c'
+ node = FakeNode()
+ node.name = 'testing'
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ return scan, drv1, driver2, node
+
+ def test_dup_drivers(self):
+ """Test handling of duplicate drivers"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name)
+ self.assertEqual('', drv1.phase)
+
+ # The driver should not have a duplicate yet
+ self.assertEqual([], drv1.dups)
+
+ scan._parse_driver('file2.c', driver2)
+
+ # The first driver should now be a duplicate of the second
+ drv2 = scan._drivers[name]
+ self.assertEqual('', drv2.phase)
+ self.assertEqual(1, len(drv2.dups))
+ self.assertEqual([drv1], drv2.dups)
+
+ # There is no way to distinguish them, so we should expect a warning
+ self.assertTrue(drv2.warn_dups)
+
+ # We should see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual(
+ "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
+ stdout.getvalue().strip())
+
+ def test_dup_drivers_phase(self):
+ """Test handling of duplicate drivers but with different phases"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
+ scan._parse_driver('file2.c', driver2)
+ self.assertEqual('spl', drv1.phase)
+
+ # The second driver should now be a duplicate of the second
+ self.assertEqual(1, len(drv1.dups))
+ drv2 = drv1.dups[0]
+
+ # The phase is different, so we should not warn of dups
+ self.assertFalse(drv1.warn_dups)
+
+ # We should not see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual('', stdout.getvalue().strip())
+
+ def test_sequence(self):
+ """Test assignment of sequence numnbers"""
+ scan = src_scan.Scanner(None, False, None, '')
+ node = FakeNode()
+ uc = src_scan.UclassDriver('UCLASS_I2C')
+ node.uclass = uc
+ node.driver = True
+ node.seq = -1
+ node.path = 'mypath'
+ uc.alias_num_to_node[2] = node
+
+ # This should assign 3 (after the 2 that exists)
+ seq = scan.assign_seq(node)
+ self.assertEqual(3, seq)
+ self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
+ self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)
diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c
index e4112b8..db51246 100644
--- a/tools/fdtgrep.c
+++ b/tools/fdtgrep.c
@@ -213,7 +213,7 @@ static void utilfdt_print_data(const char *data, int len)
} else {
printf(" = [");
for (i = 0; i < len; i++)
- printf("%02x%s", *p++, i < len - 1 ? " " : "");
+ printf("%02x%s", (unsigned char)*p++, i < len - 1 ? " " : "");
printf("]");
}
}
diff --git a/tools/patman/README b/tools/patman/README
index 6b80663..53f55ce 100644
--- a/tools/patman/README
+++ b/tools/patman/README
@@ -136,17 +136,17 @@ How to run it
First do a dry run:
-$ ./tools/patman/patman -n
+$ ./tools/patman/patman send -n
If it can't detect the upstream branch, try telling it how many patches
there are in your series:
-$ ./tools/patman/patman -n -c5
+$ ./tools/patman/patman -c5 send -n
This will create patch files in your current directory and tell you who
it is thinking of sending them to. Take a look at the patch files.
-$ ./tools/patman/patman -n -c5 -s1
+$ ./tools/patman/patman -c5 -s1 send -n
Similar to the above, but skip the first commit and take the next 5. This
is useful if your top commit is for setting up testing.
@@ -433,12 +433,12 @@ but that you don't want to submit because there is an existing patch for it
on the list. So you can tell patman to create and check some patches
(skipping the first patch) with:
- patman -s1 -n
+ patman -s1 send -n
If you want to do all of them including the work-in-progress one, then
(if you are tracking an upstream branch):
- patman -n
+ patman send -n
Let's say that patman reports an error in the second patch. Then:
@@ -450,7 +450,7 @@ Let's say that patman reports an error in the second patch. Then:
Now you have an updated patch series. To check it:
- patman -s1 -n
+ patman -s1 send -n
Let's say it is now clean and you want to send it. Now you need to set up
the destination. So amend the top commit with:
@@ -485,7 +485,7 @@ mmc and sparc, and the last one to sandbox.
Now to send the patches, take off the -n flag:
- patman -s1
+ patman -s1 send
The patches will be created, shown in your editor, and then sent along with
the cover letter. Note that patman's tags are automatically removed so that
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py
index 89072b1..450fe66 100644
--- a/tools/patman/func_test.py
+++ b/tools/patman/func_test.py
@@ -186,7 +186,7 @@ class TestFunctional(unittest.TestCase):
- Commit-notes
"""
process_tags = True
- ignore_bad_tags = True
+ ignore_bad_tags = False
stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
rick = 'Richard III <richard@palace.gov>'
mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
index bf1271d..5e4c112 100644
--- a/tools/patman/gitutil.py
+++ b/tools/patman/gitutil.py
@@ -345,7 +345,7 @@ def CreatePatches(branch, start, count, ignore_binary, series, signoff = True):
else:
return None, files
-def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
+def BuildEmailList(in_list, tag=None, alias=None, warn_on_error=True):
"""Build a list of email addresses based on an input list.
Takes a list of email addresses and aliases, and turns this into a list
@@ -359,7 +359,7 @@ def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
in_list: List of aliases/email addresses
tag: Text to put before each address
alias: Alias dictionary
- raise_on_error: True to raise an error when an alias fails to match,
+ warn_on_error: True to raise an error when an alias fails to match,
False to just print a message.
Returns:
@@ -382,7 +382,7 @@ def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
quote = '"' if tag and tag[0] == '-' else ''
raw = []
for item in in_list:
- raw += LookupEmail(item, alias, raise_on_error=raise_on_error)
+ raw += LookupEmail(item, alias, warn_on_error=warn_on_error)
result = []
for item in raw:
if not item in result:
@@ -416,7 +416,7 @@ def CheckSuppressCCConfig():
return True
-def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
+def EmailPatches(series, cover_fname, args, dry_run, warn_on_error, cc_fname,
self_only=False, alias=None, in_reply_to=None, thread=False,
smtp_server=None):
"""Email a patch series.
@@ -426,8 +426,8 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
cover_fname: filename of cover letter
args: list of filenames of patch files
dry_run: Just return the command that would be run
- raise_on_error: True to raise an error when an alias fails to match,
- False to just print a message.
+ warn_on_error: True to print a warning when an alias fails to match,
+ False to ignore it.
cc_fname: Filename of Cc file for per-commit Cc
self_only: True to just email to yourself as a test
in_reply_to: If set we'll pass this to git as --in-reply-to.
@@ -475,7 +475,7 @@ send --cc-cmd cc-fname" cover p1 p2'
# Restore argv[0] since we clobbered it.
>>> sys.argv[0] = _old_argv0
"""
- to = BuildEmailList(series.get('to'), '--to', alias, raise_on_error)
+ to = BuildEmailList(series.get('to'), '--to', alias, warn_on_error)
if not to:
git_config_to = command.Output('git', 'config', 'sendemail.to',
raise_on_error=False)
@@ -487,9 +487,9 @@ send --cc-cmd cc-fname" cover p1 p2'
"git config sendemail.to u-boot@lists.denx.de")
return
cc = BuildEmailList(list(set(series.get('cc')) - set(series.get('to'))),
- '--cc', alias, raise_on_error)
+ '--cc', alias, warn_on_error)
if self_only:
- to = BuildEmailList([os.getenv('USER')], '--to', alias, raise_on_error)
+ to = BuildEmailList([os.getenv('USER')], '--to', alias, warn_on_error)
cc = []
cmd = ['git', 'send-email', '--annotate']
if smtp_server:
@@ -511,7 +511,7 @@ send --cc-cmd cc-fname" cover p1 p2'
return cmdstr
-def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
+def LookupEmail(lookup_name, alias=None, warn_on_error=True, level=0):
"""If an email address is an alias, look it up and return the full name
TODO: Why not just use git's own alias feature?
@@ -519,8 +519,8 @@ def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
Args:
lookup_name: Alias or email address to look up
alias: Dictionary containing aliases (None to use settings default)
- raise_on_error: True to raise an error when an alias fails to match,
- False to just print a message.
+ warn_on_error: True to print a warning when an alias fails to match,
+ False to ignore it.
Returns:
tuple:
@@ -547,18 +547,16 @@ def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
>>> LookupEmail('all', alias)
['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz', 'm.poppins@cloud.net']
>>> LookupEmail('odd', alias)
- Traceback (most recent call last):
- ...
- ValueError: Alias 'odd' not found
+ Alias 'odd' not found
+ []
>>> LookupEmail('loop', alias)
Traceback (most recent call last):
...
OSError: Recursive email alias at 'other'
- >>> LookupEmail('odd', alias, raise_on_error=False)
- Alias 'odd' not found
+ >>> LookupEmail('odd', alias, warn_on_error=False)
[]
>>> # In this case the loop part will effectively be ignored.
- >>> LookupEmail('loop', alias, raise_on_error=False)
+ >>> LookupEmail('loop', alias, warn_on_error=False)
Recursive email alias at 'other'
Recursive email alias at 'john'
Recursive email alias at 'mary'
@@ -576,7 +574,7 @@ def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
out_list = []
if level > 10:
msg = "Recursive email alias at '%s'" % lookup_name
- if raise_on_error:
+ if warn_on_error:
raise OSError(msg)
else:
print(col.Color(col.RED, msg))
@@ -585,18 +583,15 @@ def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
if lookup_name:
if not lookup_name in alias:
msg = "Alias '%s' not found" % lookup_name
- if raise_on_error:
- raise ValueError(msg)
- else:
+ if warn_on_error:
print(col.Color(col.RED, msg))
- return out_list
+ return out_list
for item in alias[lookup_name]:
- todo = LookupEmail(item, alias, raise_on_error, level + 1)
+ todo = LookupEmail(item, alias, warn_on_error, level + 1)
for new_item in todo:
if not new_item in out_list:
out_list.append(new_item)
- #print("No match for alias '%s'" % lookup_name)
return out_list
def GetTopLevel():
diff --git a/tools/patman/main.py b/tools/patman/main.py
index c4e4d80..04e37a5 100755
--- a/tools/patman/main.py
+++ b/tools/patman/main.py
@@ -9,6 +9,7 @@
from argparse import ArgumentParser
import os
import re
+import shutil
import sys
import traceback
import unittest
@@ -68,7 +69,8 @@ send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
send.add_argument('-r', '--in-reply-to', type=str, action='store',
help="Message ID that this series is in reply to")
send.add_argument('-t', '--ignore-bad-tags', action='store_true',
- default=False, help='Ignore bad tags / aliases')
+ default=False,
+ help='Ignore bad tags / aliases (default=warn)')
send.add_argument('-T', '--thread', action='store_true', dest='thread',
default=False, help='Create patches as a single thread')
send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store',
@@ -170,12 +172,17 @@ elif args.cmd == 'send':
elif args.full_help:
pager = os.getenv('PAGER')
if not pager:
+ pager = shutil.which('less')
+ if not pager:
pager = 'more'
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
'README')
command.Run(pager, fname)
else:
+ # If we are not processing tags, no need to warning about bad ones
+ if not args.process_tags:
+ args.ignore_bad_tags = True
control.send(args)
# Check status of patches in patchwork
diff --git a/tools/patman/series.py b/tools/patman/series.py
index 41a1173..8ae218d 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -234,7 +234,7 @@ class Series(dict):
str = 'Change log exists, but no version is set'
print(col.Color(col.RED, str))
- def MakeCcFile(self, process_tags, cover_fname, raise_on_error,
+ def MakeCcFile(self, process_tags, cover_fname, warn_on_error,
add_maintainers, limit):
"""Make a cc file for us to use for per-commit Cc automation
@@ -243,8 +243,8 @@ class Series(dict):
Args:
process_tags: Process tags as if they were aliases
cover_fname: If non-None the name of the cover letter.
- raise_on_error: True to raise an error when an alias fails to match,
- False to just print a message.
+ warn_on_error: True to print a warning when an alias fails to match,
+ False to ignore it.
add_maintainers: Either:
True/False to call the get_maintainers to CC maintainers
List of maintainers to include (for testing)
@@ -261,9 +261,9 @@ class Series(dict):
cc = []
if process_tags:
cc += gitutil.BuildEmailList(commit.tags,
- raise_on_error=raise_on_error)
+ warn_on_error=warn_on_error)
cc += gitutil.BuildEmailList(commit.cc_list,
- raise_on_error=raise_on_error)
+ warn_on_error=warn_on_error)
if type(add_maintainers) == type(cc):
cc += add_maintainers
elif add_maintainers:
diff --git a/tools/patman/tools.py b/tools/patman/tools.py
index 10997e4..e5f391b 100644
--- a/tools/patman/tools.py
+++ b/tools/patman/tools.py
@@ -130,8 +130,12 @@ def GetInputFilename(fname, allow_missing=False):
allow_missing: True if the filename can be missing
Returns:
- The full path of the filename, within the input directory, or
- None on error
+ fname, if indir is None;
+ full path of the filename, within the input directory;
+ None, if file is missing and allow_missing is True
+
+ Raises:
+ ValueError if file is missing and allow_missing is False
"""
if not indir or fname[:1] == '/':
return fname