summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kconfig26
-rw-r--r--Makefile20
-rw-r--r--arch/arm/include/asm/arch-sunxi/spl.h19
-rw-r--r--arch/arm/lib/Makefile4
-rw-r--r--arch/arm/mach-sunxi/Kconfig4
-rw-r--r--board/sunxi/MAINTAINERS6
-rw-r--r--board/sunxi/README.pine6498
-rw-r--r--board/sunxi/README.sunxi64165
-rw-r--r--board/sunxi/board.c36
-rwxr-xr-xboard/sunxi/mksunxi_fit_atf.sh75
-rw-r--r--common/spl/spl_fit.c301
-rw-r--r--configs/am335x_evm_defconfig1
-rw-r--r--configs/pine64_plus_defconfig1
-rw-r--r--doc/uImage.FIT/howto.txt21
-rw-r--r--doc/uImage.FIT/multi_spl.its89
-rw-r--r--include/configs/sunxi-common.h17
-rw-r--r--scripts/Makefile.spl3
-rw-r--r--tools/mksunxiboot.c53
18 files changed, 714 insertions, 225 deletions
diff --git a/Kconfig b/Kconfig
index 1b19b7b76c..bb80adacf4 100644
--- a/Kconfig
+++ b/Kconfig
@@ -220,18 +220,22 @@ config FIT_IMAGE_POST_PROCESS
injected into the FIT creation (i.e. the blobs would have been pre-
processed before being added to the FIT image).
+if SPL
+
config SPL_FIT
bool "Support Flattened Image Tree within SPL"
depends on SPL
+ select SPL_OF_LIBFDT
config SPL_FIT_SIGNATURE
bool "Enable signature verification of FIT firmware within SPL"
- depends on SPL_FIT
depends on SPL_DM
+ select SPL_FIT
select SPL_RSA
config SPL_LOAD_FIT
bool "Enable SPL loading U-Boot as a FIT"
+ select SPL_FIT
help
Normally with the SPL framework a legacy image is generated as part
of the build. This contains U-Boot along with information as to
@@ -254,6 +258,26 @@ config SPL_FIT_IMAGE_POST_PROCESS
injected into the FIT creation (i.e. the blobs would have been pre-
processed before being added to the FIT image).
+config SPL_FIT_SOURCE
+ string ".its source file for U-Boot FIT image"
+ depends on SPL_FIT
+ help
+ Specifies a (platform specific) FIT source file to generate the
+ U-Boot FIT image. This could specify further image to load and/or
+ execute.
+
+config SPL_FIT_GENERATOR
+ string ".its file generator script for U-Boot FIT image"
+ depends on SPL_FIT
+ default "board/sunxi/mksunxi_fit_atf.sh" if SPL_LOAD_FIT && ARCH_SUNXI
+ help
+ Specifies a (platform specific) script file to generate the FIT
+ source file used to build the U-Boot FIT image file. This gets
+ passed a list of supported device tree file stub names to
+ include in the generated image.
+
+endif # SPL
+
endif # FIT
config OF_BOARD_SETUP
diff --git a/Makefile b/Makefile
index bcab72697f..1b7cab2121 100644
--- a/Makefile
+++ b/Makefile
@@ -833,6 +833,10 @@ quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
$(if $(KBUILD_VERBOSE:1=), >$(MKIMAGEOUTPUT))
+quiet_cmd_mkfitimage = MKIMAGE $@
+cmd_mkfitimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -f $(U_BOOT_ITS) -E $@ \
+ $(if $(KBUILD_VERBOSE:1=), >$(MKIMAGEOUTPUT))
+
quiet_cmd_cat = CAT $@
cmd_cat = cat $(filter-out $(PHONY), $^) > $@
@@ -952,6 +956,19 @@ quiet_cmd_cpp_cfg = CFG $@
cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
-DDO_DEPS_ONLY -D__ASSEMBLY__ -x assembler-with-cpp -P -dM -E -o $@ $<
+# Boards with more complex image requirments can provide an .its source file
+# or a generator script
+ifneq ($(CONFIG_SPL_FIT_SOURCE),"")
+U_BOOT_ITS = $(subst ",,$(CONFIG_SPL_FIT_SOURCE))
+else
+ifneq ($(CONFIG_SPL_FIT_GENERATOR),"")
+U_BOOT_ITS := u-boot.its
+$(U_BOOT_ITS): FORCE
+ $(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \
+ $(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) > $@
+endif
+endif
+
ifdef CONFIG_SPL_LOAD_FIT
MKIMAGEFLAGS_u-boot.img = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \
@@ -984,6 +1001,9 @@ u-boot-dtb.img u-boot.img u-boot.kwb u-boot.pbl u-boot-ivt.img: \
$(if $(CONFIG_SPL_LOAD_FIT),u-boot-nodtb.bin dts/dt.dtb,u-boot.bin) FORCE
$(call if_changed,mkimage)
+u-boot.itb: u-boot-nodtb.bin dts/dt.dtb $(U_BOOT_ITS) FORCE
+ $(call if_changed,mkfitimage)
+
u-boot-spl.kwb: u-boot.img spl/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index 831d0c0ff6..9358397da2 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -10,7 +10,7 @@
#define BOOT0_MAGIC "eGON.BT0"
#define SPL_SIGNATURE "SPL" /* marks "sunxi" SPL header */
-#define SPL_HEADER_VERSION 1
+#define SPL_HEADER_VERSION 2
#ifdef CONFIG_SUNXI_HIGH_SRAM
#define SPL_ADDR 0x10000
@@ -58,11 +58,24 @@ struct boot_file_head {
* compatible format, ready to be imported via "env import -t".
*/
uint32_t fel_uEnv_length;
- uint32_t reserved1[2];
+ /*
+ * Offset of an ASCIIZ string (relative to the SPL header), which
+ * contains the default device tree name (CONFIG_DEFAULT_DEVICE_TREE).
+ * This is optional and may be set to NULL. Is intended to be used
+ * by flash programming tools for providing nice informative messages
+ * to the users.
+ */
+ uint32_t dt_name_offset;
+ uint32_t reserved1;
uint32_t boot_media; /* written here by the boot ROM */
- uint32_t reserved2[5]; /* padding, align to 64 bytes */
+ /* A padding area (may be used for storing text strings) */
+ uint32_t string_pool[13];
+ /* The header must be a multiple of 32 bytes (for VBAR alignment) */
};
+/* Compile time check to assure proper alignment of structure */
+typedef char boot_file_head_not_multiple_of_32[1 - 2*(sizeof(struct boot_file_head) % 32)];
+
#define is_boot0_magic(addr) (memcmp((void *)addr, BOOT0_MAGIC, 8) == 0)
#endif
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 53d4ed2bc6..f162c1428c 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -44,8 +44,10 @@ obj-y += stack.o
ifdef CONFIG_CPU_V7M
obj-y += interrupts_m.o
else ifdef CONFIG_ARM64
-obj-y += ccn504.o
+obj-$(CONFIG_FSL_LAYERSCAPE) += ccn504.o
+ifneq ($(CONFIG_GICV2)$(CONFIG_GICV3),)
obj-y += gic_64.o
+endif
obj-y += interrupts_64.o
else
obj-y += interrupts.o
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 8d9900e00b..7ced838d6a 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -143,12 +143,16 @@ config MACH_SUN50I
select SUNXI_GEN_SUN6I
select SUNXI_HIGH_SRAM
select SUPPORT_SPL
+ select FIT
+ select SPL_LOAD_FIT
config MACH_SUN50I_H5
bool "sun50i (Allwinner H5)"
select ARM64
select MACH_SUNXI_H3_H5
select SUNXI_HIGH_SRAM
+ select FIT
+ select SPL_LOAD_FIT
endchoice
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 1c8817375d..a512a201d0 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -72,7 +72,6 @@ F: configs/q8_a33_tablet_1024x600_defconfig
F: include/configs/sun9i.h
F: configs/Merrii_A80_Optimus_defconfig
F: include/configs/sun50i.h
-F: configs/pine64_plus_defconfig
A20-OLIMEX-SOM-EVB BOARD
M: Marcus Cooper <codekipper@gmail.com>
@@ -263,6 +262,11 @@ M: Andre Przywara <andre.przywara@arm.com>
S: Maintained
F: configs/orangepi_pc2_defconfig
+PINE64 BOARDS
+M: Andre Przywara <andre.przywara@arm.com>
+S: Maintained
+F: configs/pine64_plus_defconfig
+
R16 EVB PARROT BOARD
M: Quentin Schulz <quentin.schulz@free-electrons.com>
S: Maintained
diff --git a/board/sunxi/README.pine64 b/board/sunxi/README.pine64
deleted file mode 100644
index 5553415270..0000000000
--- a/board/sunxi/README.pine64
+++ /dev/null
@@ -1,98 +0,0 @@
-Pine64 board README
-====================
-
-The Pine64(+) is a single board computer equipped with an AArch64 capable ARMv8
-compliant Allwinner A64 SoC.
-This chip has ARM Cortex A-53 cores and thus can run both in AArch32
-(compatible to 32-bit ARMv7) and AArch64 modes. Upon reset the SoC starts
-in AArch32 mode and executes 32-bit code from the Boot ROM (BROM).
-This has some implications on U-Boot.
-
-Quick start
-============
-- Get hold of a boot0.img file (see below for more details).
-- Get the boot0img tool source from the tools directory in [1] and compile
- that on your host.
-- Build U-Boot:
-$ export CROSS_COMPILE=aarch64-linux-gnu-
-$ make pine64_plus_defconfig
-$ make
-- You also need a compiled ARM Trusted Firmware (ATF) binary. Checkout the
- "allwinner" branch from the github repository [2] and build it:
-$ export CROSS_COMPILE=aarch64-linux-gnu-
-$ make PLAT=sun50iw1p1 DEBUG=1 bl31
- The resulting binary is build/sun50iw1p1/debug/bl31.bin.
-
-Now put an empty (or disposable) micro SD card in your card reader and learn
-its device file name, replacing /dev/sd<x> below with the result (that could
-be /dev/mmcblk<x> as well):
-
-$ ./boot0img --device /dev/sd<x> -e -u u-boot.bin -B boot0.img \
- -d trampoline64:0x44000 -s bl31.bin -a 0x44008 -p 100
-(either copying the respective files to the working directory or specifying
-the paths directly)
-
-This will create a new partition table (with a 100 MB FAT boot partition),
-copies boot0.img, ATF and U-Boot to the proper locations on the SD card and
-will fill in the magic Allwinner header to be recognized by boot0.
-Prefix the above call with "sudo" if you don't have write access to the
-uSD card. You can also use "-o output.img" instead of "--device /dev/sd<x>"
-to create an image file and "dd" that to the uSD card.
-Omitting the "-p" option will skip the partition table.
-
-Now put this uSD card in the board and power it on. You should be greeted by
-the U-Boot prompt.
-
-
-Main U-Boot
-============
-The main U-Boot proper is a real 64-bit ARMv8 port and runs entirely in the
-64-bit AArch64 mode. It can load any AArch64 code, EFI applications or arm64
-Linux kernel images (often named "Image") using the booti command.
-Launching 32-bit code and kernels is technically possible, though not without
-drawbacks (or hacks to avoid them) and currently not implemented.
-
-SPL support
-============
-The main task of the SPL support is to bring up the DRAM controller and make
-DRAM actually accessible. At the moment there is no documentation or source
-code available which would do this.
-There are currently two ways to overcome this situation: using a tainted 32-bit
-SPL (involving some hacks and resulting in a non-redistributable binary, thus
-not described here) or using the Allwinner boot0 blob.
-
-boot0 method
--------------
-boot0 is Allwiner's secondary program loader and it can be used as some kind
-of SPL replacement to get U-Boot up and running.
-The binary is a 32 KByte blob and contained on every Pine64 image distributed
-so far. It can be easily extracted from a micro SD card or an image file:
-# dd if=/dev/sd<x> of=boot0.bin bs=8k skip=1 count=4
-where /dev/sd<x> is the device name of the uSD card or the name of the image
-file. Apparently Allwinner allows re-distribution of this proprietary code
-as-is.
-For the time being this boot0 blob is the only redistributable way of making
-U-Boot work on the Pine64. Beside loading the various parts of the (original)
-firmware it also switches the core into AArch64 mode.
-The original boot0 code looks for U-Boot at a certain place on an uSD card
-(at 19096 KB), also it expects a header with magic bytes and a checksum.
-There is a tool called boot0img[1] which takes a boot0.bin image and a compiled
-U-Boot binary (plus other binaries) and will populate that header accordingly.
-To make space for the magic header, the pine64_plus_defconfig will make sure
-there is sufficient space at the beginning of the U-Boot binary.
-boot0img will also take care of putting the different binaries at the right
-places on the uSD card and works around unused, but mandatory parts by using
-trampoline code. See the output of "boot0img -h" for more information.
-boot0img can also patch boot0 to avoid loading U-Boot from 19MB, instead
-fetching it from just behind the boot0 binary (-B option).
-
-FEL boot
-=========
-FEL is the name of the Allwinner defined USB boot protocol built-in the
-mask ROM of most Allwinner SoCs. It allows to bootstrap a board solely
-by using the USB-OTG interface and a host port on another computer.
-Since FEL boot does not work with boot0, it requires the libdram hack, which
-is not described here.
-
-[1] https://github.com/apritzel/pine64/
-[2] https://github.com/apritzel/arm-trusted-firmware.git
diff --git a/board/sunxi/README.sunxi64 b/board/sunxi/README.sunxi64
new file mode 100644
index 0000000000..c492f749b8
--- /dev/null
+++ b/board/sunxi/README.sunxi64
@@ -0,0 +1,165 @@
+Allwinner 64-bit boards README
+==============================
+
+Newer Allwinner SoCs feature ARMv8 cores (ARM Cortex-A53) with support for
+both the 64-bit AArch64 mode and the ARMv7 compatible 32-bit AArch32 mode.
+Examples are the Allwinner A64 (used for instance on the Pine64 board) or
+the Allwinner H5 SoC (as used on the OrangePi PC 2).
+These SoCs are wired to start in AArch32 mode on reset and execute 32-bit
+code from the Boot ROM (BROM). As this has some implications on U-Boot, this
+file describes how to make full use of the 64-bit capabilities.
+
+Quick Start / Overview
+======================
+- Build the ARM Trusted Firmware binary (see "ARM Trusted Firmware (ATF)" below)
+- Build U-Boot (see "SPL/U-Boot" below)
+- Transfer to an uSD card (see "microSD card" below)
+- Boot and enjoy!
+
+Building the firmware
+=====================
+
+The Allwinner A64/H5 firmware consists of three parts: U-Boot's SPL, an
+ARM Trusted Firmware (ATF) build and the U-Boot proper.
+The SPL will load both ATF and U-Boot proper along with the right device
+tree blob (.dtb) and will pass execution to ATF (in EL3), which in turn will
+drop into the U-Boot proper (in EL2).
+As the ATF binary will become part of the U-Boot image file, you will need
+to build it first.
+
+ ARM Trusted Firmware (ATF)
+----------------------------
+Checkout the "allwinner" branch from the github repository [1] and build it:
+$ export CROSS_COMPILE=aarch64-linux-gnu-
+$ make PLAT=sun50iw1p1 DEBUG=1 bl31
+The resulting binary is build/sun50iw1p1/debug/bl31.bin. Either put the
+location of this file into the BL31 environment variable or copy this to
+the root of your U-Boot build directory (or create a symbolic link).
+$ export BL31=/src/arm-trusted-firmware/build/sun50iw1p1/debug/bl31.bin
+ (adjust the actual path accordingly)
+
+ SPL/U-Boot
+------------
+Both U-Boot proper and the SPL are using the 64-bit mode. As the boot ROM
+enters the SPL still in AArch32 secure SVC mode, there is some shim code to
+enter AArch64 very early. The rest of the SPL runs in AArch64 EL3.
+U-Boot proper runs in EL2 and can load any AArch64 code (using the "go"
+command), EFI applications (with "bootefi") or arm64 Linux kernel images
+(often named "Image"), using the "booti" command.
+
+$ make clean
+$ export CROSS_COMPILE=aarch64-linux-gnu-
+$ make pine64_plus_defconfig
+$ make
+
+This will build the SPL in spl/sunxi-spl.bin and a FIT image called u-boot.itb,
+which contains the rest of the firmware.
+
+
+Boot process
+============
+The on-die BROM code will try several methods to load and execute the firmware.
+On a typical board like the Pine64 this will result in the following boot order:
+
+1) Reading 32KB from sector 16 (@8K) of the microSD card to SRAM A1. If the
+BROM finds the magic "eGON" header in the first bytes, it will execute that
+code. If not (no SD card at all or invalid magic), it will:
+2) Try to read 32KB from sector 16 (@8K) of memory connected to the MMC2
+controller, typically an on-board eMMC chip. If there is no eMMC or it does
+not contain a valid boot header, it will:
+3) Initialize the SPI0 controller and try to access a NOR flash connected to
+it (using the CS0 pin). If a flash chip is found, the BROM will load the
+first 32KB (from offset 0) into SRAM A1. Now it checks for the magic eGON
+header and checksum and will execute the code upon finding it. If not, it will:
+4) Initialize the USB OTG controller and will wait for a host to connect to
+it, speaking the Allwinner proprietary (but deciphered) "FEL" USB protocol.
+
+
+To boot the Pine64 board, you can use U-Boot and any of the described methods.
+
+FEL boot (USB OTG)
+------------------
+FEL is the name of the Allwinner defined USB boot protocol built in the
+mask ROM of most Allwinner SoCs. It allows to bootstrap a board solely
+by using the USB-OTG interface and a host port on another computer.
+As the FEL mode is controlled by the boot ROM, it expects to be running in
+AArch32. For now the AArch64 SPL cannot properly return into FEL mode, so the
+feature is disabled in the configuration at the moment.
+
+microSD card
+------------
+Transfer the SPL and the U-Boot FIT image directly to an uSD card:
+# dd if=spl/sunxi-spl.bin of=/dev/sdx bs=8k seek=1
+# dd if=u-boot.itb of=/dev/sdx bs=8k seek=5
+# sync
+(replace /dev/sdx with you SD card device file name, which could be
+/dev/mmcblk[x] as well).
+
+Alternatively you can concatenate the SPL and the U-Boot FIT image into a
+single file and transfer that instead:
+$ cat spl/sunxi-spl.bin u-boot.itb > u-boot-sunxi-with-spl.bin
+# dd if=u-boot-sunxi-with-spl.bin of=/dev/sdx bs=8k seek=1
+
+You can partition the microSD card, but leave the first MB unallocated (most
+partitioning tools will do this anyway).
+
+NOR flash
+---------
+Some boards (like the SoPine, Pinebook or the OrangePi PC2) come with a
+soldered SPI NOR flash chip. On other boards like the Pine64 such a chip
+can be connected to the SPI0/CS0 pins on the PI-2 headers.
+Create the SPL and FIT image like described above for the SD card.
+Now connect either an "A to A" USB cable to the upper USB port on the Pine64
+or get an adaptor and use a regular A-microB cable connected to it. Other
+boards often have a proper micro-B USB socket connected to the USB OTB port.
+Remove a microSD card from the slot and power on the board.
+On your host computer download and build the sunxi-tools package[2], then
+use "sunxi-fel" to access the board:
+$ ./sunxi-fel ver -v -p
+This should give you an output starting with: AWUSBFEX soc=00001689(A64) ...
+Now use the sunxi-fel tool to write to the NOR flash:
+$ ./sunxi-fel spiflash-write 0 spl/sunxi-spl.bin
+$ ./sunxi-fel spiflash-write 32768 u-boot.itb
+Now boot the board without an SD card inserted and you should see the
+U-Boot prompt on the serial console.
+
+(Legacy) boot0 method
+---------------------
+boot0 is Allwiner's secondary program loader and it can be used as some kind
+of SPL replacement to get U-Boot up and running from an microSD card.
+For some time using boot0 was the only option to get the Pine64 booted.
+With working DRAM init code in U-Boot's SPL this is no longer necessary,
+but this method is described here for the sake of completeness.
+Please note that this method works only with the boot0 files shipped with
+A64 based boards, the H5 uses an incompatible layout which is not supported
+by this method.
+
+The boot0 binary is a 32 KByte blob and contained in the official Pine64 images
+distributed by Pine64 or Allwinner. It can be easily extracted from a micro
+SD card or an image file:
+# dd if=/dev/sd<x> of=boot0.bin bs=8k skip=1 count=4
+where /dev/sd<x> is the device name of the uSD card or the name of the image
+file. Apparently Allwinner allows re-distribution of this proprietary code
+"as-is".
+This boot0 blob takes care of DRAM initialisation and loads the remaining
+firmware parts, then switches the core into AArch64 mode.
+The original boot0 code looks for U-Boot at a certain place on an uSD card
+(at 19096 KB), also it expects a header with magic bytes and a checksum.
+There is a tool called boot0img[3] which takes a boot0.bin image and a compiled
+U-Boot binary (plus other binaries) and will populate that header accordingly.
+To make space for the magic header, the pine64_plus_defconfig will make sure
+there is sufficient space at the beginning of the U-Boot binary.
+boot0img will also take care of putting the different binaries at the right
+places on the uSD card and works around unused, but mandatory parts by using
+trampoline code. See the output of "boot0img -h" for more information.
+boot0img can also patch boot0 to avoid loading U-Boot from 19MB, instead
+fetching it from just behind the boot0 binary (-B option).
+$ ./boot0img -o firmware.img -B boot0.img -u u-boot-dtb.bin -e -s bl31.bin \
+-a 0x44008 -d trampoline64:0x44000
+Then write this image to a microSD card, replacing /dev/sdx with the right
+device file (see above):
+$ dd if=firmware.img of=/dev/sdx bs=8k seek=1
+
+[1] https://github.com/apritzel/arm-trusted-firmware.git
+[2] git://github.com/linux-sunxi/sunxi-tools.git
+[3] https://github.com/apritzel/pine64/
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 4404edb59e..f79bd5c62c 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -512,7 +512,6 @@ int board_mmc_init(bd_t *bis)
void sunxi_board_init(void)
{
int power_failed = 0;
- unsigned long ramsize;
#ifdef CONFIG_SY8106A_POWER
power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT);
@@ -573,9 +572,9 @@ void sunxi_board_init(void)
#endif
#endif
printf("DRAM:");
- ramsize = sunxi_dram_init();
- printf(" %d MiB\n", (int)(ramsize >> 20));
- if (!ramsize)
+ gd->ram_size = sunxi_dram_init();
+ printf(" %d MiB\n", (int)(gd->ram_size >> 20));
+ if (!gd->ram_size)
hang();
/*
@@ -758,3 +757,32 @@ int ft_board_setup(void *blob, bd_t *bd)
#endif
return 0;
}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
+ const char *cmp_str = (void *)(ulong)SPL_ADDR;
+
+ /* Check if there is a DT name stored in the SPL header and use that. */
+ if (spl->dt_name_offset) {
+ cmp_str += spl->dt_name_offset;
+ } else {
+#ifdef CONFIG_DEFAULT_DEVICE_TREE
+ cmp_str = CONFIG_DEFAULT_DEVICE_TREE;
+#else
+ return 0;
+#endif
+ };
+
+/* Differentiate the two Pine64 board DTs by their DRAM size. */
+ if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) {
+ if ((gd->ram_size > 512 * 1024 * 1024))
+ return !strstr(name, "plus");
+ else
+ return !!strstr(name, "plus");
+ } else {
+ return strcmp(name, cmp_str);
+ }
+}
+#endif
diff --git a/board/sunxi/mksunxi_fit_atf.sh b/board/sunxi/mksunxi_fit_atf.sh
new file mode 100755
index 0000000000..ecea1b839b
--- /dev/null
+++ b/board/sunxi/mksunxi_fit_atf.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# script to generate FIT image source for 64-bit sunxi boards with
+# ARM Trusted Firmware and multiple device trees (given on the command line)
+#
+# usage: $0 <dt_name> [<dt_name> [<dt_name] ...]
+
+[ -z "$BL31" ] && BL31="bl31.bin"
+
+cat << __HEADER_EOF
+/dts-v1/;
+
+/ {
+ description = "Configuration to load ATF before U-Boot";
+ #address-cells = <1>;
+
+ images {
+ uboot@1 {
+ description = "U-Boot (64-bit)";
+ data = /incbin/("u-boot-nodtb.bin");
+ type = "standalone";
+ arch = "arm64";
+ compression = "none";
+ load = <0x4a000000>;
+ };
+ atf@1 {
+ description = "ARM Trusted Firmware";
+ data = /incbin/("$BL31");
+ type = "firmware";
+ arch = "arm64";
+ compression = "none";
+ load = <0x44000>;
+ entry = <0x44000>;
+ };
+__HEADER_EOF
+
+cnt=1
+for dtname in $*
+do
+ cat << __FDT_IMAGE_EOF
+ fdt@$cnt {
+ description = "$(basename $dtname .dtb)";
+ data = /incbin/("$dtname");
+ type = "flat_dt";
+ compression = "none";
+ };
+__FDT_IMAGE_EOF
+ cnt=$((cnt+1))
+done
+
+cat << __CONF_HEADER_EOF
+ };
+ configurations {
+ default = "config@1";
+
+__CONF_HEADER_EOF
+
+cnt=1
+for dtname in $*
+do
+ cat << __CONF_SECTION_EOF
+ config@$cnt {
+ description = "$(basename $dtname .dtb)";
+ firmware = "uboot@1";
+ loadables = "atf@1";
+ fdt = "fdt@$cnt";
+ };
+__CONF_SECTION_EOF
+ cnt=$((cnt+1))
+done
+
+cat << __ITS_EOF
+ };
+};
+__ITS_EOF
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index aae556f97d..4c42a96ca3 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -11,24 +11,30 @@
#include <libfdt.h>
#include <spl.h>
+#define FDT_ERROR ((ulong)(-1))
+
static ulong fdt_getprop_u32(const void *fdt, int node, const char *prop)
{
const u32 *cell;
int len;
cell = fdt_getprop(fdt, node, prop, &len);
- if (len != sizeof(*cell))
- return -1U;
+ if (!cell || len != sizeof(*cell))
+ return FDT_ERROR;
+
return fdt32_to_cpu(*cell);
}
-static int spl_fit_select_fdt(const void *fdt, int images, int *fdt_offsetp)
+/*
+ * Iterate over all /configurations subnodes and call a platform specific
+ * function to find the matching configuration.
+ * Returns the node offset or a negative error number.
+ */
+static int spl_fit_find_config_node(const void *fdt)
{
- const char *name, *fdt_name;
- int conf, node, fdt_node;
- int len;
+ const char *name;
+ int conf, node, len;
- *fdt_offsetp = 0;
conf = fdt_path_offset(fdt, FIT_CONFS_PATH);
if (conf < 0) {
debug("%s: Cannot find /configurations node: %d\n", __func__,
@@ -50,39 +56,69 @@ static int spl_fit_select_fdt(const void *fdt, int images, int *fdt_offsetp)
continue;
debug("Selecting config '%s'", name);
- fdt_name = fdt_getprop(fdt, node, FIT_FDT_PROP, &len);
- if (!fdt_name) {
- debug("%s: Cannot find fdt name property: %d\n",
- __func__, len);
- return -EINVAL;
- }
- debug(", fdt '%s'\n", fdt_name);
- fdt_node = fdt_subnode_offset(fdt, images, fdt_name);
- if (fdt_node < 0) {
- debug("%s: Cannot find fdt node '%s': %d\n",
- __func__, fdt_name, fdt_node);
- return -EINVAL;
+ return node;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * spl_fit_get_image_node(): By using the matching configuration subnode,
+ * retrieve the name of an image, specified by a property name and an index
+ * into that.
+ * @fit: Pointer to the FDT blob.
+ * @images: Offset of the /images subnode.
+ * @type: Name of the property within the configuration subnode.
+ * @index: Index into the list of strings in this property.
+ *
+ * Return: the node offset of the respective image node or a negative
+ * error number.
+ */
+static int spl_fit_get_image_node(const void *fit, int images,
+ const char *type, int index)
+{
+ const char *name, *str;
+ int node, conf_node;
+ int len, i;
+
+ conf_node = spl_fit_find_config_node(fit);
+ if (conf_node < 0) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("No matching DT out of these options:\n");
+ for (node = fdt_first_subnode(fit, conf_node);
+ node >= 0;
+ node = fdt_next_subnode(fit, node)) {
+ name = fdt_getprop(fit, node, "description", &len);
+ printf(" %s\n", name);
}
+#endif
+ return conf_node;
+ }
- *fdt_offsetp = fdt_getprop_u32(fdt, fdt_node, "data-offset");
- len = fdt_getprop_u32(fdt, fdt_node, "data-size");
- debug("FIT: Selected '%s'\n", name);
+ name = fdt_getprop(fit, conf_node, type, &len);
+ if (!name) {
+ debug("cannot find property '%s': %d\n", type, len);
+ return -EINVAL;
+ }
- return len;
+ str = name;
+ for (i = 0; i < index; i++) {
+ str = strchr(str, '\0') + 1;
+ if (!str || (str - name >= len)) {
+ debug("no string for index %d\n", index);
+ return -E2BIG;
+ }
}
-#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
- printf("No matching DT out of these options:\n");
- for (node = fdt_first_subnode(fdt, conf);
- node >= 0;
- node = fdt_next_subnode(fdt, node)) {
- name = fdt_getprop(fdt, node, "description", &len);
- printf(" %s\n", name);
+ debug("%s: '%s'\n", type, str);
+ node = fdt_subnode_offset(fit, images, str);
+ if (node < 0) {
+ debug("cannot find image node '%s': %d\n", str, node);
+ return -EINVAL;
}
-#endif
- return -ENOENT;
+ return node;
}
static int get_aligned_image_offset(struct spl_load_info *info, int offset)
@@ -123,19 +159,82 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size,
return (data_size + info->bl_len - 1) / info->bl_len;
}
+/**
+ * spl_load_fit_image(): load the image described in a certain FIT node
+ * @info: points to information about the device to load data from
+ * @sector: the start sector of the FIT image on the device
+ * @fit: points to the flattened device tree blob describing the FIT
+ * image
+ * @base_offset: the beginning of the data area containing the actual
+ * image data, relative to the beginning of the FIT
+ * @node: offset of the DT node describing the image to load (relative
+ * to @fit)
+ * @image_info: will be filled with information about the loaded image
+ * If the FIT node does not contain a "load" (address) property,
+ * the image gets loaded to the address pointed to by the
+ * load_addr member in this struct.
+ *
+ * Return: 0 on success or a negative error number.
+ */
+static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
+ void *fit, ulong base_offset, int node,
+ struct spl_image_info *image_info)
+{
+ ulong offset;
+ size_t length;
+ ulong load_addr, load_ptr;
+ void *src;
+ ulong overhead;
+ int nr_sectors;
+ int align_len = ARCH_DMA_MINALIGN - 1;
+
+ offset = fdt_getprop_u32(fit, node, "data-offset");
+ if (offset == FDT_ERROR)
+ return -ENOENT;
+ offset += base_offset;
+ length = fdt_getprop_u32(fit, node, "data-size");
+ if (length == FDT_ERROR)
+ return -ENOENT;
+ load_addr = fdt_getprop_u32(fit, node, "load");
+ if (load_addr == FDT_ERROR && image_info)
+ load_addr = image_info->load_addr;
+ load_ptr = (load_addr + align_len) & ~align_len;
+
+ overhead = get_aligned_image_overhead(info, offset);
+ nr_sectors = get_aligned_image_size(info, length, offset);
+
+ if (info->read(info, sector + get_aligned_image_offset(info, offset),
+ nr_sectors, (void*)load_ptr) != nr_sectors)
+ return -EIO;
+ debug("image: dst=%lx, offset=%lx, size=%lx\n", load_ptr, offset,
+ (unsigned long)length);
+
+ src = (void *)load_ptr + overhead;
+#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
+ board_fit_image_post_process(&src, &length);
+#endif
+
+ memcpy((void*)load_addr, src, length);
+
+ if (image_info) {
+ image_info->load_addr = load_addr;
+ image_info->size = length;
+ image_info->entry_point = fdt_getprop_u32(fit, node, "entry");
+ }
+
+ return 0;
+}
+
int spl_load_simple_fit(struct spl_image_info *spl_image,
struct spl_load_info *info, ulong sector, void *fit)
{
int sectors;
- ulong size, load;
+ ulong size;
unsigned long count;
- int node, images;
- void *load_ptr;
- int fdt_offset, fdt_len;
- int data_offset, data_size;
+ struct spl_image_info image_info;
+ int node, images, ret;
int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
- int src_sector;
- void *dst, *src;
+ int index = 0;
/*
* Figure out where the external images start. This is the base for the
@@ -168,90 +267,82 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
if (count == 0)
return -EIO;
- /* find the firmware image to load */
+ /* find the node holding the images information */
images = fdt_path_offset(fit, FIT_IMAGES_PATH);
if (images < 0) {
debug("%s: Cannot find /images node: %d\n", __func__, images);
return -1;
}
- node = fdt_first_subnode(fit, images);
+
+ /* find the U-Boot image */
+ node = spl_fit_get_image_node(fit, images, "firmware", 0);
+ if (node < 0) {
+ debug("could not find firmware image, trying loadables...\n");
+ node = spl_fit_get_image_node(fit, images, "loadables", 0);
+ /*
+ * If we pick the U-Boot image from "loadables", start at
+ * the second image when later loading additional images.
+ */
+ index = 1;
+ }
if (node < 0) {
- debug("%s: Cannot find first image node: %d\n", __func__, node);
+ debug("%s: Cannot find u-boot image node: %d\n",
+ __func__, node);
return -1;
}
- /* Get its information and set up the spl_image structure */
- data_offset = fdt_getprop_u32(fit, node, "data-offset");
- data_size = fdt_getprop_u32(fit, node, "data-size");
- load = fdt_getprop_u32(fit, node, "load");
- debug("data_offset=%x, data_size=%x\n", data_offset, data_size);
- spl_image->load_addr = load;
- spl_image->entry_point = load;
- spl_image->os = IH_OS_U_BOOT;
-
- /*
- * Work out where to place the image. We read it so that the first
- * byte will be at 'load'. This may mean we need to load it starting
- * before then, since we can only read whole blocks.
- */
- data_offset += base_offset;
- sectors = get_aligned_image_size(info, data_size, data_offset);
- load_ptr = (void *)load;
- debug("U-Boot size %x, data %p\n", data_size, load_ptr);
- dst = load_ptr;
-
- /* Read the image */
- src_sector = sector + get_aligned_image_offset(info, data_offset);
- debug("Aligned image read: dst=%p, src_sector=%x, sectors=%x\n",
- dst, src_sector, sectors);
- count = info->read(info, src_sector, sectors, dst);
- if (count != sectors)
- return -EIO;
- debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset,
- data_size);
- src = dst + get_aligned_image_overhead(info, data_offset);
+ /* Load the image and set up the spl_image structure */
+ ret = spl_load_fit_image(info, sector, fit, base_offset, node,
+ spl_image);
+ if (ret)
+ return ret;
-#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
- board_fit_image_post_process((void **)&src, (size_t *)&data_size);
-#endif
-
- memcpy(dst, src, data_size);
+ spl_image->os = IH_OS_U_BOOT;
/* Figure out which device tree the board wants to use */
- fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset);
- if (fdt_len < 0)
- return fdt_len;
+ node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0);
+ if (node < 0) {
+ debug("%s: cannot find FDT node\n", __func__);
+ return node;
+ }
/*
- * Read the device tree and place it after the image. There may be
- * some extra data before it since we can only read entire blocks.
- * And also align the destination address to ARCH_DMA_MINALIGN.
+ * Read the device tree and place it after the image.
+ * Align the destination address to ARCH_DMA_MINALIGN.
*/
- dst = (void *)((load + data_size + align_len) & ~align_len);
- fdt_offset += base_offset;
- sectors = get_aligned_image_size(info, fdt_len, fdt_offset);
- src_sector = sector + get_aligned_image_offset(info, fdt_offset);
- count = info->read(info, src_sector, sectors, dst);
- debug("Aligned fdt read: dst %p, src_sector = %x, sectors %x\n",
- dst, src_sector, sectors);
- if (count != sectors)
- return -EIO;
+ image_info.load_addr = spl_image->load_addr + spl_image->size;
+ ret = spl_load_fit_image(info, sector, fit, base_offset, node,
+ &image_info);
+ if (ret < 0)
+ return ret;
+
+ /* Now check if there are more images for us to load */
+ for (; ; index++) {
+ node = spl_fit_get_image_node(fit, images, "loadables", index);
+ if (node < 0)
+ break;
+
+ ret = spl_load_fit_image(info, sector, fit, base_offset, node,
+ &image_info);
+ if (ret < 0)
+ continue;
+
+ /*
+ * If the "firmware" image did not provide an entry point,
+ * use the first valid entry point from the loadables.
+ */
+ if (spl_image->entry_point == FDT_ERROR &&
+ image_info.entry_point != FDT_ERROR)
+ spl_image->entry_point = image_info.entry_point;
+ }
/*
- * Copy the device tree so that it starts immediately after the image.
- * After this we will have the U-Boot image and its device tree ready
- * for us to start.
+ * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's
+ * Makefile will set it to 0 and it will end up as the entry point
+ * here. What it actually means is: use the load address.
*/
- debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset,
- fdt_len);
- src = dst + get_aligned_image_overhead(info, fdt_offset);
- dst = load_ptr + data_size;
-
-#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
- board_fit_image_post_process((void **)&src, (size_t *)&fdt_len);
-#endif
-
- memcpy(dst, src, fdt_len);
+ if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0)
+ spl_image->entry_point = spl_image->load_addr;
return 0;
}
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index c3237f51e4..962bb65443 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -48,4 +48,3 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
CONFIG_RSA=y
-CONFIG_SPL_OF_LIBFDT=y
diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig
index 92bda60095..593e24a836 100644
--- a/configs/pine64_plus_defconfig
+++ b/configs/pine64_plus_defconfig
@@ -3,6 +3,7 @@ CONFIG_ARCH_SUNXI=y
CONFIG_MACH_SUN50I=y
CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-plus"
+CONFIG_OF_LIST="sun50i-a64-pine64 sun50i-a64-pine64-plus"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_CONSOLE_MUX=y
CONFIG_SPL=y
diff --git a/doc/uImage.FIT/howto.txt b/doc/uImage.FIT/howto.txt
index 14e316f72c..2988a52aa1 100644
--- a/doc/uImage.FIT/howto.txt
+++ b/doc/uImage.FIT/howto.txt
@@ -44,6 +44,27 @@ image source file mkimage + dtc transfer to target
+ ---------------> image file --------------------> bootm
image data file(s)
+SPL usage
+---------
+
+The SPL can make use of the new image format as well, this traditionally
+is used to ship multiple device tree files within one image. Code in the SPL
+will choose the one matching the current board and append this to the
+U-Boot proper binary to be automatically used up by it.
+Aside from U-Boot proper and one device tree blob the SPL can load multiple,
+arbitrary image files as well. These binaries should be specified in their
+own subnode under the /images node, which should then be referenced from one or
+multiple /configurations subnodes. The required images must be enumerated in
+the "loadables" property as a list of strings.
+
+If a platform specific image source file (.its) is shipped with the U-Boot
+source, it can be specified using the CONFIG_SPL_FIT_SOURCE Kconfig symbol.
+In this case it will be automatically used by U-Boot's Makefile to generate
+the image.
+If a static source file is not flexible enough, CONFIG_SPL_FIT_GENERATOR
+can point to a script which generates this image source file during
+the build process. It gets passed a list of device tree files (taken from the
+CONFIG_OF_LIST symbol).
Example 1 -- old-style (non-FDT) kernel booting
-----------------------------------------------
diff --git a/doc/uImage.FIT/multi_spl.its b/doc/uImage.FIT/multi_spl.its
new file mode 100644
index 0000000000..e5551d42b7
--- /dev/null
+++ b/doc/uImage.FIT/multi_spl.its
@@ -0,0 +1,89 @@
+/dts-v1/;
+
+/*
+ * (Bogus) example FIT image description file demonstrating the usage
+ * of multiple images loaded by the SPL.
+ * Several binaries will be loaded at their respective load addresses.
+ * Finally the one image specifying an entry point will be entered by the SPL.
+ */
+
+/ {
+ description = "multiple firmware blobs and U-Boot, loaded by SPL";
+ #address-cells = <0x1>;
+
+ images {
+
+ uboot {
+ description = "U-Boot (64-bit)";
+ type = "standalone";
+ arch = "arm64";
+ compression = "none";
+ load = <0x4a000000>;
+ };
+
+ atf {
+ description = "ARM Trusted Firmware";
+ type = "firmware";
+ arch = "arm64";
+ compression = "none";
+ load = <0x18000>;
+ entry = <0x18000>;
+ };
+
+ mgmt-firmware {
+ description = "arisc management processor firmware";
+ type = "firmware";
+ arch = "or1k";
+ compression = "none";
+ load = <0x40000>;
+ };
+
+ fdt@1 {
+ description = "Pine64+ DT";
+ type = "flat_dt";
+ compression = "none";
+ load = <0x4fa00000>;
+ arch = "arm64";
+ };
+
+ fdt@2 {
+ description = "Pine64 DT";
+ type = "flat_dt";
+ compression = "none";
+ load = <0x4fa00000>;
+ arch = "arm64";
+ };
+
+ kernel {
+ description = "4.7-rc5 kernel";
+ type = "kernel";
+ compression = "none";
+ load = <0x40080000>;
+ arch = "arm64";
+ };
+
+ initrd {
+ description = "Debian installer initrd";
+ type = "ramdisk";
+ compression = "none";
+ load = <0x4fe00000>;
+ arch = "arm64";
+ };
+ };
+
+ configurations {
+ default = "config@1";
+
+ config@1 {
+ description = "sun50i-a64-pine64-plus";
+ loadables = "uboot", "atf", "kernel", "initrd";
+ fdt = "fdt@1";
+ };
+
+ config@2 {
+ description = "sun50i-a64-pine64";
+ loadables = "uboot", "atf", "mgmt-firmware";
+ fdt = "fdt@2";
+ };
+ };
+};
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 997a92c8be..f042f0d0c2 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -32,6 +32,10 @@
# define CONFIG_MACH_TYPE_COMPAT_REV 1
#endif
+#ifdef CONFIG_ARM64
+#define CONFIG_BUILD_TARGET "u-boot.itb"
+#endif
+
/* Serial & console */
#define CONFIG_SYS_NS16550_SERIAL
/* ns16550 reg in the low bits of cpu reg */
@@ -185,12 +189,17 @@
#endif
#ifdef CONFIG_SUNXI_HIGH_SRAM
-#define CONFIG_SPL_TEXT_BASE 0x10040 /* sram start+header */
-#define CONFIG_SPL_MAX_SIZE 0x7fc0 /* 32 KiB */
+#define CONFIG_SPL_TEXT_BASE 0x10060 /* sram start+header */
+#define CONFIG_SPL_MAX_SIZE 0x7fa0 /* 32 KiB */
+#ifdef CONFIG_ARM64
+/* end of SRAM A2 for now, as SRAM A1 is pretty tight for an ARM64 build */
+#define LOW_LEVEL_SRAM_STACK 0x00054000
+#else
#define LOW_LEVEL_SRAM_STACK 0x00018000
+#endif /* !CONFIG_ARM64 */
#else
-#define CONFIG_SPL_TEXT_BASE 0x40 /* sram start+header */
-#define CONFIG_SPL_MAX_SIZE 0x5fc0 /* 24KB on sun4i/sun7i */
+#define CONFIG_SPL_TEXT_BASE 0x60 /* sram start+header */
+#define CONFIG_SPL_MAX_SIZE 0x5fa0 /* 24KB on sun4i/sun7i */
#define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */
#endif
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 182b3002c1..135706f21d 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -304,7 +304,8 @@ $(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE
$(call if_changed,mkimage)
quiet_cmd_mksunxiboot = MKSUNXI $@
-cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
+cmd_mksunxiboot = $(objtree)/tools/mksunxiboot \
+ --default-dt $(CONFIG_DEFAULT_DEVICE_TREE) $< $@
$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
$(call if_changed,mksunxiboot)
diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c
index 0f0b003a83..db0f10ec29 100644
--- a/tools/mksunxiboot.c
+++ b/tools/mksunxiboot.c
@@ -48,8 +48,8 @@ int gen_check_sum(struct boot_file_head *head_p)
#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
-#define SUN4I_SRAM_SIZE 0x7600 /* 0x7748+ is used by BROM */
-#define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head))
+#define SUNXI_SRAM_SIZE 0x8000 /* SoC with smaller size are limited before */
+#define SRAM_LOAD_MAX_SIZE (SUNXI_SRAM_SIZE - sizeof(struct boot_file_head))
/*
* BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned
@@ -70,11 +70,40 @@ int main(int argc, char *argv[])
struct boot_img img;
unsigned file_size;
int count;
+ char *tool_name = argv[0];
+ char *default_dt = NULL;
- if (argc < 2) {
- printf("\tThis program makes an input bin file to sun4i " \
- "bootable image.\n" \
- "\tUsage: %s input_file out_putfile\n", argv[0]);
+ /* a sanity check */
+ if ((sizeof(img.header) % 32) != 0) {
+ fprintf(stderr, "ERROR: the SPL header must be a multiple ");
+ fprintf(stderr, "of 32 bytes.\n");
+ return EXIT_FAILURE;
+ }
+
+ /* process optional command line switches */
+ while (argc >= 2 && argv[1][0] == '-') {
+ if (strcmp(argv[1], "--default-dt") == 0) {
+ if (argc >= 3) {
+ default_dt = argv[2];
+ argv += 2;
+ argc -= 2;
+ continue;
+ }
+ fprintf(stderr, "ERROR: no --default-dt arg\n");
+ return EXIT_FAILURE;
+ } else {
+ fprintf(stderr, "ERROR: bad option '%s'\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (argc < 3) {
+ printf("This program converts an input binary file to a sunxi bootable image.\n");
+ printf("\nUsage: %s [options] input_file output_file\n",
+ tool_name);
+ printf("Where [options] may be:\n");
+ printf(" --default-dt arg - 'arg' is the default device tree name\n");
+ printf(" (CONFIG_DEFAULT_DEVICE_TREE).\n");
return EXIT_FAILURE;
}
@@ -122,6 +151,18 @@ int main(int argc, char *argv[])
memcpy(img.header.spl_signature, SPL_SIGNATURE, 3); /* "sunxi" marker */
img.header.spl_signature[3] = SPL_HEADER_VERSION;
+ if (default_dt) {
+ if (strlen(default_dt) + 1 <= sizeof(img.header.string_pool)) {
+ strcpy((char *)img.header.string_pool, default_dt);
+ img.header.dt_name_offset =
+ cpu_to_le32(offsetof(struct boot_file_head,
+ string_pool));
+ } else {
+ printf("WARNING: The SPL header is too small\n");
+ printf(" and has no space to store the dt name.\n");
+ }
+ }
+
gen_check_sum(&img.header);
count = write(fd_out, &img, le32_to_cpu(img.header.length));