diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index 9a5a9747c48a4b82380c34f568fb1239be0cb6cd..8f8586295efd76e57f00c07c0214c103e8d99d4b 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -120,8 +120,8 @@ endif
 ifdef CONFIG_ARM64
 OBJCOPYFLAGS += -j .text -j .rodata -j .data -j .u_boot_list -j .rela.dyn
 else
-OBJCOPYFLAGS += -j .text -j .secure_text -j .rodata -j .hash -j .data -j \
-	.got -j .got.plt -j .u_boot_list -j .rel.dyn
+OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
+		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn
 endif
 
 ifdef CONFIG_OF_EMBED
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index ddd8d12d51700f4f2fac80a8e1cc72ffb361203b..0d4bfbc55b313f2506c8c83af71972ca9cb96823 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -19,7 +19,7 @@ endif
 endif
 
 obj-$(CONFIG_ARMV7_NONSEC)	+= nonsec_virt.o virt-v7.o virt-dt.o
-obj-$(CONFIG_ARMV7_PSCI)	+= psci.o
+obj-$(CONFIG_ARMV7_PSCI)	+= psci.o psci-common.o
 
 obj-$(CONFIG_IPROC) += iproc-common/
 obj-$(CONFIG_KONA) += kona-common/
diff --git a/arch/arm/cpu/armv7/ls102xa/psci.S b/arch/arm/cpu/armv7/ls102xa/psci.S
index cf5cd48bcbec037015e422273f6b8a6df292a535..f9b26b43218a53701b742435196b4644a02c61bb 100644
--- a/arch/arm/cpu/armv7/ls102xa/psci.S
+++ b/arch/arm/cpu/armv7/ls102xa/psci.S
@@ -29,16 +29,16 @@
 	@ r2 = target PC
 .globl	psci_cpu_on
 psci_cpu_on:
-	push	{lr}
+	push	{r4, r5, r6, lr}
 
 	@ Clear and Get the correct CPU number
 	@ r1 = 0xf01
-	and	r1, r1, #0xff
+	and	r4, r1, #0xff
 
-	mov	r0, r1
-	bl	psci_get_cpu_stack_top
-	str	r2, [r0]
-	dsb
+	mov	r0, r4
+	mov	r1, r2
+	bl	psci_save_target_pc
+	mov	r1, r4
 
 	@ Get DCFG base address
 	movw	r4, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff)
@@ -101,7 +101,7 @@ holdoff_release:
 	@ Return
 	mov	r0, #ARM_PSCI_RET_SUCCESS
 
-	pop	{lr}
+	pop	{r4, r5, r6, lr}
 	bx	lr
 
 .globl	psci_cpu_off
@@ -111,16 +111,4 @@ psci_cpu_off:
 1:	wfi
 	b	1b
 
-.globl	psci_arch_init
-psci_arch_init:
-	mov	r6, lr
-
-	bl	psci_get_cpu_id
-	bl	psci_get_cpu_stack_top
-	mov	sp, r0
-
-	bx	r6
-
-	.globl psci_text_end
-psci_text_end:
 	.popsection
diff --git a/arch/arm/cpu/armv7/mx7/psci-mx7.c b/arch/arm/cpu/armv7/mx7/psci-mx7.c
index 9a330476cf5f32c9c83444238df3e805b0adbc1d..502552d1718fe32a4ddd45d52984805c9039b14a 100644
--- a/arch/arm/cpu/armv7/mx7/psci-mx7.c
+++ b/arch/arm/cpu/armv7/mx7/psci-mx7.c
@@ -1,9 +1,9 @@
 #include <asm/io.h>
 #include <asm/psci.h>
+#include <asm/secure.h>
 #include <asm/arch/imx-regs.h>
 #include <common.h>
 
-#define __secure __attribute__((section("._secure.text")))
 
 #define GPC_CPU_PGC_SW_PDN_REQ	0xfc
 #define GPC_CPU_PGC_SW_PUP_REQ	0xf0
diff --git a/arch/arm/cpu/armv7/mx7/psci.S b/arch/arm/cpu/armv7/mx7/psci.S
index 34c6ab33f058745993221ec2c1c097a86241fc98..96e88d6184e40b06a67ade00ac67e309b8f094a7 100644
--- a/arch/arm/cpu/armv7/mx7/psci.S
+++ b/arch/arm/cpu/armv7/mx7/psci.S
@@ -9,35 +9,22 @@
 
 	.arch_extension sec
 
-	@ r1 = target CPU
-	@ r2 = target PC
-
-.globl	psci_arch_init
-psci_arch_init:
-	mov	r6, lr
-
-	bl	psci_get_cpu_id
-	bl	psci_get_cpu_stack_top
-	mov	sp, r0
-
-	bx	r6
-
-	@ r1 = target CPU
-	@ r2 = target PC
-
 .globl psci_cpu_on
 psci_cpu_on:
-	push	{lr}
+	push	{r4, r5, lr}
 
+	mov	r4, r0
+	mov	r5, r1
 	mov	r0, r1
-	bl	psci_get_cpu_stack_top
-	str	r2, [r0]
-	dsb
+	mov	r1, r2
+	bl	psci_save_target_pc
 
+	mov	r0, r4
+	mov	r1, r5
 	ldr	r2, =psci_cpu_entry
 	bl	imx_cpu_on
 
-	pop	{pc}
+	pop	{r4, r5, pc}
 
 .globl psci_cpu_off
 psci_cpu_off:
@@ -49,6 +36,4 @@ psci_cpu_off:
 1: 	wfi
 	b 1b
 
-	.globl psci_text_end
-psci_text_end:
 	.popsection
diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S
index b7563edbe6bc0d81891abdd47f62f85b5a1be663..95ce9387b83e972414b6de2d5711a9f40fe097df 100644
--- a/arch/arm/cpu/armv7/nonsec_virt.S
+++ b/arch/arm/cpu/armv7/nonsec_virt.S
@@ -49,8 +49,13 @@ _secure_monitor:
 	mcr	p15, 0, r5, c12, c0, 1
 	isb
 
-	@ Obtain a secure stack, and configure the PSCI backend
+	@ Obtain a secure stack
+	bl	psci_stack_setup
+
+	@ Configure the PSCI backend
+	push	{r0, r1, r2, ip}
 	bl	psci_arch_init
+	pop	{r0, r1, r2, ip}
 #endif
 
 #ifdef CONFIG_ARM_ERRATA_773022
diff --git a/arch/arm/cpu/armv7/psci-common.c b/arch/arm/cpu/armv7/psci-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..d14b6937473f08af0e4dca8733d0c7366383eedf
--- /dev/null
+++ b/arch/arm/cpu/armv7/psci-common.c
@@ -0,0 +1,39 @@
+/*
+ * Common PSCI functions
+ *
+ * Copyright (C) 2016 Chen-Yu Tsai
+ * Author: Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <asm/armv7.h>
+#include <asm/macro.h>
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <linux/linkage.h>
+
+static u32 psci_target_pc[CONFIG_ARMV7_PSCI_NR_CPUS] __secure_data = { 0 };
+
+void __secure psci_save_target_pc(int cpu, u32 pc)
+{
+	psci_target_pc[cpu] = pc;
+	DSB;
+}
+
+u32 __secure psci_get_target_pc(int cpu)
+{
+	return psci_target_pc[cpu];
+}
+
diff --git a/arch/arm/cpu/armv7/psci.S b/arch/arm/cpu/armv7/psci.S
index ab408378fcae329592d03b590dc0205cb2272b2b..350b75ce20e888e3512c9f46f6dbe157f38aafb1 100644
--- a/arch/arm/cpu/armv7/psci.S
+++ b/arch/arm/cpu/armv7/psci.S
@@ -196,29 +196,56 @@ ENTRY(psci_cpu_off_common)
 	bx	lr
 ENDPROC(psci_cpu_off_common)
 
-@ expects CPU ID in r0 and returns stack top in r0
-ENTRY(psci_get_cpu_stack_top)
-	mov	r3, #0x400			@ 1kB of stack per CPU
-	mul	r0, r0, r3
-
-	ldr	r3, =psci_text_end		@ end of monitor text
-	add	r3, r3, #0x2000			@ Skip two pages
-	lsr	r3, r3, #12			@ Align to start of page
-	lsl	r3, r3, #12
-	sub	r3, r3, #4			@ reserve 1 word for target PC
-	sub	r0, r3, r0			@ here's our stack!
-
+@ The stacks are allocated in reverse order, i.e.
+@ the stack for CPU0 has the highest memory address.
+@
+@ --------------------  __secure_stack_end
+@ |  CPU0 target PC  |
+@ |------------------|
+@ |                  |
+@ |    CPU0 stack    |
+@ |                  |
+@ |------------------|  __secure_stack_end - 1KB
+@ |        .         |
+@ |        .         |
+@ |        .         |
+@ |        .         |
+@ --------------------  __secure_stack_start
+@
+@ This expects CPU ID in r0 and returns stack top in r0
+LENTRY(psci_get_cpu_stack_top)
+	@ stack top = __secure_stack_end - (cpuid << ARM_PSCI_STACK_SHIFT)
+	ldr	r3, =__secure_stack_end
+	sub	r0, r3, r0, LSL #ARM_PSCI_STACK_SHIFT
+	sub	r0, r0, #4		@ Save space for target PC
 	bx	lr
 ENDPROC(psci_get_cpu_stack_top)
 
+@ {r0, r1, r2, ip} from _do_nonsec_entry(kernel_entry, 0, machid, r2) in
+@ arch/arm/lib/bootm.c:boot_jump_linux() must remain unchanged across
+@ this function.
+ENTRY(psci_stack_setup)
+	mov	r6, lr
+	mov	r7, r0
+	bl	psci_get_cpu_id		@ CPU ID => r0
+	bl	psci_get_cpu_stack_top	@ stack top => r0
+	mov	sp, r0
+	mov	r0, r7
+	bx	r6
+ENDPROC(psci_stack_setup)
+
+ENTRY(psci_arch_init)
+	mov	pc, lr
+ENDPROC(psci_arch_init)
+.weak psci_arch_init
+
 ENTRY(psci_cpu_entry)
 	bl	psci_enable_smp
 
 	bl	_nonsec_init
 
 	bl	psci_get_cpu_id			@ CPU ID => r0
-	bl	psci_get_cpu_stack_top		@ stack top => r0
-	ldr	r0, [r0]			@ target PC at stack top
+	bl	psci_get_target_pc		@ target PC => r0
 	b	_do_nonsec_entry
 ENDPROC(psci_cpu_entry)
 
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index c2085101685bb28199e38c6e91ea8668027795da..b35b9df4a9d6f7d75a82265a19914946131e1aca 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_MACH_SUN8I_H3)	+= tzpc.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_ARMV7_PSCI)	+= psci.o
-obj-$(CONFIG_ARMV7_PSCI)	+= psci_head.o
 endif
 
 ifdef CONFIG_SPL_BUILD
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
index a118e9d0c4ada1c73001109d013cd84eaf227c73..7ac84065f4ab99fbf822f47984117525396b2e6d 100644
--- a/arch/arm/cpu/armv7/sunxi/psci.c
+++ b/arch/arm/cpu/armv7/sunxi/psci.c
@@ -17,11 +17,11 @@
 #include <asm/gic.h>
 #include <asm/io.h>
 #include <asm/psci.h>
+#include <asm/secure.h>
 #include <asm/system.h>
 
 #include <linux/bitops.h>
 
-#define __secure	__attribute__ ((section ("._secure.text")))
 #define __irq		__attribute__ ((interrupt ("IRQ")))
 
 #define	GICD_BASE	(SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
@@ -209,9 +209,8 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc)
 		(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
 	u32 cpu = (mpidr & 0x3);
 
-	/* store target PC at target CPU stack top */
-	writel(pc, psci_get_cpu_stack_top(cpu));
-	DSB;
+	/* store target PC */
+	psci_save_target_pc(cpu, pc);
 
 	/* Set secondary core power on PC */
 	writel((u32)&psci_cpu_entry, &cpucfg->priv0);
@@ -250,7 +249,7 @@ void __secure psci_cpu_off(void)
 		wfi();
 }
 
-void __secure sunxi_gic_init(void)
+void __secure psci_arch_init(void)
 {
 	u32 reg;
 
diff --git a/arch/arm/cpu/armv7/sunxi/psci_head.S b/arch/arm/cpu/armv7/sunxi/psci_head.S
deleted file mode 100644
index 8fa823d1df3a7e2bf3d1bb0d9b6c421216bdc425..0000000000000000000000000000000000000000
--- a/arch/arm/cpu/armv7/sunxi/psci_head.S
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * Based on code by Carl van Schaik <carl@ok-labs.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-#include <linux/linkage.h>
-
-#include <asm/arch-armv7/generictimer.h>
-#include <asm/gic.h>
-#include <asm/macro.h>
-#include <asm/psci.h>
-#include <asm/arch/cpu.h>
-
-/*
- * Memory layout:
- *
- * SECURE_RAM to text_end :
- *	._secure_text section
- * text_end to ALIGN_PAGE(text_end):
- *	nothing
- * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000)
- *	1kB of stack per CPU (4 CPUs max).
- */
-
-	.pushsection ._secure.text, "ax"
-
-	.arch_extension sec
-
-#define	GICD_BASE		(SUNXI_GIC400_BASE +  0x1000)
-#define	GICC_BASE		(SUNXI_GIC400_BASE +  0x2000)
-
-@ {r0, r1, r2, ip} from _do_nonsec_entry(kernel_entry, 0, machid, r2) in
-@ arch/arm/lib/bootm.c:boot_jump_linux() must remain unchanged across
-@ this function.
-ENTRY(psci_arch_init)
-	mov	r6, lr
-	mov	r7, r0
-	bl	psci_get_cpu_id		@ CPU ID => r0
-	bl	psci_get_cpu_stack_top	@ stack top => r0
-	sub	r0, r0, #4		@ Save space for target PC
-	mov	sp, r0
-	mov	r0, r7
-	mov	lr, r6
-
-	push	{r0, r1, r2, ip, lr}
-	bl	sunxi_gic_init
-	pop	{r0, r1, r2, ip, pc}
-ENDPROC(psci_arch_init)
-
-ENTRY(psci_text_end)
-	.popsection
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 1769b6ea881b2f909a0799237869754fd1c777f3..36c9fd0bd01f36737ed60b3b33d239b7cb860610 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -8,6 +8,7 @@
  */
 
 #include <config.h>
+#include <asm/psci.h>
 
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
@@ -48,34 +49,67 @@ SECTIONS
 
 #ifdef CONFIG_ARMV7_NONSEC
 
+	/* Align the secure section only if we're going to use it in situ */
+	.__secure_start :
+#ifndef CONFIG_ARMV7_SECURE_BASE
+		ALIGN(CONSTANT(COMMONPAGESIZE))
+#endif
+	{
+		KEEP(*(.__secure_start))
+	}
+
 #ifndef CONFIG_ARMV7_SECURE_BASE
 #define CONFIG_ARMV7_SECURE_BASE
 #define __ARMV7_PSCI_STACK_IN_RAM
 #endif
 
-	.__secure_start : {
-		. = ALIGN(0x1000);
-		*(.__secure_start)
-	}
-
 	.secure_text CONFIG_ARMV7_SECURE_BASE :
 		AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
 	{
 		*(._secure.text)
 	}
 
-	. = LOADADDR(.__secure_start) +
-		SIZEOF(.__secure_start) +
-		SIZEOF(.secure_text);
+	.secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text))
+	{
+		*(._secure.data)
+	}
 
+	.secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data),
+			    CONSTANT(COMMONPAGESIZE)) (NOLOAD) :
 #ifdef __ARMV7_PSCI_STACK_IN_RAM
-	/* Align to page boundary and skip 2 pages */
-	. = (. & ~ 0xfff) + 0x2000;
-#undef __ARMV7_PSCI_STACK_IN_RAM
+		AT(ADDR(.secure_stack))
+#else
+		AT(LOADADDR(.secure_data) + SIZEOF(.secure_data))
+#endif
+	{
+		KEEP(*(.__secure_stack_start))
+
+		/* Skip addreses for stack */
+		. = . + CONFIG_ARMV7_PSCI_NR_CPUS * ARM_PSCI_STACK_SIZE;
+
+		/* Align end of stack section to page boundary */
+		. = ALIGN(CONSTANT(COMMONPAGESIZE));
+
+		KEEP(*(.__secure_stack_end))
+
+#ifdef CONFIG_ARMV7_SECURE_MAX_SIZE
+		/*
+		 * We are not checking (__secure_end - __secure_start) here,
+		 * as these are the load addresses, and do not include the
+		 * stack section. Instead, use the end of the stack section
+		 * and the start of the text section.
+		 */
+		ASSERT((. - ADDR(.secure_text)) <= CONFIG_ARMV7_SECURE_MAX_SIZE,
+		       "Error: secure section exceeds secure memory size");
+#endif
+	}
+
+#ifndef __ARMV7_PSCI_STACK_IN_RAM
+	/* Reset VMA but don't allocate space if we have secure SRAM */
+	. = LOADADDR(.secure_stack);
 #endif
 
-	__secure_end_lma = .;
-	.__secure_end : AT(__secure_end_lma) {
+	.__secure_end : AT(ADDR(.__secure_end)) {
 		*(.__secure_end)
 		LONG(0x1d1071c);	/* Must output something to reset LMA */
 	}
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index ef573ec68515c42214b72a79ee919958c6f08c5d..acecb7c3594ea6febf96ec6770d37fd8fbabfe3a 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -242,6 +242,7 @@ dtb-$(CONFIG_MACH_SUN8I_A83T) += \
 	sun8i-a83t-sinovoip-bpi-m3.dtb
 dtb-$(CONFIG_MACH_SUN8I_H3) += \
 	sun8i-h3-orangepi-2.dtb \
+	sun8i-h3-orangepi-lite.dtb \
 	sun8i-h3-orangepi-one.dtb \
 	sun8i-h3-orangepi-pc.dtb \
 	sun8i-h3-orangepi-plus.dtb
diff --git a/arch/arm/dts/sun50i-a64-pine64-plus.dts b/arch/arm/dts/sun50i-a64-pine64-plus.dts
index 549dc15bd5d0000e2260136498dab6ca9045b3fd..389c6096ca149734af69b9d9549b72073841d475 100644
--- a/arch/arm/dts/sun50i-a64-pine64-plus.dts
+++ b/arch/arm/dts/sun50i-a64-pine64-plus.dts
@@ -57,3 +57,16 @@
 		reg = <0x40000000 0x40000000>;
 	};
 };
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii";
+	phy = <&phy1>;
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+	reg = <1>;
+	};
+};
+
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi
index 1bd436f8470b08b19401e75f23a507055f1eecf8..7d0dc76a11f7170f45248bfa8b543ea63b9a24bf 100644
--- a/arch/arm/dts/sun50i-a64.dtsi
+++ b/arch/arm/dts/sun50i-a64.dtsi
@@ -506,6 +506,25 @@
 				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
+
+			rmii_pins: rmii_pins {
+				allwinner,pins = "PD10", "PD11", "PD13", "PD14",
+						 "PD17", "PD18", "PD19", "PD20",
+						 "PD22", "PD23";
+				allwinner,function = "emac";
+				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			rgmii_pins: rgmii_pins {
+				allwinner,pins = "PD8", "PD9", "PD10", "PD11",
+						 "PD12", "PD13", "PD15",
+						 "PD16", "PD17", "PD18", "PD19",
+						 "PD20", "PD21", "PD22", "PD23";
+				allwinner,function = "emac";
+				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
 		};
 
 		ahb_rst: reset@1c202c0 {
@@ -620,5 +639,19 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		emac: ethernet@01c30000 {
+			compatible = "allwinner,sun50i-a64-emac";
+			reg = <0x01c30000 0x2000>, <0x01c00030 0x4>;
+			reg-names = "emac", "syscon";
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&ahb_rst 17>;
+			reset-names = "ahb";
+			clocks = <&bus_gates 17>;
+			clock-names = "ahb";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
 	};
 };
diff --git a/arch/arm/dts/sun8i-h3-orangepi-2.dts b/arch/arm/dts/sun8i-h3-orangepi-2.dts
index f93f5d1695c4b38a05fbc8fdb818e2301e7366e4..d3f8f550a227a6b74982d517cc68b5b9c3a3cf50 100644
--- a/arch/arm/dts/sun8i-h3-orangepi-2.dts
+++ b/arch/arm/dts/sun8i-h3-orangepi-2.dts
@@ -184,3 +184,16 @@
 	usb1_vbus-supply = <&reg_usb1_vbus>;
 	status = "okay";
 };
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii";
+	phy = <&phy1>;
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+};
+
diff --git a/arch/arm/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/dts/sun8i-h3-orangepi-lite.dts
new file mode 100644
index 0000000000000000000000000000000000000000..ac7174914e6377dbd1c27c59affb8c95370d2f30
--- /dev/null
+++ b/arch/arm/dts/sun8i-h3-orangepi-lite.dts
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "Xunlong Orange Pi Lite";
+	compatible = "xunlong,orangepi-lite", "allwinner,sun8i-h3";
+
+	aliases {
+		/* The H3 emac is not used so the wifi is ethernet0 */
+		ethernet1 = &rtl8189ftv;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
+
+		pwr_led {
+			label = "orangepi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		status_led {
+			label = "orangepi:red:status";
+			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	r_gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sw_r_opc>;
+
+		sw4 {
+			label = "sw4";
+			linux,code = <BTN_0>;
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+};
+
+&ir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ir_pins_a>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	/*
+	 * Explicitly define the sdio device, so that we can add an ethernet
+	 * alias for it (which e.g. makes u-boot set a mac-address).
+	 */
+	rtl8189ftv: sdio_wifi@1 {
+		reg = <1>;
+	};
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
+&pio {
+	leds_opc: led_pins@0 {
+		allwinner,pins = "PA15";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&r_pio {
+	leds_r_opc: led_pins@0 {
+		allwinner,pins = "PL10";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	sw_r_opc: key_pins@0 {
+		allwinner,pins = "PL3";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	/* USB VBUS is always on */
+	status = "okay";
+};
diff --git a/arch/arm/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/dts/sun8i-h3-orangepi-pc.dts
index 30ccca019dd23747256b2c90b305b7d667a27287..0a74a9193bbfc06d54efb7a301340c14d5390378 100644
--- a/arch/arm/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/dts/sun8i-h3-orangepi-pc.dts
@@ -173,3 +173,15 @@
 	/* USB VBUS is always on */
 	status = "okay";
 };
+
+&emac {
+	phy = <&phy1>;
+	phy-mode = "mii";
+	allwinner,use-internal-phy;
+	allwinner,leds-active-low;
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+};
diff --git a/arch/arm/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/dts/sun8i-h3-orangepi-plus.dts
index 900ec4fc8c818a660435a048e699007eb9529068..28f74f6ffd1ea119dfcfe99462673f5739f4ac08 100644
--- a/arch/arm/dts/sun8i-h3-orangepi-plus.dts
+++ b/arch/arm/dts/sun8i-h3-orangepi-plus.dts
@@ -40,26 +40,13 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/dts-v1/;
-#include "sun8i-h3.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
+/* The Orange Pi Plus is an extended version of the Orange Pi 2 */
+#include "sun8i-h3-orangepi-2.dts"
 
 / {
-	model = "Xunlong Orange Pi Plus";
+	model = "Xunlong Orange Pi Plus / Plus 2 / Plus 2E";
 	compatible = "xunlong,orangepi-plus", "allwinner,sun8i-h3";
 
-	aliases {
-		serial0 = &uart0;
-	};
-
-	chosen {
-		stdout-path = "serial0:115200n8";
-	};
-
 	reg_usb3_vbus: usb3-vbus {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
@@ -71,75 +58,42 @@
 		enable-active-high;
 		gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
 	};
+};
 
-	leds {
-		compatible = "gpio-leds";
-		pinctrl-names = "default";
-		pinctrl-0 = <&leds_opc>;
-
-		status_led {
-			label = "status:red:user";
-			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
-		};
-	};
-
-	r_leds {
-		compatible = "gpio-leds";
-		pinctrl-names = "default";
-		pinctrl-0 = <&leds_r_opc>;
-
-		tx {
-			label = "pwr:green:user";
-			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
-			default-state = "on";
-		};
-	};
-
-	r_gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "sw4";
-
-		pinctrl-names = "default";
-		pinctrl-0 = <&sw_r_opc>;
+&ehci2 {
+	status = "okay";
+};
 
-		sw4@0 {
-			label = "sw4";
-			linux,code = <BTN_0>;
-			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
-		};
-	};
+&ehci3 {
+	status = "okay";
 };
 
-&pio {
-	leds_opc: led_pins@0 {
-		allwinner,pins = "PA15";
-		allwinner,function = "gpio_out";
-		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
-		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
-	};
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
 };
 
-&r_pio {
-	leds_r_opc: led_pins@0 {
-		allwinner,pins = "PL10";
-		allwinner,function = "gpio_out";
-		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
-		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
-	};
+&mmc2_8bit_pins {
+	/* Increase drive strength for DDR modes */
+	allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+	/* eMMC is missing pull-ups */
+	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
 
-	sw_r_opc: key_pins@0 {
-		allwinner,pins = "PL03";
-		allwinner,function = "gpio_in";
-		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
-		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
-	};
+&ohci1 {
+	status = "okay";
 };
 
-&ehci1 {
+&ohci2 {
 	status = "okay";
 };
 
-&ehci3 {
+&ohci3 {
 	status = "okay";
 };
 
@@ -152,33 +106,6 @@
 	};
 };
 
-&mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
-	vmmc-supply = <&reg_vcc3v3>;
-	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
-	status = "okay";
-};
-
-&reg_usb1_vbus {
-	gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
-	status = "okay";
-};
-
-&uart0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart0_pins_a>;
-	status = "okay";
-};
-
-&usb1_vbus_pin_a {
-	allwinner,pins = "PG13";
-};
-
 &usbphy {
-	usb1_vbus-supply = <&reg_usb1_vbus>;
 	usb3_vbus-supply = <&reg_usb3_vbus>;
-	status = "okay";
 };
diff --git a/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi
index c2f63c50501cd0196b8ef14ae8a4e133f8ca877d..72c0920466a76273b01fca1533c3ed5b99f072a4 100644
--- a/arch/arm/dts/sun8i-h3.dtsi
+++ b/arch/arm/dts/sun8i-h3.dtsi
@@ -501,6 +501,17 @@
 			interrupt-controller;
 			#interrupt-cells = <3>;
 
+			rgmii_pins: rgmii_pins {
+				allwinner,pins = "PD0", "PD1", "PD2", "PD3",
+						 "PD4", "PD5", "PD7",
+						 "PD8", "PD9", "PD10",
+						 "PD12", "PD13", "PD15",
+						 "PD16", "PD17";
+				allwinner,function = "emac";
+				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PA4", "PA5";
 				allwinner,function = "uart0";
@@ -530,6 +541,16 @@
 				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
+
+			mmc2_8bit_pins: mmc2_8bit {
+				allwinner,pins = "PC5", "PC6", "PC8",
+						 "PC9", "PC10", "PC11",
+						 "PC12", "PC13", "PC14",
+						 "PC15", "PC16";
+				allwinner,function = "mmc2";
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
 		};
 
 		ahb_rst: reset@01c202c0 {
@@ -616,6 +637,20 @@
 			status = "disabled";
 		};
 
+		emac: ethernet@01c30000 {
+			compatible = "allwinner,sun8i-h3-emac";
+			reg = <0x01c30000 0x2000>, <0x01c00030 0x4>;
+			reg-names = "emac", "syscon";
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&ahb_rst 17>, <&ahb_rst 66>;
+			reset-names = "ahb", "ephy";
+			clocks = <&bus_gates 17>, <&bus_gates 128>;
+			clock-names = "ahb", "ephy";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		gic: interrupt-controller@01c81000 {
 			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
 			reg = <0x01c81000 0x1000>,
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index c2e72f5a86b2595609d856d75a2ce18a1a87021a..d4dff1e3463e5a532aa79645ecd08dc8d2651209 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -40,7 +40,8 @@ struct sunxi_ccm_reg {
 	u32 ahb_gate1;		/* 0x64 ahb module clock gating 1 */
 	u32 apb1_gate;		/* 0x68 apb1 module clock gating */
 	u32 apb2_gate;		/* 0x6c apb2 module clock gating */
-	u32 reserved9[4];
+	u32 bus_gate4;          /* 0x70 gate 4 module clock gating */
+	u8 res3[0xc];
 	u32 nand0_clk_cfg;	/* 0x80 nand0 clock control */
 	u32 nand1_clk_cfg;	/* 0x84 nand1 clock control */
 	u32 sd0_clk_cfg;	/* 0x88 sd0 clock control */
@@ -387,6 +388,7 @@ struct sunxi_ccm_reg {
 #define AHB_RESET_OFFSET_LCD0		4
 
 /* ahb_reset2 offsets */
+#define AHB_RESET_OFFSET_EPHY		2
 #define AHB_RESET_OFFSET_LVDS		0
 
 /* apb2 reset */
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
index c5e9d88bab5c974ce040a5555fd676dbd0860f48..cd009d7ccc2332075943956bf1387c42be5bb704 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
@@ -87,7 +87,8 @@
 #define SUNXI_KEYPAD_BASE		0x01c23000
 #define SUNXI_TZPC_BASE			0x01c23400
 
-#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3)
+#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3) || \
+defined(CONFIG_MACH_SUN50I)
 /* SID address space starts at 0x01c1400, but e-fuse is at offset 0x200 */
 #define SUNXI_SID_BASE			0x01c14200
 #else
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 1ace54802273643df8fbb91aeb00ec651e9c2d35..bff7d1453f12d71624ffdd08f25ee66b36fda398 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -141,6 +141,7 @@ enum sunxi_gpio_number {
 /* GPIO pin function config */
 #define SUNXI_GPIO_INPUT	0
 #define SUNXI_GPIO_OUTPUT	1
+#define SUNXI_GPIO_DISABLE	7
 
 #define SUNXI_GPA_EMAC		2
 #define SUN6I_GPA_GMAC		2
@@ -162,8 +163,10 @@ enum sunxi_gpio_number {
 #define SUN50I_GPB_UART0	4
 
 #define SUNXI_GPC_NAND		2
+#define SUNXI_GPC_SPI0		3
 #define SUNXI_GPC_SDC2		3
 #define SUN6I_GPC_SDC3		4
+#define SUN50I_GPC_SPI0		4
 
 #define SUN8I_GPD_SDC1		3
 #define SUNXI_GPD_LCD0		2
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
index 3da360b177d9b2a0369745f253a759652aac32ca..cb52e648731ce9687b7c9cb472463fd54d8da38d 100644
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -127,5 +127,4 @@ struct sunxi_mmc {
 #define SUNXI_MMC_COMMON_RESET			(1 << 18)
 
 struct mmc *sunxi_mmc_init(int sdc_no);
-int sunxi_mmc_has_egon_boot_signature(struct mmc *mmc);
 #endif /* _SUNXI_MMC_H */
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index ec73379735c93257b209ad0ec7dba7da71eebdbe..5d7ab559ef90b9211aafa59ada93435a2beebce2 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -51,7 +51,14 @@ struct boot_file_head {
 		uint8_t spl_signature[4];
 	};
 	uint32_t fel_script_address;
-	uint32_t reserved1[3];
+	/*
+	 * If the fel_uEnv_length member below is set to a non-zero value,
+	 * it specifies the size (byte count) of data at fel_script_address.
+	 * At the same time this indicates that the data is in uEnv.txt
+	 * compatible format, ready to be imported via "env import -t".
+	 */
+	uint32_t fel_uEnv_length;
+	uint32_t reserved1[2];
 	uint32_t boot_media;		/* written here by the boot ROM */
 	uint32_t reserved2[5];		/* padding, align to 64 bytes */
 };
diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h
index 423fc701116614ea94c56fae77c299ca2124d5d3..a20702e612b1b0a9fd31cc5a5eb141e1fa0894b1 100644
--- a/arch/arm/include/asm/armv7.h
+++ b/arch/arm/include/asm/armv7.h
@@ -126,6 +126,8 @@ void _smp_pen(void);
 
 extern char __secure_start[];
 extern char __secure_end[];
+extern char __secure_stack_start[];
+extern char __secure_stack_end[];
 
 #endif /* CONFIG_ARMV7_NONSEC */
 
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
index bc5edda73f0076a670214b348bdbc41f976ba720..7ba7ce306ab1f7d6e46a06b4f4c34401277aec46 100644
--- a/arch/arm/include/asm/psci.h
+++ b/arch/arm/include/asm/psci.h
@@ -47,12 +47,19 @@
 #define ARM_PSCI_0_2_FN_SYSTEM_OFF		ARM_PSCI_0_2_FN(8)
 #define ARM_PSCI_0_2_FN_SYSTEM_RESET		ARM_PSCI_0_2_FN(9)
 
+/* 1KB stack per core */
+#define ARM_PSCI_STACK_SHIFT	10
+#define ARM_PSCI_STACK_SIZE	(1 << ARM_PSCI_STACK_SHIFT)
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
+/* These 2 helper functions assume cpu < CONFIG_ARMV7_PSCI_NR_CPUS */
+u32 psci_get_target_pc(int cpu);
+void psci_save_target_pc(int cpu, u32 pc);
+
 void psci_cpu_entry(void);
 u32 psci_get_cpu_id(void);
-u32 psci_get_cpu_stack_top(int cpu);
 void psci_cpu_off_common(void);
 
 int psci_update_dt(void *fdt);
diff --git a/arch/arm/include/asm/secure.h b/arch/arm/include/asm/secure.h
index effdb1858d88759b945c8e6f45eadad6666c6266..5a403bc0f153593163f3883692233ac1386ff81d 100644
--- a/arch/arm/include/asm/secure.h
+++ b/arch/arm/include/asm/secure.h
@@ -3,6 +3,9 @@
 
 #include <config.h>
 
+#define __secure __attribute__ ((section ("._secure.text")))
+#define __secure_data __attribute__ ((section ("._secure.data")))
+
 #ifdef CONFIG_ARMV7_SECURE_BASE
 /*
  * Warning, horror ahead.
diff --git a/arch/arm/lib/sections.c b/arch/arm/lib/sections.c
index 6a9452241834c68d329834ccd10ae5e73c31c023..952e8ae49bf4ae9b19c755b5240791f31e1127ec 100644
--- a/arch/arm/lib/sections.c
+++ b/arch/arm/lib/sections.c
@@ -27,6 +27,8 @@ char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
 char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
 char __secure_start[0] __attribute__((section(".__secure_start")));
 char __secure_end[0] __attribute__((section(".__secure_end")));
+char __secure_stack_start[0] __attribute__((section(".__secure_stack_start")));
+char __secure_stack_end[0] __attribute__((section(".__secure_stack_end")));
 char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
 char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
 char __efi_runtime_rel_start[0] __attribute__((section(".__efi_runtime_rel_start")));
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 66e028ec1467d657a1c408f6bd80b9b8dd50cc45..06a1986efdb3acec662b49626f2841598608d5bd 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -203,7 +203,8 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 u32 spl_boot_device(void)
 {
-	__maybe_unused struct mmc *mmc0, *mmc1;
+	int boot_source;
+
 	/*
 	 * When booting from the SD card or NAND memory, the "eGON.BT0"
 	 * signature is expected to be found in memory at the address 0x0004
@@ -223,27 +224,19 @@ u32 spl_boot_device(void)
 	if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
 		return BOOT_DEVICE_BOARD;
 
-	/* The BROM will try to boot from mmc0 first, so try that first. */
-#ifdef CONFIG_MMC
-	mmc_initialize(gd->bd);
-	mmc0 = find_mmc_device(0);
-	if (sunxi_mmc_has_egon_boot_signature(mmc0))
+	boot_source = readb(SPL_ADDR + 0x28);
+	switch (boot_source) {
+	case SUNXI_BOOTED_FROM_MMC0:
 		return BOOT_DEVICE_MMC1;
-#endif
-
-	/* Fallback to booting NAND if enabled. */
-	if (IS_ENABLED(CONFIG_SPL_NAND_SUPPORT))
+	case SUNXI_BOOTED_FROM_NAND:
 		return BOOT_DEVICE_NAND;
-
-#ifdef CONFIG_MMC
-	if (CONFIG_MMC_SUNXI_SLOT_EXTRA == 2) {
-		mmc1 = find_mmc_device(1);
-		if (sunxi_mmc_has_egon_boot_signature(mmc1))
-			return BOOT_DEVICE_MMC2;
+	case SUNXI_BOOTED_FROM_MMC2:
+		return BOOT_DEVICE_MMC2;
+	case SUNXI_BOOTED_FROM_SPI:
+		return BOOT_DEVICE_SPI;
 	}
-#endif
 
-	panic("Could not determine boot source\n");
+	panic("Unknown boot source %d\n", boot_source);
 	return -1;		/* Never reached */
 }
 
diff --git a/arch/arm/mach-tegra/psci.S b/arch/arm/mach-tegra/psci.S
index b836da1c0ed79b958c5544cfeff36a55b90314fe..645d08fa0bd84b7287e4137f8d2dd47a6bd99987 100644
--- a/arch/arm/mach-tegra/psci.S
+++ b/arch/arm/mach-tegra/psci.S
@@ -61,9 +61,6 @@ ENTRY(psci_arch_init)
 	ldrne	r7, [r5]
 	mcrne	p15, 0, r7, c14, c0, 0	@ write CNTFRQ to CPU1..3
 
-	bl	psci_get_cpu_stack_top	@ stack top => r0
-	mov	sp, r0
-
 	bx	r6
 ENDPROC(psci_arch_init)
 
@@ -88,12 +85,13 @@ _loop:	wfi
 ENDPROC(psci_cpu_off)
 
 ENTRY(psci_cpu_on)
-	push	{lr}
+	push	{r4, r5, r6, lr}
 
+	mov	r4, r1
 	mov	r0, r1
-	bl	psci_get_cpu_stack_top	@ get stack top of target CPU
-	str	r2, [r0]		@ store target PC at stack top
-	dsb
+	mov	r1, r2
+	bl	psci_save_target_pc	@ store target PC
+	mov	r1, r4
 
 	ldr	r6, =TEGRA_RESET_EXCEPTION_VECTOR
 	ldr	r5, =psci_cpu_entry
@@ -106,9 +104,7 @@ ENTRY(psci_cpu_on)
 	str	r5, [r6, r2]
 
 	mov	r0, #ARM_PSCI_RET_SUCCESS	@ Return PSCI_RET_SUCCESS
-	pop	{pc}
+	pop	{r4, r5, r6, pc}
 ENDPROC(psci_cpu_on)
 
-	.globl psci_text_end
-psci_text_end:
 	.popsection
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index d2dfebef46bd8f4cfef96dd907c627aa6c10115f..0dc84f6aabdf79c9f052137519bebbf3c4e81dab 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -56,6 +56,7 @@ F:	configs/ga10h_v1_1_defconfig
 F:	configs/gt90h_v4_defconfig
 F:	configs/inet86dz_defconfig
 F:	configs/orangepi_2_defconfig
+F:	configs/orangepi_lite_defconfig
 F:	configs/orangepi_one_defconfig
 F:	configs/orangepi_pc_defconfig
 F:	configs/orangepi_plus_defconfig
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index c8bf3169d12b94cb300f1505bdd2ddb0b3e835a4..f6e28b050d318c6d0079853bb3e2db437efe755e 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -20,12 +20,15 @@
 #include <asm/arch/dram.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
+#include <asm/arch/spl.h>
 #include <asm/arch/usb_phy.h>
 #ifndef CONFIG_ARM64
 #include <asm/armv7.h>
 #endif
 #include <asm/gpio.h>
 #include <asm/io.h>
+#include <environment.h>
+#include <libfdt.h>
 #include <nand.h>
 #include <net.h>
 #include <sy8106a.h>
@@ -366,8 +369,7 @@ int board_mmc_init(bd_t *bis)
 	 * are searched there first. Note we only do this for u-boot proper,
 	 * not for the SPL, see spl_boot_device().
 	 */
-	if (!sunxi_mmc_has_egon_boot_signature(mmc0) &&
-	    sunxi_mmc_has_egon_boot_signature(mmc1)) {
+	if (readb(SPL_ADDR + 0x28) == SUNXI_BOOTED_FROM_MMC2) {
 		/* Booting from emmc / mmc2, swap */
 		mmc0->block_dev.devnum = 1;
 		mmc1->block_dev.devnum = 0;
@@ -571,9 +573,6 @@ void get_board_serial(struct tag_serialnr *serialnr)
 }
 #endif
 
-#if !defined(CONFIG_SPL_BUILD)
-#include <asm/arch/spl.h>
-
 /*
  * Check the SPL header for the "sunxi" variant. If found: parse values
  * that might have been passed by the loader ("fel" utility), and update
@@ -582,50 +581,67 @@ void get_board_serial(struct tag_serialnr *serialnr)
 static void parse_spl_header(const uint32_t spl_addr)
 {
 	struct boot_file_head *spl = (void *)(ulong)spl_addr;
-	if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) == 0) {
-		uint8_t spl_header_version = spl->spl_signature[3];
-		if (spl_header_version == SPL_HEADER_VERSION) {
-			if (spl->fel_script_address)
-				setenv_hex("fel_scriptaddr",
-					   spl->fel_script_address);
-			return;
-		}
+	if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
+		return; /* signature mismatch, no usable header */
+
+	uint8_t spl_header_version = spl->spl_signature[3];
+	if (spl_header_version != SPL_HEADER_VERSION) {
 		printf("sunxi SPL version mismatch: expected %u, got %u\n",
 		       SPL_HEADER_VERSION, spl_header_version);
+		return;
 	}
+	if (!spl->fel_script_address)
+		return;
+
+	if (spl->fel_uEnv_length != 0) {
+		/*
+		 * data is expected in uEnv.txt compatible format, so "env
+		 * import -t" the string(s) at fel_script_address right away.
+		 */
+		himport_r(&env_htab, (char *)spl->fel_script_address,
+			  spl->fel_uEnv_length, '\n', H_NOCLEAR, 0, 0, NULL);
+		return;
+	}
+	/* otherwise assume .scr format (mkimage-type script) */
+	setenv_hex("fel_scriptaddr", spl->fel_script_address);
 }
-#endif
 
-#ifdef CONFIG_MISC_INIT_R
-int misc_init_r(void)
+/*
+ * Note this function gets called multiple times.
+ * It must not make any changes to env variables which already exist.
+ */
+static void setup_environment(const void *fdt)
 {
 	char serial_string[17] = { 0 };
 	unsigned int sid[4];
 	uint8_t mac_addr[6];
-	int ret;
-
-#if !defined(CONFIG_SPL_BUILD)
-	setenv("fel_booted", NULL);
-	setenv("fel_scriptaddr", NULL);
-	/* determine if we are running in FEL mode */
-	if (!is_boot0_magic(SPL_ADDR + 4)) { /* eGON.BT0 */
-		setenv("fel_booted", "1");
-		parse_spl_header(SPL_ADDR);
-	}
-#endif
+	char ethaddr[16];
+	int i, ret;
 
 	ret = sunxi_get_sid(sid);
 	if (ret == 0 && sid[0] != 0 && sid[3] != 0) {
-		if (!getenv("ethaddr")) {
+		for (i = 0; i < 4; i++) {
+			sprintf(ethaddr, "ethernet%d", i);
+			if (!fdt_get_alias(fdt, ethaddr))
+				continue;
+
+			if (i == 0)
+				strcpy(ethaddr, "ethaddr");
+			else
+				sprintf(ethaddr, "eth%daddr", i);
+
+			if (getenv(ethaddr))
+				continue;
+
 			/* Non OUI / registered MAC address */
-			mac_addr[0] = 0x02;
+			mac_addr[0] = (i << 4) | 0x02;
 			mac_addr[1] = (sid[0] >>  0) & 0xff;
 			mac_addr[2] = (sid[3] >> 24) & 0xff;
 			mac_addr[3] = (sid[3] >> 16) & 0xff;
 			mac_addr[4] = (sid[3] >>  8) & 0xff;
 			mac_addr[5] = (sid[3] >>  0) & 0xff;
 
-			eth_setenv_enetaddr("ethaddr", mac_addr);
+			eth_setenv_enetaddr(ethaddr, mac_addr);
 		}
 
 		if (!getenv("serial#")) {
@@ -635,6 +651,21 @@ int misc_init_r(void)
 			setenv("serial#", serial_string);
 		}
 	}
+}
+
+int misc_init_r(void)
+{
+	__maybe_unused int ret;
+
+	setenv("fel_booted", NULL);
+	setenv("fel_scriptaddr", NULL);
+	/* determine if we are running in FEL mode */
+	if (!is_boot0_magic(SPL_ADDR + 4)) { /* eGON.BT0 */
+		setenv("fel_booted", "1");
+		parse_spl_header(SPL_ADDR);
+	}
+
+	setup_environment(gd->fdt_blob);
 
 #ifndef CONFIG_MACH_SUN9I
 	ret = sunxi_usb_phy_probe();
@@ -645,12 +676,17 @@ int misc_init_r(void)
 
 	return 0;
 }
-#endif
 
 int ft_board_setup(void *blob, bd_t *bd)
 {
 	int __maybe_unused r;
 
+	/*
+	 * Call setup_environment again in case the boot fdt has
+	 * ethernet aliases the u-boot copy does not have.
+	 */
+	setup_environment(blob);
+
 #ifdef CONFIG_VIDEO_DT_SIMPLEFB
 	r = sunxi_simplefb_setup(blob);
 	if (r)
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 12aed02935648eaa43d1faeb465d75aecb48160e..14320fe75c10aa673122c1ef0a08664dd37a8784 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -270,7 +270,7 @@ struct boot_device_name boot_name_table[] = {
 #ifdef CONFIG_SPL_YMODEM_SUPPORT
 	{ BOOT_DEVICE_UART, "UART" },
 #endif
-#ifdef CONFIG_SPL_SPI_SUPPORT
+#if defined(CONFIG_SPL_SPI_SUPPORT) || defined(CONFIG_SPL_SPI_FLASH_SUPPORT)
 	{ BOOT_DEVICE_SPI, "SPI" },
 #endif
 #ifdef CONFIG_SPL_ETH_SUPPORT
@@ -346,7 +346,7 @@ static int spl_load_image(u32 boot_device)
 	case BOOT_DEVICE_UART:
 		return spl_ymodem_load_image();
 #endif
-#ifdef CONFIG_SPL_SPI_SUPPORT
+#if defined(CONFIG_SPL_SPI_SUPPORT) || defined(CONFIG_SPL_SPI_FLASH_SUPPORT)
 	case BOOT_DEVICE_SPI:
 		return spl_spi_load_image();
 #endif
diff --git a/configs/orangepi_lite_defconfig b/configs/orangepi_lite_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..417e4f6a0af2632bb47b2ab8b0cc4ba0cdca9d4d
--- /dev/null
+++ b/configs/orangepi_lite_defconfig
@@ -0,0 +1,15 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN8I_H3=y
+CONFIG_DRAM_CLK=672
+CONFIG_DRAM_ZQ=3881979
+CONFIG_DRAM_ODT_EN=y
+CONFIG_MMC0_CD_PIN="PF6"
+# CONFIG_VIDEO is not set
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-orangepi-lite"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_USB_EHCI_HCD=y
diff --git a/configs/orangepi_pc_defconfig b/configs/orangepi_pc_defconfig
index 7eaa795b32e44d93f340b7ae07c6aa6c78dff2cd..43ec927ced712d0b129e61181018c1d469d153b1 100644
--- a/configs/orangepi_pc_defconfig
+++ b/configs/orangepi_pc_defconfig
@@ -4,6 +4,8 @@ CONFIG_MACH_SUN8I_H3=y
 CONFIG_DRAM_CLK=624
 CONFIG_DRAM_ZQ=3881979
 CONFIG_DRAM_ODT_EN=y
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
 # CONFIG_VIDEO is not set
 CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-orangepi-pc"
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
@@ -13,3 +15,4 @@ CONFIG_SPL=y
 # CONFIG_CMD_FPGA is not set
 CONFIG_SY8106A_POWER=y
 CONFIG_USB_EHCI_HCD=y
+CONFIG_SUN8I_EMAC=y
diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig
index 0bf79bfd3346f7e5e978ff7057923af39cfe511a..5c97de1dccb89fd8766d395558218fb6324afe67 100644
--- a/configs/pine64_plus_defconfig
+++ b/configs/pine64_plus_defconfig
@@ -10,3 +10,4 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-plus"
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_FPGA is not set
 CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK=y
+CONFIG_SUN8I_EMAC=y
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index ce2dc4ae41c363c6d2c597e54d66227dde2b9a04..5d8abdc8974cf8bde3924138c983a4b7cfe379bf 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -269,18 +269,18 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
 	unsigned i;
 	unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
 	unsigned byte_cnt = data->blocksize * data->blocks;
-	unsigned timeout_msecs = byte_cnt >> 8;
-	if (timeout_msecs < 2000)
-		timeout_msecs = 2000;
+	unsigned timeout_usecs = (byte_cnt >> 8) * 1000;
+	if (timeout_usecs < 2000000)
+		timeout_usecs = 2000000;
 
 	/* Always read / write data through the CPU */
 	setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
 
 	for (i = 0; i < (byte_cnt >> 2); i++) {
 		while (readl(&mmchost->reg->status) & status_bit) {
-			if (!timeout_msecs--)
+			if (!timeout_usecs--)
 				return -1;
-			udelay(1000);
+			udelay(1);
 		}
 
 		if (reading)
@@ -445,23 +445,6 @@ static int sunxi_mmc_getcd(struct mmc *mmc)
 	return !gpio_get_value(cd_pin);
 }
 
-int sunxi_mmc_has_egon_boot_signature(struct mmc *mmc)
-{
-	char *buf = malloc(512);
-	int valid_signature = 0;
-
-	if (buf == NULL)
-		panic("Failed to allocate memory\n");
-
-	if (mmc_getcd(mmc) && mmc_init(mmc) == 0 &&
-	    mmc->block_dev.block_read(&mmc->block_dev, 16, 1, buf) == 1 &&
-	    strncmp(&buf[4], "eGON.BT0", 8) == 0)
-		valid_signature = 1;
-
-	free(buf);
-	return valid_signature;
-}
-
 static const struct mmc_ops sunxi_mmc_ops = {
 	.send_cmd	= sunxi_mmc_send_cmd,
 	.set_ios	= sunxi_mmc_set_ios,
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 3f7433cbc214b76a7120886f858047d64b51744c..1f23c8e34e6f0579df67694924164d72f3e10f1a 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -128,4 +128,16 @@ config SPI_FLASH_MTD
 
 	  If unsure, say N
 
+if SPL
+
+config SPL_SPI_SUNXI
+	bool "Support for SPI Flash on Allwinner SoCs in SPL"
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_H3 || MACH_SUN50I
+	---help---
+	Enable support for SPI Flash. This option allows SPL to read from
+	sunxi SPI Flash. It uses the same method as the boot ROM, so does
+	not need any extra configuration.
+
+endif
+
 endmenu # menu "SPI Flash Support"
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index c665836f9560ed4c3f34f601041a4da35bf71a6f..6f47a66f400654c9456570f160e474aa71d1b3c5 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_SPI_LOAD)	+= spi_spl_load.o
 obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o
+obj-$(CONFIG_SPL_SPI_SUNXI)	+= sunxi_spi_spl.o
 endif
 
 obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o
diff --git a/drivers/mtd/spi/sunxi_spi_spl.c b/drivers/mtd/spi/sunxi_spi_spl.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3ded5b4e81434d9810b99ba27a5913ed9bfd455
--- /dev/null
+++ b/drivers/mtd/spi/sunxi_spi_spl.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SPL_OS_BOOT
+#error CONFIG_SPL_OS_BOOT is not supported yet
+#endif
+
+/*
+ * This is a very simple U-Boot image loading implementation, trying to
+ * replicate what the boot ROM is doing when loading the SPL. Because we
+ * know the exact pins where the SPI Flash is connected and also know
+ * that the Read Data Bytes (03h) command is supported, the hardware
+ * configuration is very simple and we don't need the extra flexibility
+ * of the SPI framework. Moreover, we rely on the default settings of
+ * the SPI controler hardware registers and only adjust what needs to
+ * be changed. This is good for the code size and this implementation
+ * adds less than 400 bytes to the SPL.
+ *
+ * There are two variants of the SPI controller in Allwinner SoCs:
+ * A10/A13/A20 (sun4i variant) and everything else (sun6i variant).
+ * Both of them are supported.
+ *
+ * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are
+ * supported at the moment.
+ */
+
+/*****************************************************************************/
+/* SUN4I variant of the SPI controller                                       */
+/*****************************************************************************/
+
+#define SUN4I_SPI0_CCTL             (0x01C05000 + 0x1C)
+#define SUN4I_SPI0_CTL              (0x01C05000 + 0x08)
+#define SUN4I_SPI0_RX               (0x01C05000 + 0x00)
+#define SUN4I_SPI0_TX               (0x01C05000 + 0x04)
+#define SUN4I_SPI0_FIFO_STA         (0x01C05000 + 0x28)
+#define SUN4I_SPI0_BC               (0x01C05000 + 0x20)
+#define SUN4I_SPI0_TC               (0x01C05000 + 0x24)
+
+#define SUN4I_CTL_ENABLE            BIT(0)
+#define SUN4I_CTL_MASTER            BIT(1)
+#define SUN4I_CTL_TF_RST            BIT(8)
+#define SUN4I_CTL_RF_RST            BIT(9)
+#define SUN4I_CTL_XCH               BIT(10)
+
+/*****************************************************************************/
+/* SUN6I variant of the SPI controller                                       */
+/*****************************************************************************/
+
+#define SUN6I_SPI0_CCTL             (0x01C68000 + 0x24)
+#define SUN6I_SPI0_GCR              (0x01C68000 + 0x04)
+#define SUN6I_SPI0_TCR              (0x01C68000 + 0x08)
+#define SUN6I_SPI0_FIFO_STA         (0x01C68000 + 0x1C)
+#define SUN6I_SPI0_MBC              (0x01C68000 + 0x30)
+#define SUN6I_SPI0_MTC              (0x01C68000 + 0x34)
+#define SUN6I_SPI0_BCC              (0x01C68000 + 0x38)
+#define SUN6I_SPI0_TXD              (0x01C68000 + 0x200)
+#define SUN6I_SPI0_RXD              (0x01C68000 + 0x300)
+
+#define SUN6I_CTL_ENABLE            BIT(0)
+#define SUN6I_CTL_MASTER            BIT(1)
+#define SUN6I_CTL_SRST              BIT(31)
+#define SUN6I_TCR_XCH               BIT(31)
+
+/*****************************************************************************/
+
+#define CCM_AHB_GATING0             (0x01C20000 + 0x60)
+#define CCM_SPI0_CLK                (0x01C20000 + 0xA0)
+#define SUN6I_BUS_SOFT_RST_REG0     (0x01C20000 + 0x2C0)
+
+#define AHB_RESET_SPI0_SHIFT        20
+#define AHB_GATE_OFFSET_SPI0        20
+
+#define SPI0_CLK_DIV_BY_2           0x1000
+#define SPI0_CLK_DIV_BY_4           0x1001
+
+/*****************************************************************************/
+
+/*
+ * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
+ * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
+ */
+static void spi0_pinmux_setup(unsigned int pin_function)
+{
+	unsigned int pin;
+
+	for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++)
+		sunxi_gpio_set_cfgpin(pin, pin_function);
+
+	if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I))
+		sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function);
+	else
+		sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
+}
+
+/*
+ * Setup 6 MHz from OSC24M (because the BROM is doing the same).
+ */
+static void spi0_enable_clock(void)
+{
+	/* Deassert SPI0 reset on SUN6I */
+	if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+		setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+			     (1 << AHB_RESET_SPI0_SHIFT));
+
+	/* Open the SPI0 gate */
+	setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+	/* Divide by 4 */
+	writel(SPI0_CLK_DIV_BY_4, IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
+				  SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL);
+	/* 24MHz from OSC24M */
+	writel((1 << 31), CCM_SPI0_CLK);
+
+	if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+		/* Enable SPI in the master mode and do a soft reset */
+		setbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+					     SUN6I_CTL_ENABLE |
+					     SUN6I_CTL_SRST);
+		/* Wait for completion */
+		while (readl(SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
+			;
+	} else {
+		/* Enable SPI in the master mode and reset FIFO */
+		setbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+					     SUN4I_CTL_ENABLE |
+					     SUN4I_CTL_TF_RST |
+					     SUN4I_CTL_RF_RST);
+	}
+}
+
+static void spi0_disable_clock(void)
+{
+	/* Disable the SPI0 controller */
+	if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+		clrbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+					     SUN6I_CTL_ENABLE);
+	else
+		clrbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+					     SUN4I_CTL_ENABLE);
+
+	/* Disable the SPI0 clock */
+	writel(0, CCM_SPI0_CLK);
+
+	/* Close the SPI0 gate */
+	clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+	/* Assert SPI0 reset on SUN6I */
+	if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+		clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+			     (1 << AHB_RESET_SPI0_SHIFT));
+}
+
+static int spi0_init(void)
+{
+	unsigned int pin_function = SUNXI_GPC_SPI0;
+	if (IS_ENABLED(CONFIG_MACH_SUN50I))
+		pin_function = SUN50I_GPC_SPI0;
+
+	spi0_pinmux_setup(pin_function);
+	spi0_enable_clock();
+}
+
+static void spi0_deinit(void)
+{
+	/* New SoCs can disable pins, older could only set them as input */
+	unsigned int pin_function = SUNXI_GPIO_INPUT;
+	if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+		pin_function = SUNXI_GPIO_DISABLE;
+
+	spi0_disable_clock();
+	spi0_pinmux_setup(pin_function);
+}
+
+/*****************************************************************************/
+
+#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
+
+static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
+				 u32 spi_ctl_reg,
+				 u32 spi_ctl_xch_bitmask,
+				 u32 spi_fifo_reg,
+				 u32 spi_tx_reg,
+				 u32 spi_rx_reg,
+				 u32 spi_bc_reg,
+				 u32 spi_tc_reg,
+				 u32 spi_bcc_reg)
+{
+	writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
+	writel(4, spi_tc_reg);           /* Transfer counter (bytes to send) */
+	if (spi_bcc_reg)
+		writel(4, spi_bcc_reg);  /* SUN6I also needs this */
+
+	/* Send the Read Data Bytes (03h) command header */
+	writeb(0x03, spi_tx_reg);
+	writeb((u8)(addr >> 16), spi_tx_reg);
+	writeb((u8)(addr >> 8), spi_tx_reg);
+	writeb((u8)(addr), spi_tx_reg);
+
+	/* Start the data transfer */
+	setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
+
+	/* Wait until everything is received in the RX FIFO */
+	while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
+		;
+
+	/* Skip 4 bytes */
+	readl(spi_rx_reg);
+
+	/* Read the data */
+	while (bufsize-- > 0)
+		*buf++ = readb(spi_rx_reg);
+
+	/* tSHSL time is up to 100 ns in various SPI flash datasheets */
+	udelay(1);
+}
+
+static void spi0_read_data(void *buf, u32 addr, u32 len)
+{
+	u8 *buf8 = buf;
+	u32 chunk_len;
+
+	while (len > 0) {
+		chunk_len = len;
+		if (chunk_len > SPI_READ_MAX_SIZE)
+			chunk_len = SPI_READ_MAX_SIZE;
+
+		if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+			sunxi_spi0_read_data(buf8, addr, chunk_len,
+					     SUN6I_SPI0_TCR,
+					     SUN6I_TCR_XCH,
+					     SUN6I_SPI0_FIFO_STA,
+					     SUN6I_SPI0_TXD,
+					     SUN6I_SPI0_RXD,
+					     SUN6I_SPI0_MBC,
+					     SUN6I_SPI0_MTC,
+					     SUN6I_SPI0_BCC);
+		} else {
+			sunxi_spi0_read_data(buf8, addr, chunk_len,
+					     SUN4I_SPI0_CTL,
+					     SUN4I_CTL_XCH,
+					     SUN4I_SPI0_FIFO_STA,
+					     SUN4I_SPI0_TX,
+					     SUN4I_SPI0_RX,
+					     SUN4I_SPI0_BC,
+					     SUN4I_SPI0_TC,
+					     0);
+		}
+
+		len  -= chunk_len;
+		buf8 += chunk_len;
+		addr += chunk_len;
+	}
+}
+
+/*****************************************************************************/
+
+int spl_spi_load_image(void)
+{
+	int err;
+	struct image_header *header;
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+
+	spi0_init();
+
+	spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40);
+	err = spl_parse_image_header(header);
+	if (err)
+		return err;
+
+	spi0_read_data((void *)spl_image.load_addr, CONFIG_SYS_SPI_U_BOOT_OFFS,
+		       spl_image.size);
+
+	spi0_deinit();
+	return 0;
+}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c1cb689ccf337338d0e5d76e473313102c56bddf..88d8e83906a10b314db1d4730b4e9be8e3dcf896 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -152,6 +152,15 @@ config RTL8169
 	  This driver supports Realtek 8169 series gigabit ethernet family of
 	  PCI/PCIe chipsets/adapters.
 
+config SUN8I_EMAC
+        bool "Allwinner Sun8i Ethernet MAC support"
+        depends on DM_ETH
+        select PHYLIB
+        help
+          This driver supports the  Allwinner based SUN8I/SUN50I Ethernet MAC.
+	  It can be found in H3/A64/A83T based SoCs and compatible with both
+	  External and Internal PHY's.
+
 config XILINX_AXIEMAC
 	depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP)
 	select PHYLIB
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 57025921698028fe6e9d8af831e4a0875df0098c..a4485266d45732a66279fbc32bcdee23632e2552 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_E1000) += e1000.o
 obj-$(CONFIG_E1000_SPI) += e1000_spi.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
 obj-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o
+obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
 obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_EP93XX) += ep93xx_eth.o
 obj-$(CONFIG_ETHOC) += ethoc.o
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
new file mode 100644
index 0000000000000000000000000000000000000000..4bed50d66808c2c505c0f9d0cff51577952a5602
--- /dev/null
+++ b/drivers/net/sun8i_emac.c
@@ -0,0 +1,789 @@
+/*
+ * (C) Copyright 2016
+ * Author: Amit Singh Tomar, amittomer25@gmail.com
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Ethernet driver for H3/A64/A83T based SoC's
+ *
+ * It is derived from the work done by
+ * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS!
+ *
+*/
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <common.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <net.h>
+
+#define SCTL_EMAC_TX_CLK_SRC_MII	BIT(0)
+#define SCTL_EMAC_EPIT_MII		BIT(2)
+#define SCTL_EMAC_CLK_SEL		BIT(18) /* 25 Mhz */
+
+#define MDIO_CMD_MII_BUSY		BIT(0)
+#define MDIO_CMD_MII_WRITE		BIT(1)
+
+#define MDIO_CMD_MII_PHY_REG_ADDR_MASK	0x000001f0
+#define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT	4
+#define MDIO_CMD_MII_PHY_ADDR_MASK	0x0001f000
+#define MDIO_CMD_MII_PHY_ADDR_SHIFT	12
+
+#define CONFIG_TX_DESCR_NUM	32
+#define CONFIG_RX_DESCR_NUM	32
+#define CONFIG_ETH_BUFSIZE	2024
+
+#define TX_TOTAL_BUFSIZE	(CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
+#define RX_TOTAL_BUFSIZE	(CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
+
+#define H3_EPHY_DEFAULT_VALUE	0x58000
+#define H3_EPHY_DEFAULT_MASK	GENMASK(31, 15)
+#define H3_EPHY_ADDR_SHIFT	20
+#define REG_PHY_ADDR_MASK	GENMASK(4, 0)
+#define H3_EPHY_LED_POL		BIT(17)	/* 1: active low, 0: active high */
+#define H3_EPHY_SHUTDOWN	BIT(16)	/* 1: shutdown, 0: power up */
+#define H3_EPHY_SELECT		BIT(15) /* 1: internal PHY, 0: external PHY */
+
+#define SC_RMII_EN		BIT(13)
+#define SC_EPIT			BIT(2) /* 1: RGMII, 0: MII */
+#define SC_ETCS_MASK		GENMASK(1, 0)
+#define SC_ETCS_EXT_GMII	0x1
+#define SC_ETCS_INT_GMII	0x2
+
+#define CONFIG_MDIO_TIMEOUT	(3 * CONFIG_SYS_HZ)
+
+#define AHB_GATE_OFFSET_EPHY	0
+
+#if defined(CONFIG_MACH_SUN8I_H3)
+#define SUN8I_GPD8_GMAC		2
+#else
+#define SUN8I_GPD8_GMAC		4
+#endif
+
+/* H3/A64 EMAC Register's offset */
+#define EMAC_CTL0		0x00
+#define EMAC_CTL1		0x04
+#define EMAC_INT_STA		0x08
+#define EMAC_INT_EN		0x0c
+#define EMAC_TX_CTL0		0x10
+#define EMAC_TX_CTL1		0x14
+#define EMAC_TX_FLOW_CTL	0x1c
+#define EMAC_TX_DMA_DESC	0x20
+#define EMAC_RX_CTL0		0x24
+#define EMAC_RX_CTL1		0x28
+#define EMAC_RX_DMA_DESC	0x34
+#define EMAC_MII_CMD		0x48
+#define EMAC_MII_DATA		0x4c
+#define EMAC_ADDR0_HIGH		0x50
+#define EMAC_ADDR0_LOW		0x54
+#define EMAC_TX_DMA_STA		0xb0
+#define EMAC_TX_CUR_DESC	0xb4
+#define EMAC_TX_CUR_BUF		0xb8
+#define EMAC_RX_DMA_STA		0xc0
+#define EMAC_RX_CUR_DESC	0xc4
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum emac_variant {
+	A83T_EMAC = 1,
+	H3_EMAC,
+	A64_EMAC,
+};
+
+struct emac_dma_desc {
+	u32 status;
+	u32 st;
+	u32 buf_addr;
+	u32 next;
+} __aligned(ARCH_DMA_MINALIGN);
+
+struct emac_eth_dev {
+	struct emac_dma_desc rx_chain[CONFIG_TX_DESCR_NUM];
+	struct emac_dma_desc tx_chain[CONFIG_RX_DESCR_NUM];
+	char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+	char txbuffer[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+
+	u32 interface;
+	u32 phyaddr;
+	u32 link;
+	u32 speed;
+	u32 duplex;
+	u32 phy_configured;
+	u32 tx_currdescnum;
+	u32 rx_currdescnum;
+	u32 addr;
+	u32 tx_slot;
+	bool use_internal_phy;
+
+	enum emac_variant variant;
+	void *mac_reg;
+	phys_addr_t sysctl_reg;
+	struct phy_device *phydev;
+	struct mii_dev *bus;
+};
+
+static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct emac_eth_dev *priv = bus->priv;
+	ulong start;
+	u32 miiaddr = 0;
+	int timeout = CONFIG_MDIO_TIMEOUT;
+
+	miiaddr &= ~MDIO_CMD_MII_WRITE;
+	miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+	miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
+		MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+
+	miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
+
+	miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
+		MDIO_CMD_MII_PHY_ADDR_MASK;
+
+	miiaddr |= MDIO_CMD_MII_BUSY;
+
+	writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
+
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
+		if (!(readl(priv->mac_reg + EMAC_MII_CMD) & MDIO_CMD_MII_BUSY))
+			return readl(priv->mac_reg + EMAC_MII_DATA);
+		udelay(10);
+	};
+
+	return -1;
+}
+
+static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			    u16 val)
+{
+	struct emac_eth_dev *priv = bus->priv;
+	ulong start;
+	u32 miiaddr = 0;
+	int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
+
+	miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+	miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
+		MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+
+	miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
+	miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
+		MDIO_CMD_MII_PHY_ADDR_MASK;
+
+	miiaddr |= MDIO_CMD_MII_WRITE;
+	miiaddr |= MDIO_CMD_MII_BUSY;
+
+	writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
+	writel(val, priv->mac_reg + EMAC_MII_DATA);
+
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
+		if (!(readl(priv->mac_reg + EMAC_MII_CMD) &
+					MDIO_CMD_MII_BUSY)) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	};
+
+	return ret;
+}
+
+static int _sun8i_write_hwaddr(struct emac_eth_dev *priv, u8 *mac_id)
+{
+	u32 macid_lo, macid_hi;
+
+	macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
+		(mac_id[3] << 24);
+	macid_hi = mac_id[4] + (mac_id[5] << 8);
+
+	writel(macid_hi, priv->mac_reg + EMAC_ADDR0_HIGH);
+	writel(macid_lo, priv->mac_reg + EMAC_ADDR0_LOW);
+
+	return 0;
+}
+
+static void sun8i_adjust_link(struct emac_eth_dev *priv,
+			      struct phy_device *phydev)
+{
+	u32 v;
+
+	v = readl(priv->mac_reg + EMAC_CTL0);
+
+	if (phydev->duplex)
+		v |= BIT(0);
+	else
+		v &= ~BIT(0);
+
+	v &= ~0x0C;
+
+	switch (phydev->speed) {
+	case 1000:
+		break;
+	case 100:
+		v |= BIT(2);
+		v |= BIT(3);
+		break;
+	case 10:
+		v |= BIT(3);
+		break;
+	}
+	writel(v, priv->mac_reg + EMAC_CTL0);
+}
+
+static int sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 *reg)
+{
+	if (priv->use_internal_phy) {
+		/* H3 based SoC's that has an Internal 100MBit PHY
+		 * needs to be configured and powered up before use
+		*/
+		*reg &= ~H3_EPHY_DEFAULT_MASK;
+		*reg |=  H3_EPHY_DEFAULT_VALUE;
+		*reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT;
+		*reg &= ~H3_EPHY_SHUTDOWN;
+		*reg |= H3_EPHY_SELECT;
+	} else
+		/* This is to select External Gigabit PHY on
+		 * the boards with H3 SoC.
+		*/
+		*reg &= ~H3_EPHY_SELECT;
+
+	return 0;
+}
+
+static int sun8i_emac_set_syscon(struct emac_eth_dev *priv)
+{
+	int ret;
+	u32 reg;
+
+	reg = readl(priv->sysctl_reg);
+
+	if (priv->variant == H3_EMAC) {
+		ret = sun8i_emac_set_syscon_ephy(priv, &reg);
+		if (ret)
+			return ret;
+	}
+
+	reg &= ~(SC_ETCS_MASK | SC_EPIT);
+	if (priv->variant == H3_EMAC || priv->variant == A64_EMAC)
+		reg &= ~SC_RMII_EN;
+
+	switch (priv->interface) {
+	case PHY_INTERFACE_MODE_MII:
+		/* default */
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+		reg |= SC_EPIT | SC_ETCS_INT_GMII;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		if (priv->variant == H3_EMAC ||
+		    priv->variant == A64_EMAC) {
+			reg |= SC_RMII_EN | SC_ETCS_EXT_GMII;
+		break;
+		}
+		/* RMII not supported on A83T */
+	default:
+		debug("%s: Invalid PHY interface\n", __func__);
+		return -EINVAL;
+	}
+
+	writel(reg, priv->sysctl_reg);
+
+	return 0;
+}
+
+static int sun8i_phy_init(struct emac_eth_dev *priv, void *dev)
+{
+	struct phy_device *phydev;
+
+	phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+	if (!phydev)
+		return -ENODEV;
+
+	phy_connect_dev(phydev, dev);
+
+	priv->phydev = phydev;
+	phy_config(priv->phydev);
+
+	return 0;
+}
+
+static void rx_descs_init(struct emac_eth_dev *priv)
+{
+	struct emac_dma_desc *desc_table_p = &priv->rx_chain[0];
+	char *rxbuffs = &priv->rxbuffer[0];
+	struct emac_dma_desc *desc_p;
+	u32 idx;
+
+	/* flush Rx buffers */
+	flush_dcache_range((uintptr_t)rxbuffs, (ulong)rxbuffs +
+			RX_TOTAL_BUFSIZE);
+
+	for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
+		desc_p = &desc_table_p[idx];
+		desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE]
+			;
+		desc_p->next = (uintptr_t)&desc_table_p[idx + 1];
+		desc_p->st |= CONFIG_ETH_BUFSIZE;
+		desc_p->status = BIT(31);
+	}
+
+	/* Correcting the last pointer of the chain */
+	desc_p->next = (uintptr_t)&desc_table_p[0];
+
+	flush_dcache_range((uintptr_t)priv->rx_chain,
+			   (uintptr_t)priv->rx_chain +
+			sizeof(priv->rx_chain));
+
+	writel((uintptr_t)&desc_table_p[0], (priv->mac_reg + EMAC_RX_DMA_DESC));
+	priv->rx_currdescnum = 0;
+}
+
+static void tx_descs_init(struct emac_eth_dev *priv)
+{
+	struct emac_dma_desc *desc_table_p = &priv->tx_chain[0];
+	char *txbuffs = &priv->txbuffer[0];
+	struct emac_dma_desc *desc_p;
+	u32 idx;
+
+	for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
+		desc_p = &desc_table_p[idx];
+		desc_p->buf_addr = (uintptr_t)&txbuffs[idx * CONFIG_ETH_BUFSIZE]
+			;
+		desc_p->next = (uintptr_t)&desc_table_p[idx + 1];
+		desc_p->status = (1 << 31);
+		desc_p->st = 0;
+	}
+
+	/* Correcting the last pointer of the chain */
+	desc_p->next =  (uintptr_t)&desc_table_p[0];
+
+	/* Flush all Tx buffer descriptors */
+	flush_dcache_range((uintptr_t)priv->tx_chain,
+			   (uintptr_t)priv->tx_chain +
+			sizeof(priv->tx_chain));
+
+	writel((uintptr_t)&desc_table_p[0], priv->mac_reg + EMAC_TX_DMA_DESC);
+	priv->tx_currdescnum = 0;
+}
+
+static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr)
+{
+	u32 reg, v;
+	int timeout = 100;
+
+	reg = readl((priv->mac_reg + EMAC_CTL1));
+
+	if (!(reg & 0x1)) {
+		/* Soft reset MAC */
+		setbits_le32((priv->mac_reg + EMAC_CTL1), 0x1);
+		do {
+			reg = readl(priv->mac_reg + EMAC_CTL1);
+		} while ((reg & 0x01) != 0 &&  (--timeout));
+		if (!timeout) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+	}
+
+	/* Rewrite mac address after reset */
+	_sun8i_write_hwaddr(priv, enetaddr);
+
+	v = readl(priv->mac_reg + EMAC_TX_CTL1);
+	/* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/
+	v |= BIT(1);
+	writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+	v = readl(priv->mac_reg + EMAC_RX_CTL1);
+	/* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a
+	 * complete frame has been written to RX DMA FIFO
+	 */
+	v |= BIT(1);
+	writel(v, priv->mac_reg + EMAC_RX_CTL1);
+
+	/* DMA */
+	writel(8 << 24, priv->mac_reg + EMAC_CTL1);
+
+	/* Initialize rx/tx descriptors */
+	rx_descs_init(priv);
+	tx_descs_init(priv);
+
+	/* PHY Start Up */
+	genphy_parse_link(priv->phydev);
+
+	sun8i_adjust_link(priv, priv->phydev);
+
+	/* Start RX DMA */
+	v = readl(priv->mac_reg + EMAC_RX_CTL1);
+	v |= BIT(30);
+	writel(v, priv->mac_reg + EMAC_RX_CTL1);
+	/* Start TX DMA */
+	v = readl(priv->mac_reg + EMAC_TX_CTL1);
+	v |= BIT(30);
+	writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+	/* Enable RX/TX */
+	setbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31));
+	setbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31));
+
+	return 0;
+}
+
+static int parse_phy_pins(struct udevice *dev)
+{
+	int offset;
+	const char *pin_name;
+	int drive, pull, i;
+
+	offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+				       "pinctrl-0");
+	if (offset < 0) {
+		printf("WARNING: emac: cannot find pinctrl-0 node\n");
+		return offset;
+	}
+
+	drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
+					     "allwinner,drive", 4);
+	pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
+					    "allwinner,pull", 0);
+	for (i = 0; ; i++) {
+		int pin;
+
+		if (fdt_get_string_index(gd->fdt_blob, offset,
+					 "allwinner,pins", i, &pin_name))
+			break;
+		if (pin_name[0] != 'P')
+			continue;
+		pin = (pin_name[1] - 'A') << 5;
+		if (pin >= 26 << 5)
+			continue;
+		pin += simple_strtol(&pin_name[2], NULL, 10);
+
+		sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC);
+		sunxi_gpio_set_drv(pin, drive);
+		sunxi_gpio_set_pull(pin, pull);
+	}
+
+	if (!i) {
+		printf("WARNING: emac: cannot find allwinner,pins property\n");
+		return -2;
+	}
+
+	return 0;
+}
+
+static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp)
+{
+	u32 status, desc_num = priv->rx_currdescnum;
+	struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
+	int length = -EAGAIN;
+	int good_packet = 1;
+	uintptr_t desc_start = (uintptr_t)desc_p;
+	uintptr_t desc_end = desc_start +
+		roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
+
+	ulong data_start = (uintptr_t)desc_p->buf_addr;
+	ulong data_end;
+
+	/* Invalidate entire buffer descriptor */
+	invalidate_dcache_range(desc_start, desc_end);
+
+	status = desc_p->status;
+
+	/* Check for DMA own bit */
+	if (!(status & BIT(31))) {
+		length = (desc_p->status >> 16) & 0x3FFF;
+
+		if (length < 0x40) {
+			good_packet = 0;
+			debug("RX: Bad Packet (runt)\n");
+		}
+
+		data_end = data_start + length;
+		/* Invalidate received data */
+		invalidate_dcache_range(rounddown(data_start,
+						  ARCH_DMA_MINALIGN),
+					roundup(data_end,
+						ARCH_DMA_MINALIGN));
+		if (good_packet) {
+			if (length > CONFIG_ETH_BUFSIZE) {
+				printf("Received packet is too big (len=%d)\n",
+				       length);
+				return -EMSGSIZE;
+			}
+			*packetp = (uchar *)(ulong)desc_p->buf_addr;
+			return length;
+		}
+	}
+
+	return length;
+}
+
+static int _sun8i_emac_eth_send(struct emac_eth_dev *priv, void *packet,
+				int len)
+{
+	u32 v, desc_num = priv->tx_currdescnum;
+	struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num];
+	uintptr_t desc_start = (uintptr_t)desc_p;
+	uintptr_t desc_end = desc_start +
+		roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
+
+	uintptr_t data_start = (uintptr_t)desc_p->buf_addr;
+	uintptr_t data_end = data_start +
+		roundup(len, ARCH_DMA_MINALIGN);
+
+	/* Invalidate entire buffer descriptor */
+	invalidate_dcache_range(desc_start, desc_end);
+
+	desc_p->st = len;
+	/* Mandatory undocumented bit */
+	desc_p->st |= BIT(24);
+
+	memcpy((void *)data_start, packet, len);
+
+	/* Flush data to be sent */
+	flush_dcache_range(data_start, data_end);
+
+	/* frame end */
+	desc_p->st |= BIT(30);
+	desc_p->st |= BIT(31);
+
+	/*frame begin */
+	desc_p->st |= BIT(29);
+	desc_p->status = BIT(31);
+
+	/*Descriptors st and status field has changed, so FLUSH it */
+	flush_dcache_range(desc_start, desc_end);
+
+	/* Move to next Descriptor and wrap around */
+	if (++desc_num >= CONFIG_TX_DESCR_NUM)
+		desc_num = 0;
+	priv->tx_currdescnum = desc_num;
+
+	/* Start the DMA */
+	v = readl(priv->mac_reg + EMAC_TX_CTL1);
+	v |= BIT(31);/* mandatory */
+	v |= BIT(30);/* mandatory */
+	writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+	return 0;
+}
+
+static int sun8i_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	return _sun8i_write_hwaddr(priv, pdata->enetaddr);
+}
+
+static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
+{
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (priv->use_internal_phy) {
+		/* Set clock gating for ephy */
+		setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY));
+
+		/* Set Tx clock source as MII with rate 25 MZ */
+		setbits_le32(priv->sysctl_reg, SCTL_EMAC_TX_CLK_SRC_MII |
+				SCTL_EMAC_EPIT_MII | SCTL_EMAC_CLK_SEL);
+		/* Deassert EPHY */
+		setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY));
+	}
+
+	/* Set clock gating for emac */
+	setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC));
+
+	/* Set EMAC clock */
+	setbits_le32(&ccm->axi_gate, (BIT(1) | BIT(0)));
+
+	/* De-assert EMAC */
+	setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC));
+}
+
+static int sun8i_mdio_init(const char *name, struct  emac_eth_dev *priv)
+{
+	struct mii_dev *bus = mdio_alloc();
+
+	if (!bus) {
+		debug("Failed to allocate MDIO bus\n");
+		return -ENOMEM;
+	}
+
+	bus->read = sun8i_mdio_read;
+	bus->write = sun8i_mdio_write;
+	snprintf(bus->name, sizeof(bus->name), name);
+	bus->priv = (void *)priv;
+
+	return  mdio_register(bus);
+}
+
+static int sun8i_emac_eth_start(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+
+	return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr);
+}
+
+static int sun8i_emac_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	return _sun8i_emac_eth_send(priv, packet, length);
+}
+
+static int sun8i_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	return _sun8i_eth_recv(priv, packetp);
+}
+
+static int _sun8i_free_pkt(struct emac_eth_dev *priv)
+{
+	u32 desc_num = priv->rx_currdescnum;
+	struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
+	uintptr_t desc_start = (uintptr_t)desc_p;
+	uintptr_t desc_end = desc_start +
+		roundup(sizeof(u32), ARCH_DMA_MINALIGN);
+
+	/* Make the current descriptor valid again */
+	desc_p->status |= BIT(31);
+
+	/* Flush Status field of descriptor */
+	flush_dcache_range(desc_start, desc_end);
+
+	/* Move to next desc and wrap-around condition. */
+	if (++desc_num >= CONFIG_RX_DESCR_NUM)
+		desc_num = 0;
+	priv->rx_currdescnum = desc_num;
+
+	return 0;
+}
+
+static int sun8i_eth_free_pkt(struct udevice *dev, uchar *packet,
+			      int length)
+{
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	return _sun8i_free_pkt(priv);
+}
+
+static void sun8i_emac_eth_stop(struct udevice *dev)
+{
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	/* Stop Rx/Tx transmitter */
+	clrbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31));
+	clrbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31));
+
+	/* Stop TX DMA */
+	clrbits_le32(priv->mac_reg + EMAC_TX_CTL1, BIT(30));
+
+	phy_shutdown(priv->phydev);
+}
+
+static int sun8i_emac_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+
+	priv->mac_reg = (void *)pdata->iobase;
+
+	sun8i_emac_board_setup(priv);
+
+	sun8i_mdio_init(dev->name, priv);
+	priv->bus = miiphy_get_dev_by_name(dev->name);
+
+	sun8i_emac_set_syscon(priv);
+
+	return sun8i_phy_init(priv, dev);
+}
+
+static const struct eth_ops sun8i_emac_eth_ops = {
+	.start                  = sun8i_emac_eth_start,
+	.write_hwaddr           = sun8i_eth_write_hwaddr,
+	.send                   = sun8i_emac_eth_send,
+	.recv                   = sun8i_emac_eth_recv,
+	.free_pkt               = sun8i_eth_free_pkt,
+	.stop                   = sun8i_emac_eth_stop,
+};
+
+static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct emac_eth_dev *priv = dev_get_priv(dev);
+	const char *phy_mode;
+	int offset = 0;
+
+	pdata->iobase = dev_get_addr_name(dev, "emac");
+	priv->sysctl_reg = dev_get_addr_name(dev, "syscon");
+
+	pdata->phy_interface = -1;
+	priv->phyaddr = -1;
+	priv->use_internal_phy = false;
+
+	offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+				       "phy");
+	if (offset > 0)
+		priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+					       -1);
+
+	phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	printf("phy interface%d\n", pdata->phy_interface);
+
+	if (pdata->phy_interface == -1) {
+		debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+		return -EINVAL;
+	}
+
+	priv->variant = dev_get_driver_data(dev);
+
+	if (!priv->variant) {
+		printf("%s: Missing variant '%s'\n", __func__,
+		       (char *)priv->variant);
+		return -EINVAL;
+	}
+
+	if (priv->variant == H3_EMAC) {
+		if (fdt_getprop(gd->fdt_blob, dev->of_offset,
+				"allwinner,use-internal-phy", NULL))
+			priv->use_internal_phy = true;
+	}
+
+	priv->interface = pdata->phy_interface;
+
+	if (!priv->use_internal_phy)
+		parse_phy_pins(dev);
+
+	return 0;
+}
+
+static const struct udevice_id sun8i_emac_eth_ids[] = {
+	{.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC },
+	{.compatible = "allwinner,sun50i-a64-emac",
+		.data = (uintptr_t)A64_EMAC },
+	{.compatible = "allwinner,sun8i-a83t-emac",
+		.data = (uintptr_t)A83T_EMAC },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_sun8i_emac) = {
+	.name   = "eth_sun8i_emac",
+	.id     = UCLASS_ETH,
+	.of_match = sun8i_emac_eth_ids,
+	.ofdata_to_platdata = sun8i_emac_eth_ofdata_to_platdata,
+	.probe  = sun8i_emac_eth_probe,
+	.ops    = &sun8i_emac_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct emac_eth_dev),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h
index 953c0880501d8bc21e5ce5a195529b9f5bbb1bf5..2b172a50730a49f1a330dd67eaa4c5cd4862ab42 100644
--- a/include/configs/jetson-tk1.h
+++ b/include/configs/jetson-tk1.h
@@ -61,6 +61,7 @@
 #include "tegra-common-post.h"
 
 #define CONFIG_ARMV7_PSCI			1
+#define CONFIG_ARMV7_PSCI_NR_CPUS		4
 /* Reserve top 1M for secure RAM */
 #define CONFIG_ARMV7_SECURE_BASE		0xfff00000
 #define CONFIG_ARMV7_SECURE_RESERVE_SIZE	0x00100000
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index db684d25582cc9790c6ae2fabb6ed3bbddd2fee9..eb444ebd59e21b0807b14388fb34bc09fc8b1a3f 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -10,6 +10,7 @@
 #define CONFIG_LS102XA
 
 #define CONFIG_ARMV7_PSCI
+#define CONFIG_ARMV7_PSCI_NR_CPUS	CONFIG_MAX_CPUS
 
 #define CONFIG_SYS_FSL_CLK
 
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index 0fb28eff557434265edcaa1f756a60cb7998713a..616aebb4e91400c57eea52808285e2641d8c6abf 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -10,6 +10,7 @@
 #define CONFIG_LS102XA
 
 #define CONFIG_ARMV7_PSCI
+#define CONFIG_ARMV7_PSCI_NR_CPUS	CONFIG_MAX_CPUS
 
 #define CONFIG_SYS_FSL_CLK
 
diff --git a/include/configs/sun6i.h b/include/configs/sun6i.h
index 95ccc35708a7ecba89b9c3a1b2cddd5d8b515d29..0625502f44b49fa4980b59834540a7f2eb623b0d 100644
--- a/include/configs/sun6i.h
+++ b/include/configs/sun6i.h
@@ -25,6 +25,7 @@
 #define CONFIG_ARMV7_PSCI		1
 #define CONFIG_ARMV7_PSCI_NR_CPUS	4
 #define CONFIG_ARMV7_SECURE_BASE	SUNXI_SRAM_B_BASE
+#define CONFIG_ARMV7_SECURE_MAX_SIZE    (64 * 1024) /* 64 KB */
 
 /*
  * Include common sunxi configuration where most the settings are
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
index 0dd29029b9b3368af216195c4deec8751d32104a..e9074d5dfbf9817cdb483d6d495c8282619981de 100644
--- a/include/configs/sun7i.h
+++ b/include/configs/sun7i.h
@@ -21,7 +21,9 @@
 #define CONFIG_SUNXI_USB_PHYS	3
 
 #define CONFIG_ARMV7_PSCI		1
+#define CONFIG_ARMV7_PSCI_NR_CPUS	2
 #define CONFIG_ARMV7_SECURE_BASE	SUNXI_SRAM_B_BASE
+#define CONFIG_ARMV7_SECURE_MAX_SIZE	(64 * 1024) /* 64 KB */
 
 /*
  * Include common sunxi configuration where most the settings are
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 94275a7183ffc35547893dedcc933bb6b8d61c7a..635890122d40b638bd66a96d062165e5a2ee5201 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -137,6 +137,11 @@
 #define CONFIG_SPL_NAND_SUPPORT 1
 #endif
 
+#ifdef CONFIG_SPL_SPI_SUNXI
+#define CONFIG_SPL_SPI_FLASH_SUPPORT	1
+#define CONFIG_SYS_SPI_U_BOOT_OFFS	0x8000
+#endif
+
 /* mmc config */
 #ifdef CONFIG_MMC
 #define CONFIG_GENERIC_MMC