Merge branch 'master' of http://git.denx.de/u-boot-sunxi
diff --git a/arch/arm/cpu/armv7/exynos/spl_boot.c b/arch/arm/cpu/armv7/exynos/spl_boot.c
index bc237c9..c7f943e 100644
--- a/arch/arm/cpu/armv7/exynos/spl_boot.c
+++ b/arch/arm/cpu/armv7/exynos/spl_boot.c
@@ -309,4 +309,3 @@
 	while (1)
 		;
 }
-void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {}
diff --git a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
index 86c0e42..e19c7ae 100644
--- a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
@@ -19,7 +19,7 @@
 ENTRY(save_boot_params)
 	ldr	r1, =OMAP_SRAM_SCRATCH_BOOT_PARAMS
 	str	r0, [r1]
-	bx	lr
+	b	save_boot_params_ret
 ENDPROC(save_boot_params)
 
 ENTRY(set_pl310_ctrl_reg)
diff --git a/arch/arm/cpu/armv7/omap3/lowlevel_init.S b/arch/arm/cpu/armv7/omap3/lowlevel_init.S
index 78577b1..80cb263 100644
--- a/arch/arm/cpu/armv7/omap3/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/omap3/lowlevel_init.S
@@ -23,7 +23,7 @@
 	ldr	r5, [r0, #0x4]
 	and	r5, r5, #0xff
 	str	r5, [r4]
-	bx	lr
+	b	save_boot_params_ret
 ENDPROC(save_boot_params)
 #endif
 
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 70048c1..9b49ece 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -31,9 +31,12 @@
  *************************************************************************/
 
 	.globl	reset
+	.globl	save_boot_params_ret
 
 reset:
-	bl	save_boot_params
+	/* Allow the board to save important registers */
+	b	save_boot_params
+save_boot_params_ret:
 	/*
 	 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
 	 * except if in HYP mode already
@@ -96,7 +99,7 @@
  *
  *************************************************************************/
 ENTRY(save_boot_params)
-	bx	lr			@ back to my caller
+	b	save_boot_params_ret		@ back to my caller
 ENDPROC(save_boot_params)
 	.weak	save_boot_params
 
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index 48db744..4bb12ad 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -11,6 +11,7 @@
 obj-y	+= board.o
 obj-y	+= clock.o
 obj-y	+= cpu_info.o
+obj-y	+= dram_helpers.o
 obj-y	+= pinmux.o
 obj-y	+= usbc.o
 obj-$(CONFIG_MACH_SUN6I)	+= prcm.o
@@ -38,7 +39,5 @@
 obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
 obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
-ifdef CONFIG_SPL_FEL
-obj-y	+= start.o
-endif
+obj-y	+= fel_utils.o
 endif
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
index 6e28bcd..c02c015 100644
--- a/arch/arm/cpu/armv7/sunxi/board.c
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -27,6 +27,17 @@
 
 #include <linux/compiler.h>
 
+struct fel_stash {
+	uint32_t sp;
+	uint32_t lr;
+	uint32_t cpsr;
+	uint32_t sctlr;
+	uint32_t vbar;
+	uint32_t cr;
+};
+
+struct fel_stash fel_stash __attribute__((section(".data")));
+
 static int gpio_init(void)
 {
 #if CONFIG_CONS_INDEX == 1 && defined(CONFIG_UART0_PORT_F)
@@ -65,6 +76,12 @@
 	return 0;
 }
 
+void spl_board_load_image(void)
+{
+	debug("Returning to FEL sp=%x, lr=%x\n", fel_stash.sp, fel_stash.lr);
+	return_to_fel(fel_stash.sp, fel_stash.lr);
+}
+
 void s_init(void)
 {
 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
@@ -95,7 +112,34 @@
  */
 u32 spl_boot_device(void)
 {
-	return BOOT_DEVICE_MMC1;
+#ifdef CONFIG_SPL_FEL
+	/*
+	 * This is the legacy compile time configuration for a special FEL
+	 * enabled build. It has many restrictions and can only boot over USB.
+	 */
+	return BOOT_DEVICE_BOARD;
+#else
+	/*
+	 * When booting from the SD card, the "eGON.BT0" signature is expected
+	 * to be found in memory at the address 0x0004 (see the "mksunxiboot"
+	 * tool, which generates this header).
+	 *
+	 * When booting in the FEL mode over USB, this signature is patched in
+	 * memory and replaced with something else by the 'fel' tool. This other
+	 * signature is selected in such a way, that it can't be present in a
+	 * valid bootable SD card image (because the BROM would refuse to
+	 * execute the SPL in this case).
+	 *
+	 * This branch is just making a decision at runtime whether to load
+	 * the main u-boot binary from the SD card (if the "eGON.BT0" signature
+	 * is found) or return to the FEL code in the BROM to wait and receive
+	 * the main u-boot binary over USB.
+	 */
+	if (readl(4) == 0x4E4F4765 && readl(8) == 0x3054422E) /* eGON.BT0 */
+		return BOOT_DEVICE_MMC1;
+	else
+		return BOOT_DEVICE_BOARD;
+#endif
 }
 
 /* No confirmation data available in SPL yet. Hardcode bootmode */
diff --git a/arch/arm/cpu/armv7/sunxi/config.mk b/arch/arm/cpu/armv7/sunxi/config.mk
index 00f5ffc..76ffec9 100644
--- a/arch/arm/cpu/armv7/sunxi/config.mk
+++ b/arch/arm/cpu/armv7/sunxi/config.mk
@@ -1,8 +1,6 @@
 # Build a combined spl + u-boot image
 ifdef CONFIG_SPL
 ifndef CONFIG_SPL_BUILD
-ifndef CONFIG_SPL_FEL
 ALL-y += u-boot-sunxi-with-spl.bin
 endif
 endif
-endif
diff --git a/arch/arm/cpu/armv7/sunxi/dram_helpers.c b/arch/arm/cpu/armv7/sunxi/dram_helpers.c
new file mode 100644
index 0000000..9a94e1b
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/dram_helpers.c
@@ -0,0 +1,37 @@
+/*
+ * DRAM init helper functions
+ *
+ * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/dram.h>
+
+/*
+ * Wait up to 1s for value to be set in given part of reg.
+ */
+void mctl_await_completion(u32 *reg, u32 mask, u32 val)
+{
+	unsigned long tmo = timer_get_us() + 1000000;
+
+	while ((readl(reg) & mask) != val) {
+		if (timer_get_us() > tmo)
+			panic("Timeout initialising DRAM\n");
+	}
+}
+
+/*
+ * Test if memory at offset offset matches memory at begin of DRAM
+ */
+bool mctl_mem_matches(u32 offset)
+{
+	/* Try to write different values to RAM at two addresses */
+	writel(0, CONFIG_SYS_SDRAM_BASE);
+	writel(0xaa55aa55, CONFIG_SYS_SDRAM_BASE + offset);
+	/* Check if the same value is actually observed when reading back */
+	return readl(CONFIG_SYS_SDRAM_BASE) ==
+	       readl(CONFIG_SYS_SDRAM_BASE + offset);
+}
diff --git a/arch/arm/cpu/armv7/sunxi/fel_utils.S b/arch/arm/cpu/armv7/sunxi/fel_utils.S
new file mode 100644
index 0000000..bf00335
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/fel_utils.S
@@ -0,0 +1,42 @@
+/*
+ * Utility functions for FEL mode.
+ *
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <asm/system.h>
+#include <linux/linkage.h>
+
+ENTRY(save_boot_params)
+	ldr	r0, =fel_stash
+	str	sp, [r0, #0]
+	str	lr, [r0, #4]
+	mrs	lr, cpsr		@ Read CPSR
+	str	lr, [r0, #8]
+	mrc	p15, 0, lr, c1, c0, 0	@ Read CP15 SCTLR Register
+	str	lr, [r0, #12]
+	mrc	p15, 0, lr, c12, c0, 0	@ Read VBAR
+	str	lr, [r0, #16]
+	mrc	p15, 0, lr, c1, c0, 0	@ Read CP15 Control Register
+	str	lr, [r0, #20]
+	b	save_boot_params_ret
+ENDPROC(save_boot_params)
+
+ENTRY(return_to_fel)
+	mov	sp, r0
+	mov	lr, r1
+	ldr	r0, =fel_stash
+	ldr	r1, [r0, #20]
+	mcr	p15, 0, r1, c1, c0, 0	@ Write CP15 Control Register
+	ldr	r1, [r0, #16]
+	mcr	p15, 0, r1, c12, c0, 0	@ Write VBAR
+	ldr	r1, [r0, #12]
+	mcr	p15, 0, r1, c1, c0, 0	@ Write CP15 SCTLR Register
+	ldr	r1, [r0, #8]
+	msr	cpsr, r1		@ Write CPSR
+	bx	lr
+ENDPROC(return_to_fel)
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
deleted file mode 100644
index 928b7c1..0000000
--- a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * (C) Copyright 2013
- * Henrik Nordstrom <henrik@henriknordstrom.net>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
-OUTPUT_ARCH(arm)
-ENTRY(s_init)
-SECTIONS
-{
-	. = 0x00002000;
-
-	. = ALIGN(4);
-	.text :
-	{
-		*(.text.s_init)
-		*(.text*)
-	}
-
-	. = ALIGN(4);
-	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
-
-	. = ALIGN(4);
-	.data : {
-		*(.data*)
-	}
-
-	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
-	}
-
-	. = ALIGN(4);
-	. = .;
-
-	. = ALIGN(4);
-	.rel.dyn : {
-		__rel_dyn_start = .;
-		*(.rel*)
-		__rel_dyn_end = .;
-	}
-
-	.dynsym : {
-		__dynsym_start = .;
-		*(.dynsym)
-	}
-
-	. = ALIGN(4);
-	.note.gnu.build-id :
-	{
-		*(.note.gnu.build-id)
-	}
-	_end = .;
-
-	. = ALIGN(4096);
-	.mmutable : {
-		*(.mmutable)
-	}
-
-	.bss_start __rel_dyn_start (OVERLAY) : {
-		KEEP(*(.__bss_start));
-		__bss_base = .;
-	}
-
-	.bss __bss_base (OVERLAY) : {
-		*(.bss*)
-		. = ALIGN(4);
-		__bss_limit = .;
-	}
-
-	.bss_end __bss_limit (OVERLAY) : {
-		KEEP(*(.__bss_end));
-	}
-
-	/DISCARD/ : { *(.dynstr*) }
-	/DISCARD/ : { *(.dynamic*) }
-	/DISCARD/ : { *(.plt*) }
-	/DISCARD/ : { *(.interp*) }
-	/DISCARD/ : { *(.gnu*) }
-	/DISCARD/ : { *(.note*) }
-}
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index 7ff43e6..aedd194 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -25,31 +25,7 @@
 #endif
 
 unsigned long sunxi_dram_init(void);
-
-/*
- * Wait up to 1s for value to be set in given part of reg.
- */
-static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
-{
-	unsigned long tmo = timer_get_us() + 1000000;
-
-	while ((readl(reg) & mask) != val) {
-		if (timer_get_us() > tmo)
-			panic("Timeout initialising DRAM\n");
-	}
-}
-
-/*
- * Test if memory at offset offset matches memory at begin of DRAM
- */
-static inline bool mctl_mem_matches(u32 offset)
-{
-	/* Try to write different values to RAM at two addresses */
-	writel(0, CONFIG_SYS_SDRAM_BASE);
-	writel(0xaa55aa55, CONFIG_SYS_SDRAM_BASE + offset);
-	/* Check if the same value is actually observed when reading back */
-	return readl(CONFIG_SYS_SDRAM_BASE) ==
-	       readl(CONFIG_SYS_SDRAM_BASE + offset);
-}
+void mctl_await_completion(u32 *reg, u32 mask, u32 val);
+bool mctl_mem_matches(u32 offset);
 
 #endif /* _SUNXI_DRAM_H */
diff --git a/arch/arm/include/asm/arch-sunxi/sys_proto.h b/arch/arm/include/asm/arch-sunxi/sys_proto.h
index c3e636e..60a5bd8 100644
--- a/arch/arm/include/asm/arch-sunxi/sys_proto.h
+++ b/arch/arm/include/asm/arch-sunxi/sys_proto.h
@@ -13,4 +13,14 @@
 
 void sdelay(unsigned long);
 
+/* return_to_fel() - Return to BROM from SPL
+ *
+ * This returns back into the BROM after U-Boot SPL has performed its initial
+ * init. It uses the provided lr and sp to do so.
+ *
+ * @lr:		BROM link register value (return address)
+ * @sp:		BROM stack pointer
+ */
+void return_to_fel(uint32_t lr, uint32_t sp);
+
 #endif
diff --git a/arch/arm/include/asm/spl.h b/arch/arm/include/asm/spl.h
index 8acd7cd..17b6f54 100644
--- a/arch/arm/include/asm/spl.h
+++ b/arch/arm/include/asm/spl.h
@@ -26,10 +26,14 @@
 	BOOT_DEVICE_SPI,
 	BOOT_DEVICE_SATA,
 	BOOT_DEVICE_I2C,
+	BOOT_DEVICE_BOARD,
 	BOOT_DEVICE_NONE
 };
 #endif
 
+/* Board-specific load method */
+void spl_board_load_image(void);
+
 /* Linker symbols. */
 extern char __bss_start[], __bss_end[];
 
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 89f2294..7820486 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -142,6 +142,21 @@
 
 #ifndef __ASSEMBLY__
 
+/**
+ * save_boot_params() - Save boot parameters before starting reset sequence
+ *
+ * If you provide this function it will be called immediately U-Boot starts,
+ * both for SPL and U-Boot proper.
+ *
+ * All registers are unchanged from U-Boot entry. No registers need be
+ * preserved.
+ *
+ * This is not a normal C function. There is no stack. Return by branching to
+ * save_boot_params_ret.
+ *
+ * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3);
+ */
+
 #define isb() __asm__ __volatile__ ("" : : : "memory")
 
 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
diff --git a/board/nokia/rx51/lowlevel_init.S b/board/nokia/rx51/lowlevel_init.S
index e252909..9d4ea1b 100644
--- a/board/nokia/rx51/lowlevel_init.S
+++ b/board/nokia/rx51/lowlevel_init.S
@@ -37,7 +37,8 @@
 
 .global save_boot_params
 save_boot_params:
-
+	/* Get return address */
+	ldr	lr, =save_boot_params_ret
 
 /* Copy valid attached kernel to address KERNEL_ADDRESS */
 
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
index 4a21589..3eab81f 100644
--- a/board/sunxi/Kconfig
+++ b/board/sunxi/Kconfig
@@ -149,6 +149,16 @@
 	bool "SPL/FEL mode support"
 	depends on SPL
 	default n
+	help
+	  This enables support for Fast Early Loader (FEL) mode. This
+	  allows U-Boot to be loaded to the board over USB by the on-chip
+	  boot rom. U-Boot should be sent in two parts: SPL first, with
+	  'fel write 0x2000 u-boot-spl.bin; fel exe 0x2000' then U-Boot with
+	  'fel write 0x4a000000 u-boot.bin; fel exe 0x4a000000'. This option
+	  shrinks the amount of SRAM available to SPL, so only enable it if
+	  you need FEL. Note that enabling this option only allows FEL to be
+	  used; it is still possible to boot U-Boot from boot media. U-Boot
+	  SPL detects when it is being loaded using FEL.
 
 config UART0_PORT_F
 	bool "UART0 on MicroSD breakout board"
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index faa413c..9a287d3 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -46,6 +46,11 @@
 F:	board/sunxi/dram_a20_olinuxino_l2.c
 F:	configs/A20-OLinuXino-Lime2_defconfig
 
+AMPE A76 BOARD
+M:	Paul Kocialkowski <contact@paulk.fr>
+S:	Maintained
+F:	configs/Ampe_A76_defconfig
+
 COLOMBUS BOARD
 M:	Maxime Ripard <maxime.ripard@free-electrons.com>
 S:	Maintained
@@ -57,9 +62,7 @@
 S:	Maintained
 F:	include/configs/sun7i.h
 F:	configs/Cubieboard2_defconfig
-F:	configs/Cubieboard2_FEL_defconfig
 F:	configs/Cubietruck_defconfig
-F:	configs/Cubietruck_FEL_defconfig
 
 GEMEI-G9 TABLET
 M:	Priit Laes <plaes@plaes.org>
diff --git a/common/spl/spl.c b/common/spl/spl.c
index daaeb50..ded0f30 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -229,6 +229,11 @@
 		spl_sata_load_image();
 		break;
 #endif
+#ifdef CONFIG_SPL_BOARD_LOAD_IMAGE
+	case BOOT_DEVICE_BOARD:
+		spl_board_load_image();
+		break;
+#endif
 	default:
 #if defined(CONFIG_SPL_SERIAL_SUPPORT) && defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 		puts("SPL: Unsupported Boot Device!\n");
diff --git a/configs/Ampe_A76_defconfig b/configs/Ampe_A76_defconfig
new file mode 100644
index 0000000..2054fc3
--- /dev/null
+++ b/configs/Ampe_A76_defconfig
@@ -0,0 +1,15 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,AXP209_POWER"
+CONFIG_FDTFILE="sun5i-a13-ampe-a76.dtb"
+CONFIG_USB_MUSB_SUNXI=y
+CONFIG_USB0_VBUS_PIN="PG12"
+CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:45,ri:82,up:22,lo:22,hs:1,vs:1,sync:3,vmode:0"
+CONFIG_VIDEO_LCD_POWER="AXP0-0"
+CONFIG_VIDEO_LCD_BL_EN="AXP0-1"
+CONFIG_VIDEO_LCD_BL_PWM="PB2"
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN5I=y
++S:CONFIG_DRAM_CLK=432
++S:CONFIG_DRAM_ZQ=123
++S:CONFIG_DRAM_EMR1=4
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 778916d..4646a3d 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -145,16 +145,6 @@
 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
 }
 
-static void USBC_ForceVbusValidDisable(__iomem void *base)
-{
-	u32 reg_val;
-
-	reg_val = musb_readl(base, USBC_REG_o_ISCR);
-	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
-	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
-	musb_writel(base, USBC_REG_o_ISCR, reg_val);
-}
-
 static void USBC_ForceVbusValidToHigh(__iomem void *base)
 {
 	u32 reg_val;
@@ -248,12 +238,11 @@
 	if (is_host_enabled(musb)) {
 		/* Host mode */
 		USBC_ForceIdToLow(musb->mregs);
-		USBC_ForceVbusValidToHigh(musb->mregs);
 	} else {
 		/* Peripheral mode */
 		USBC_ForceIdToHigh(musb->mregs);
-		USBC_ForceVbusValidDisable(musb->mregs);
 	}
+	USBC_ForceVbusValidToHigh(musb->mregs);
 
 	return 0;
 }
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
index f5f24fc..dbda97e 100644
--- a/drivers/video/sunxi_display.c
+++ b/drivers/video/sunxi_display.c
@@ -46,6 +46,7 @@
 	GraphicDevice graphic_device;
 	enum sunxi_monitor monitor;
 	unsigned int depth;
+	unsigned int fb_size;
 } sunxi_display;
 
 #ifdef CONFIG_VIDEO_HDMI
@@ -1060,6 +1061,11 @@
 	return NULL; /* never reached */
 }
 
+ulong board_get_usable_ram_top(ulong total_size)
+{
+	return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
+}
+
 void *video_hw_init(void)
 {
 	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
@@ -1075,10 +1081,6 @@
 
 	memset(&sunxi_display, 0, sizeof(struct sunxi_display));
 
-	printf("Reserved %dkB of RAM for Framebuffer.\n",
-	       CONFIG_SUNXI_FB_SIZE >> 10);
-	gd->fb_base = gd->ram_top;
-
 	video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
 				 &sunxi_display.depth, &options);
 #ifdef CONFIG_VIDEO_HDMI
@@ -1169,6 +1171,17 @@
 		       mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
 	}
 
+	sunxi_display.fb_size =
+		(mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
+	if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
+		printf("Error need %dkB for fb, but only %dkB is reserved\n",
+		       sunxi_display.fb_size >> 10,
+		       CONFIG_SUNXI_MAX_FB_SIZE >> 10);
+		return NULL;
+	}
+
+	gd->fb_base = gd->bd->bi_dram[0].start +
+		      gd->bd->bi_dram[0].size - sunxi_display.fb_size;
 	sunxi_engines_init();
 	sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
 
@@ -1194,6 +1207,7 @@
 {
 	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
 	int offset, ret;
+	u64 start, size;
 	const char *pipeline = NULL;
 
 #ifdef CONFIG_MACH_SUN4I
@@ -1237,6 +1251,20 @@
 		return 0; /* Keep older kernels working */
 	}
 
+	/*
+	 * Do not report the framebuffer as free RAM to the OS, note we cannot
+	 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
+	 * and e.g. Linux refuses to iomap RAM on ARM, see:
+	 * linux/arch/arm/mm/ioremap.c around line 301.
+	 */
+	start = gd->bd->bi_dram[0].start;
+	size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+	ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
+	if (ret) {
+		eprintf("Cannot setup simplefb: Error reserving memory\n");
+		return ret;
+	}
+
 	ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
 			graphic_device->winSizeX, graphic_device->winSizeY,
 			graphic_device->winSizeX * graphic_device->gdfBytesPP,
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 09889ee..5e88852 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -18,10 +18,8 @@
  */
 #define CONFIG_SUNXI		/* sunxi family */
 #ifdef CONFIG_SPL_BUILD
-#ifndef CONFIG_SPL_FEL
 #define CONFIG_SYS_THUMB_BUILD	/* Thumbs mode to save space in SPL */
 #endif
-#endif
 
 #include <asm/arch/cpu.h>	/* get chip and board defs */
 
@@ -145,10 +143,10 @@
 #define CONFIG_SPL_SERIAL_SUPPORT
 #define CONFIG_SPL_LIBGENERIC_SUPPORT
 
+#define CONFIG_SPL_BOARD_LOAD_IMAGE
+
 #ifdef CONFIG_SPL_FEL
 
-#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds"
-#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7/sunxi"
 #define CONFIG_SPL_TEXT_BASE		0x2000
 #define CONFIG_SPL_MAX_SIZE		0x4000		/* 16 KiB */
 
@@ -206,10 +204,10 @@
 
 #ifdef CONFIG_VIDEO
 /*
- * The amount of RAM that is reserved for the FB. This will not show up as
- * RAM to the kernel, but will be reclaimed by a KMS driver in future.
+ * The amount of RAM to keep free at the top of RAM when relocating u-boot,
+ * to use as framebuffer. This must be a multiple of 4096.
  */
-#define CONFIG_SUNXI_FB_SIZE (9 << 20)
+#define CONFIG_SUNXI_MAX_FB_SIZE (9 << 20)
 
 /* Do we want to initialize a simple FB? */
 #define CONFIG_VIDEO_DT_SIMPLEFB
@@ -227,8 +225,6 @@
 /* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
 #define CONFIG_VGA_AS_SINGLE_DEVICE
 
-#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF)
-
 /* To be able to hook simplefb into dt */
 #ifdef CONFIG_VIDEO_DT_SIMPLEFB
 #define CONFIG_OF_BOARD_SETUP
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index e4b9881..cc189ad 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -154,10 +154,8 @@
 endif
 
 ifdef CONFIG_SUNXI
-ifndef CONFIG_SPL_FEL
 ALL-y	+= $(obj)/sunxi-spl.bin
 endif
-endif
 
 ifeq ($(CONFIG_SYS_SOC),"at91")
 ALL-y	+= boot.bin
diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c
index 1f0fbae..0035f6e 100644
--- a/tools/mksunxiboot.c
+++ b/tools/mksunxiboot.c
@@ -43,19 +43,19 @@
 	uint32_t i;
 	uint32_t sum;
 
-	length = head_p->length;
+	length = le32_to_cpu(head_p->length);
 	if ((length & 0x3) != 0)	/* must 4-byte-aligned */
 		return -1;
 	buf = (uint32_t *)head_p;
-	head_p->check_sum = STAMP_VALUE;	/* fill stamp */
+	head_p->check_sum = cpu_to_le32(STAMP_VALUE);	/* fill stamp */
 	loop = length >> 2;
 
 	/* calculate the sum */
 	for (i = 0, sum = 0; i < loop; i++)
-		sum += buf[i];
+		sum += le32_to_cpu(buf[i]);
 
 	/* write back check sum */
-	head_p->check_sum = sum;
+	head_p->check_sum = cpu_to_le32(sum);
 
 	return 0;
 }
@@ -125,10 +125,12 @@
 	memcpy(img.header.magic, BOOT0_MAGIC, 8);	/* no '0' termination */
 	img.header.length =
 		ALIGN(file_size + sizeof(struct boot_file_head), BLOCK_SIZE);
+	img.header.b_instruction = cpu_to_le32(img.header.b_instruction);
+	img.header.length = cpu_to_le32(img.header.length);
 	gen_check_sum(&img.header);
 
-	count = write(fd_out, &img, img.header.length);
-	if (count != img.header.length) {
+	count = write(fd_out, &img, le32_to_cpu(img.header.length));
+	if (count != le32_to_cpu(img.header.length)) {
 		perror("Writing output");
 		return EXIT_FAILURE;
 	}