Merge git://git.denx.de/u-boot-sunxi

trini: Make Kconfig SPL_xxx entires only show if SPL, so that we don't
get Kconfig errors on platforms without SPL, ie sandbox (without SPL).

Signed-off-by: Tom Rini <trini@konsulko.com>
diff --git a/Kconfig b/Kconfig
index 1b19b7b..bb80ada 100644
--- a/Kconfig
+++ b/Kconfig
@@ -220,18 +220,22 @@
 	  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 @@
 	  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 bcab726..1b7cab2 100644
--- a/Makefile
+++ b/Makefile
@@ -833,6 +833,10 @@
 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 @@
 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 @@
 		$(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 831d0c0..9358397 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 @@
 	 * 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 53d4ed2..f162c14 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -44,8 +44,10 @@
 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 8d9900e..7ced838 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -143,12 +143,16 @@
 	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 1c88173..a512a20 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -72,7 +72,6 @@
 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 @@
 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 5553415..0000000
--- 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 0000000..c492f74
--- /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 4404edb..f79bd5c 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -512,7 +512,6 @@
 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 @@
 #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 @@
 #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 0000000..ecea1b8
--- /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 aae556f..4c42a96 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,41 +56,71 @@
 			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;
-		}
-
-		*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);
-
-		return len;
+		return node;
 	}
 
-#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);
-	}
-#endif
-
 	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;
+	}
+
+	name = fdt_getprop(fit, conf_node, type, &len);
+	if (!name) {
+		debug("cannot find property '%s': %d\n", type, len);
+		return -EINVAL;
+	}
+
+	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;
+		}
+	}
+
+	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;
+	}
+
+	return node;
+}
+
 static int get_aligned_image_offset(struct spl_load_info *info, int offset)
 {
 	/*
@@ -123,19 +159,82 @@
 	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 @@
 	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("%s: Cannot find first image node: %d\n", __func__, node);
+		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 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;
+	/* 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;
+
 	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);
-
-#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
-	board_fit_image_post_process((void **)&src, (size_t *)&data_size);
-#endif
-
-	memcpy(dst, src, data_size);
-
 	/* 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 c3237f5..962bb65 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -48,4 +48,3 @@
 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 92bda600..593e24a 100644
--- a/configs/pine64_plus_defconfig
+++ b/configs/pine64_plus_defconfig
@@ -3,6 +3,7 @@
 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 14e316f..2988a52 100644
--- a/doc/uImage.FIT/howto.txt
+++ b/doc/uImage.FIT/howto.txt
@@ -44,6 +44,27 @@
 	+	     ---------------> 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 0000000..e5551d4
--- /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 997a92c..f042f0d 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 LOW_LEVEL_SRAM_STACK		0x00018000
+#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 CONFIG_SPL_TEXT_BASE		0x40		/* sram start+header */
-#define CONFIG_SPL_MAX_SIZE		0x5fc0		/* 24KB on sun4i/sun7i */
+#define LOW_LEVEL_SRAM_STACK		0x00018000
+#endif /* !CONFIG_ARM64 */
+#else
+#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 182b300..135706f 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -304,7 +304,8 @@
 	$(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 0f0b003..db0f10e 100644
--- a/tools/mksunxiboot.c
+++ b/tools/mksunxiboot.c
@@ -48,8 +48,8 @@
 #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 @@
 	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 @@
 	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));