diff --git a/Makefile b/Makefile
index e38fd2f95c8b649b9108809704dad4b7d1aea844..1df3f707cb461a0edfa00ed85cd60e17171176b0 100644
--- a/Makefile
+++ b/Makefile
@@ -937,6 +937,13 @@ OBJCOPYFLAGS_u-boot-spi.gph = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO)
 u-boot-spi.gph: spl/u-boot-spl.gph u-boot.img FORCE
 	$(call if_changed,pad_cat)
 
+ifneq ($(CONFIG_SUNXI),)
+OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \
+				   --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
+u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE
+	$(call if_changed,pad_cat)
+endif
+
 ifneq ($(CONFIG_TEGRA),)
 OBJCOPYFLAGS_u-boot-nodtb-tegra.bin = -O binary --pad-to=$(CONFIG_SYS_TEXT_BASE)
 u-boot-nodtb-tegra.bin: spl/u-boot-spl u-boot.bin FORCE
@@ -1163,6 +1170,9 @@ spl/u-boot-spl.bin: spl/u-boot-spl
 spl/u-boot-spl: tools prepare
 	$(Q)$(MAKE) obj=spl -f $(srctree)/spl/Makefile all
 
+spl/sunxi-spl.bin: spl/u-boot-spl
+	@:
+
 tpl/u-boot-tpl.bin: tools prepare
 	$(Q)$(MAKE) obj=tpl -f $(srctree)/spl/Makefile all CONFIG_TPL_BUILD=y
 
diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
index 7d7725c4b831392c3bddff515f9df574de44cf9f..0e6c0da1bdd4cfeefb2c7f3e20d207550b76c4c6 100644
--- a/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
+++ b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
@@ -165,3 +165,20 @@ void at91_macb_hw_init(void)
 #endif
 }
 #endif
+
+#ifdef CONFIG_GENERIC_ATMEL_MCI
+void at91_mci_hw_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	at91_set_a_periph(AT91_PIO_PORTA, 0, 0);	/* MCI0 CLK */
+	at91_set_a_periph(AT91_PIO_PORTA, 1, 0);	/* MCI0 CDA */
+	at91_set_a_periph(AT91_PIO_PORTA, 2, 0);	/* MCI0 DA0 */
+	at91_set_a_periph(AT91_PIO_PORTA, 3, 0);	/* MCI0 DA1 */
+	at91_set_a_periph(AT91_PIO_PORTA, 4, 0);	/* MCI0 DA2 */
+	at91_set_a_periph(AT91_PIO_PORTA, 5, 0);	/* MCI0 DA3 */
+
+	/* Enable clock */
+	writel(1 << ATMEL_ID_MCI0, &pmc->pcer);
+}
+#endif
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index ab869b1ee87d1f0b031ccfe2bdd7e5b6f5bbdf94..232118d7f4135475c3489787211b3a04fe254080 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -12,7 +12,7 @@ obj-y	+= cache_v7.o
 obj-y	+= cpu.o
 obj-y	+= syslib.o
 
-ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY),)
+ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI),)
 ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y)
 obj-y	+= lowlevel_init.o
 endif
diff --git a/arch/arm/cpu/armv7/at91/config.mk b/arch/arm/cpu/armv7/at91/config.mk
new file mode 100644
index 0000000000000000000000000000000000000000..09eab709554486c02d789e3481a8e39914c30a29
--- /dev/null
+++ b/arch/arm/cpu/armv7/at91/config.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2014, Andreas Bießmann <andreas.devel@googlemail.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+ifdef CONFIG_SPL_BUILD
+ALL-y	+= boot.bin
+else
+ALL-y	+= u-boot.img
+endif
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a64bfa18e0d7f779ed6f3bc9f88f6dd6f085440e
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -0,0 +1,25 @@
+#
+# (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+#
+# Based on some other Makefile
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+obj-y	+= timer.o
+obj-y	+= board.o
+obj-y	+= clock.o
+obj-y	+= pinmux.o
+obj-$(CONFIG_SUN7I)	+= clock_sun4i.o
+
+ifndef CONFIG_SPL_BUILD
+obj-y	+= cpu_info.o
+endif
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SUN7I)	+= dram.o
+ifdef CONFIG_SPL_FEL
+obj-y	+= start.o
+endif
+endif
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
new file mode 100644
index 0000000000000000000000000000000000000000..49c94489ee5d2f7d145055b0614f9eacd63f184d
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Some init for sunxi platform.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <serial.h>
+#ifdef CONFIG_SPL_BUILD
+#include <spl.h>
+#endif
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/timer.h>
+
+#ifdef CONFIG_SPL_BUILD
+/* Pointer to the global data structure for SPL */
+DECLARE_GLOBAL_DATA_PTR;
+
+/* The sunxi internal brom will try to loader external bootloader
+ * from mmc0, nand flash, mmc2.
+ * Unfortunately we can't check how SPL was loaded so assume
+ * it's always the first SD/MMC controller
+ */
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_MMC1;
+}
+
+/* No confirmation data available in SPL yet. Hardcode bootmode */
+u32 spl_boot_mode(void)
+{
+	return MMCSD_MODE_RAW;
+}
+#endif
+
+int gpio_init(void)
+{
+	sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB22_UART0_TX);
+	sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB23_UART0_RX);
+	sunxi_gpio_set_pull(SUNXI_GPB(23), 1);
+
+	return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+}
+
+/* do some early init */
+void s_init(void)
+{
+#if !defined CONFIG_SPL_BUILD && (defined CONFIG_SUN7I || defined CONFIG_SUN6I)
+	/* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */
+	asm volatile(
+		"mrc p15, 0, r0, c1, c0, 1\n"
+		"orr r0, r0, #1 << 6\n"
+		"mcr p15, 0, r0, c1, c0, 1\n");
+#endif
+
+	clock_init();
+	timer_init();
+	gpio_init();
+
+#ifdef CONFIG_SPL_BUILD
+	gd = &gdata;
+	preloader_console_init();
+
+	sunxi_board_init();
+#endif
+}
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+void enable_caches(void)
+{
+	/* Enable D-cache. I-cache is already enabled in start.S */
+	dcache_enable();
+}
+#endif
+
+#ifdef CONFIG_CMD_NET
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+	int rc;
+
+#ifdef CONFIG_SUNXI_GMAC
+	rc = sunxi_gmac_initialize(bis);
+	if (rc < 0) {
+		printf("sunxi: failed to initialize gmac\n");
+		return rc;
+	}
+#endif
+
+	return 0;
+}
+#endif
diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c
new file mode 100644
index 0000000000000000000000000000000000000000..47fb70ff7cf845b56b93029ce2a9fc235987cfac
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/clock.c
@@ -0,0 +1,25 @@
+/*
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/sys_proto.h>
+
+int clock_init(void)
+{
+#ifdef CONFIG_SPL_BUILD
+	clock_init_safe();
+#endif
+	clock_init_uart();
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
new file mode 100644
index 0000000000000000000000000000000000000000..5a7da3c6bfa68fc492c664cc658e7710bd962f8b
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
@@ -0,0 +1,188 @@
+/*
+ * sun4i, sun5i and sun7i specific clock code
+ *
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/sys_proto.h>
+
+#ifdef CONFIG_SPL_BUILD
+void clock_init_safe(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* Set safe defaults until PMU is configured */
+	writel(AXI_DIV_1 << AXI_DIV_SHIFT |
+	       AHB_DIV_2 << AHB_DIV_SHIFT |
+	       APB0_DIV_1 << APB0_DIV_SHIFT |
+	       CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
+	       &ccm->cpu_ahb_apb0_cfg);
+	writel(PLL1_CFG_DEFAULT, &ccm->pll1_cfg);
+	sdelay(200);
+	writel(AXI_DIV_1 << AXI_DIV_SHIFT |
+	       AHB_DIV_2 << AHB_DIV_SHIFT |
+	       APB0_DIV_1 << APB0_DIV_SHIFT |
+	       CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
+	       &ccm->cpu_ahb_apb0_cfg);
+#ifdef CONFIG_SUN7I
+	writel(0x1 << AHB_GATE_OFFSET_DMA | readl(&ccm->ahb_gate0),
+	       &ccm->ahb_gate0);
+#endif
+	writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg);
+}
+#endif
+
+void clock_init_uart(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* uart clock source is apb1 */
+	writel(APB1_CLK_SRC_OSC24M|
+	       APB1_CLK_RATE_N_1|
+	       APB1_CLK_RATE_M(1),
+	       &ccm->apb1_clk_div_cfg);
+
+	/* open the clock for uart */
+	setbits_le32(&ccm->apb1_gate,
+		CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT+CONFIG_CONS_INDEX-1));
+}
+
+int clock_twi_onoff(int port, int state)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (port > 2)
+		return -1;
+
+	/* set the apb clock gate for twi */
+	if (state)
+		setbits_le32(&ccm->apb1_gate,
+			     CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT+port));
+	else
+		clrbits_le32(&ccm->apb1_gate,
+			     CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT+port));
+
+	return 0;
+}
+
+#ifdef CONFIG_SPL_BUILD
+#define PLL1_CFG(N, K, M, P)	( 1 << CCM_PLL1_CFG_ENABLE_SHIFT | \
+				  0 << CCM_PLL1_CFG_VCO_RST_SHIFT |  \
+				  8 << CCM_PLL1_CFG_VCO_BIAS_SHIFT | \
+				  0 << CCM_PLL1_CFG_PLL4_EXCH_SHIFT | \
+				 16 << CCM_PLL1_CFG_BIAS_CUR_SHIFT | \
+				 (P)<< CCM_PLL1_CFG_DIVP_SHIFT | \
+				  2 << CCM_PLL1_CFG_LCK_TMR_SHIFT | \
+				 (N)<< CCM_PLL1_CFG_FACTOR_N_SHIFT | \
+				 (K)<< CCM_PLL1_CFG_FACTOR_K_SHIFT | \
+				  0 << CCM_PLL1_CFG_SIG_DELT_PAT_IN_SHIFT | \
+				  0 << CCM_PLL1_CFG_SIG_DELT_PAT_EN_SHIFT | \
+				 (M)<< CCM_PLL1_CFG_FACTOR_M_SHIFT)
+
+static struct {
+	u32 pll1_cfg;
+	unsigned int freq;
+} pll1_para[] = {
+	/* This array must be ordered by frequency. */
+	{ PLL1_CFG(16, 0, 0, 0), 384000000 },
+	{ PLL1_CFG(16, 1, 0, 0), 768000000 },
+	{ PLL1_CFG(20, 1, 0, 0), 960000000 },
+	{ PLL1_CFG(21, 1, 0, 0), 1008000000},
+	{ PLL1_CFG(22, 1, 0, 0), 1056000000},
+	{ PLL1_CFG(23, 1, 0, 0), 1104000000},
+	{ PLL1_CFG(24, 1, 0, 0), 1152000000},
+	{ PLL1_CFG(25, 1, 0, 0), 1200000000},
+	{ PLL1_CFG(26, 1, 0, 0), 1248000000},
+	{ PLL1_CFG(27, 1, 0, 0), 1296000000},
+	{ PLL1_CFG(28, 1, 0, 0), 1344000000},
+	{ PLL1_CFG(29, 1, 0, 0), 1392000000},
+	{ PLL1_CFG(30, 1, 0, 0), 1440000000},
+	{ PLL1_CFG(31, 1, 0, 0), 1488000000},
+	/* Final catchall entry */
+	{ PLL1_CFG(31, 1, 0, 0), ~0},
+};
+
+void clock_set_pll1(unsigned int hz)
+{
+	int i = 0;
+	int axi, ahb, apb0;
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* Find target frequency */
+	while (pll1_para[i].freq < hz)
+		i++;
+
+	hz = pll1_para[i].freq;
+
+	/* Calculate system clock divisors */
+	axi = DIV_ROUND_UP(hz, 432000000);	/* Max 450MHz */
+	ahb = DIV_ROUND_UP(hz/axi, 204000000);	/* Max 250MHz */
+	apb0 = 2;				/* Max 150MHz */
+
+	printf("CPU: %uHz, AXI/AHB/APB: %d/%d/%d\n", hz, axi, ahb, apb0);
+
+	/* Map divisors to register values */
+	axi = axi - 1;
+	if (ahb > 4)
+		ahb = 3;
+	else if (ahb > 2)
+		ahb = 2;
+	else if (ahb > 1)
+		ahb = 1;
+	else
+		ahb = 0;
+
+	apb0 = apb0 - 1;
+
+	/* Switch to 24MHz clock while changing PLL1 */
+	writel(AXI_DIV_1 << AXI_DIV_SHIFT |
+	       AHB_DIV_2 << AHB_DIV_SHIFT |
+	       APB0_DIV_1 << APB0_DIV_SHIFT |
+	       CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
+	       &ccm->cpu_ahb_apb0_cfg);
+	sdelay(20);
+
+	/* Configure sys clock divisors */
+	writel(axi << AXI_DIV_SHIFT |
+	       ahb << AHB_DIV_SHIFT |
+	       apb0 << APB0_DIV_SHIFT |
+	       CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
+	       &ccm->cpu_ahb_apb0_cfg);
+
+	/* Configure PLL1 at the desired frequency */
+	writel(pll1_para[i].pll1_cfg, &ccm->pll1_cfg);
+	sdelay(200);
+
+	/* Switch CPU to PLL1 */
+	writel(axi << AXI_DIV_SHIFT |
+	       ahb << AHB_DIV_SHIFT |
+	       apb0 << APB0_DIV_SHIFT |
+	       CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
+	       &ccm->cpu_ahb_apb0_cfg);
+	sdelay(20);
+}
+#endif
+
+unsigned int clock_get_pll6(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	uint32_t rval = readl(&ccm->pll6_cfg);
+	int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT);
+	int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1;
+	return 24000000 * n * k / 2;
+}
diff --git a/arch/arm/cpu/armv7/sunxi/config.mk b/arch/arm/cpu/armv7/sunxi/config.mk
new file mode 100644
index 0000000000000000000000000000000000000000..00f5ffc68301d8e0e9bb56bffaa1f87745b1b167
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/config.mk
@@ -0,0 +1,8 @@
+# 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/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c
new file mode 100644
index 0000000000000000000000000000000000000000..b4c3d5c6dd2df064241577a9d4856eb267e27240
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c
@@ -0,0 +1,19 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	puts("CPU:   Allwinner A20 (SUN7I)\n");
+	return 0;
+}
+#endif
diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
new file mode 100644
index 0000000000000000000000000000000000000000..b43c4b41d3c53dc339b3f4f4229daa9fca7f9764
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -0,0 +1,593 @@
+/*
+ * sunxi DRAM controller initialization
+ * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c
+ * and earlier U-Boot Allwiner A10 SPL work
+ *
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Berg Xing <bergxing@allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Unfortunately the only documentation we have on the sun7i DRAM
+ * controller is Allwinner boot0 + boot1 code, and that code uses
+ * magic numbers & shifts with no explanations. Hence this code is
+ * rather undocumented and full of magic.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/timer.h>
+#include <asm/arch/sys_proto.h>
+
+#define CPU_CFG_CHIP_VER(n) ((n) << 6)
+#define CPU_CFG_CHIP_VER_MASK CPU_CFG_CHIP_VER(0x3)
+#define CPU_CFG_CHIP_REV_A 0x0
+#define CPU_CFG_CHIP_REV_C1 0x1
+#define CPU_CFG_CHIP_REV_C2 0x2
+#define CPU_CFG_CHIP_REV_B 0x3
+
+/*
+ * Wait up to 1s for mask to be clear in given reg.
+ */
+static void await_completion(u32 *reg, u32 mask)
+{
+	unsigned long tmo = timer_get_us() + 1000000;
+
+	while (readl(reg) & mask) {
+		if (timer_get_us() > tmo)
+			panic("Timeout initialising DRAM\n");
+	}
+}
+
+static void mctl_ddr3_reset(void)
+{
+	struct sunxi_dram_reg *dram =
+			(struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrbits_le32(&dram->mcr, DRAM_MCR_RESET);
+	udelay(2);
+	setbits_le32(&dram->mcr, DRAM_MCR_RESET);
+}
+
+static void mctl_set_drive(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3) | (0x3 << 28),
+			DRAM_MCR_MODE_EN(0x3) |
+			0xffc);
+}
+
+static void mctl_itm_disable(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrsetbits_le32(&dram->ccr, DRAM_CCR_INIT, DRAM_CCR_ITM_OFF);
+}
+
+static void mctl_itm_enable(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF);
+}
+
+static void mctl_enable_dll0(u32 phase)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
+			((phase >> 16) & 0x3f) << 6);
+	clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE);
+	udelay(2);
+
+	clrbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE);
+	udelay(22);
+
+	clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET);
+	udelay(22);
+}
+
+/*
+ * Note: This differs from pm/standby in that it checks the bus width
+ */
+static void mctl_enable_dllx(u32 phase)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 i, n, bus_width;
+
+	bus_width = readl(&dram->dcr);
+
+	if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) ==
+	    DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT))
+		n = DRAM_DCR_NR_DLLCR_32BIT;
+	else
+		n = DRAM_DCR_NR_DLLCR_16BIT;
+
+	for (i = 1; i < n; i++) {
+		clrsetbits_le32(&dram->dllcr[i], 0xf << 14,
+				(phase & 0xf) << 14);
+		clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET,
+				DRAM_DLLCR_DISABLE);
+		phase >>= 4;
+	}
+	udelay(2);
+
+	for (i = 1; i < n; i++)
+		clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET |
+			     DRAM_DLLCR_DISABLE);
+	udelay(22);
+
+	for (i = 1; i < n; i++)
+		clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE,
+				DRAM_DLLCR_NRESET);
+	udelay(22);
+}
+
+static u32 hpcr_value[32] = {
+#ifdef CONFIG_SUN7I
+	0x0301, 0x0301, 0x0301, 0x0301,
+	0x0301, 0x0301, 0x0301, 0x0301,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0x1031, 0x1031, 0x0735, 0x1035,
+	0x1035, 0x0731, 0x1031, 0x0735,
+	0x1035, 0x1031, 0x0731, 0x1035,
+	0x0001, 0x1031, 0, 0x1031
+	/* last row differs from boot0 source table
+	 * 0x1031, 0x0301, 0x0301, 0x0731
+	 * but boot0 code skips #28 and #30, and sets #29 and #31 to the
+	 * value from #28 entry (0x1031)
+	 */
+#endif
+};
+
+static void mctl_configure_hostport(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 i;
+
+	for (i = 0; i < 32; i++)
+		writel(hpcr_value[i], &dram->hpcr[i]);
+}
+
+static void mctl_setup_dram_clock(u32 clk)
+{
+	u32 reg_val;
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* setup DRAM PLL */
+	reg_val = readl(&ccm->pll5_cfg);
+	reg_val &= ~CCM_PLL5_CTRL_M_MASK;		/* set M to 0 (x1) */
+	reg_val &= ~CCM_PLL5_CTRL_K_MASK;		/* set K to 0 (x1) */
+	reg_val &= ~CCM_PLL5_CTRL_N_MASK;		/* set N to 0 (x0) */
+	reg_val &= ~CCM_PLL5_CTRL_P_MASK;		/* set P to 0 (x1) */
+	if (clk >= 540 && clk < 552) {
+		/* dram = 540MHz, pll5p = 540MHz */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(15));
+		reg_val |= CCM_PLL5_CTRL_P(1);
+	} else if (clk >= 512 && clk < 528) {
+		/* dram = 512MHz, pll5p = 384MHz */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(4));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(16));
+		reg_val |= CCM_PLL5_CTRL_P(2);
+	} else if (clk >= 496 && clk < 504) {
+		/* dram = 496MHz, pll5p = 372MHz */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(31));
+		reg_val |= CCM_PLL5_CTRL_P(2);
+	} else if (clk >= 468 && clk < 480) {
+		/* dram = 468MHz, pll5p = 468MHz */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(13));
+		reg_val |= CCM_PLL5_CTRL_P(1);
+	} else if (clk >= 396 && clk < 408) {
+		/* dram = 396MHz, pll5p = 396MHz */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(11));
+		reg_val |= CCM_PLL5_CTRL_P(1);
+	} else 	{
+		/* any other frequency that is a multiple of 24 */
+		reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2));
+		reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2));
+		reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24));
+		reg_val |= CCM_PLL5_CTRL_P(CCM_PLL5_CTRL_P_X(2));
+	}
+	reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN;		/* PLL VCO Gain off */
+	reg_val |= CCM_PLL5_CTRL_EN;			/* PLL On */
+	writel(reg_val, &ccm->pll5_cfg);
+	udelay(5500);
+
+	setbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_DDR_CLK);
+
+#if defined(CONFIG_SUN4I) || defined(CONFIG_SUN7I)
+	/* reset GPS */
+	clrbits_le32(&ccm->gps_clk_cfg, CCM_GPS_CTRL_RESET | CCM_GPS_CTRL_GATE);
+	setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_GPS);
+	udelay(1);
+	clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_GPS);
+#endif
+
+	/* setup MBUS clock */
+	reg_val = CCM_MBUS_CTRL_GATE |
+		  CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL6) |
+		  CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(2)) |
+		  CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2));
+	writel(reg_val, &ccm->mbus_clk_cfg);
+
+	/*
+	 * open DRAMC AHB & DLL register clock
+	 * close it first
+	 */
+	clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL);
+	udelay(22);
+
+	/* then open it */
+	setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL);
+	udelay(22);
+}
+
+static int dramc_scan_readpipe(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+
+	/* data training trigger */
+#ifdef CONFIG_SUN7I
+	clrbits_le32(&dram->csr, DRAM_CSR_FAILED);
+#endif
+	setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING);
+
+	/* check whether data training process has completed */
+	await_completion(&dram->ccr, DRAM_CCR_DATA_TRAINING);
+
+	/* check data training result */
+	reg_val = readl(&dram->csr);
+	if (reg_val & DRAM_CSR_FAILED)
+		return -1;
+
+	return 0;
+}
+
+static int dramc_scan_dll_para(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	const u32 dqs_dly[7] = {0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc};
+	const u32 clk_dly[15] = {0x07, 0x06, 0x05, 0x04, 0x03,
+				 0x02, 0x01, 0x00, 0x08, 0x10,
+				 0x18, 0x20, 0x28, 0x30, 0x38};
+	u32 clk_dqs_count[15];
+	u32 dqs_i, clk_i, cr_i;
+	u32 max_val, min_val;
+	u32 dqs_index, clk_index;
+
+	/* Find DQS_DLY Pass Count for every CLK_DLY */
+	for (clk_i = 0; clk_i < 15; clk_i++) {
+		clk_dqs_count[clk_i] = 0;
+		clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
+				(clk_dly[clk_i] & 0x3f) << 6);
+		for (dqs_i = 0; dqs_i < 7; dqs_i++) {
+			for (cr_i = 1; cr_i < 5; cr_i++) {
+				clrsetbits_le32(&dram->dllcr[cr_i],
+						0x4f << 14,
+						(dqs_dly[dqs_i] & 0x4f) << 14);
+			}
+			udelay(2);
+			if (dramc_scan_readpipe() == 0)
+				clk_dqs_count[clk_i]++;
+		}
+	}
+	/* Test DQS_DLY Pass Count for every CLK_DLY from up to down */
+	for (dqs_i = 15; dqs_i > 0; dqs_i--) {
+		max_val = 15;
+		min_val = 15;
+		for (clk_i = 0; clk_i < 15; clk_i++) {
+			if (clk_dqs_count[clk_i] == dqs_i) {
+				max_val = clk_i;
+				if (min_val == 15)
+					min_val = clk_i;
+			}
+		}
+		if (max_val < 15)
+			break;
+	}
+
+	/* Check if Find a CLK_DLY failed */
+	if (!dqs_i)
+		goto fail;
+
+	/* Find the middle index of CLK_DLY */
+	clk_index = (max_val + min_val) >> 1;
+	if ((max_val == (15 - 1)) && (min_val > 0))
+		/* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle
+		 * value can be more close to the max_val
+		 */
+		clk_index = (15 + clk_index) >> 1;
+	else if ((max_val < (15 - 1)) && (min_val == 0))
+		/* if CLK_DLY[0] is very good, then the middle value can be more
+		 * close to the min_val
+		 */
+		clk_index >>= 1;
+	if (clk_dqs_count[clk_index] < dqs_i)
+		clk_index = min_val;
+
+	/* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan
+	 * read pipe again
+	 */
+	clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
+			(clk_dly[clk_index] & 0x3f) << 6);
+	max_val = 7;
+	min_val = 7;
+	for (dqs_i = 0; dqs_i < 7; dqs_i++) {
+		clk_dqs_count[dqs_i] = 0;
+		for (cr_i = 1; cr_i < 5; cr_i++) {
+			clrsetbits_le32(&dram->dllcr[cr_i],
+					0x4f << 14,
+					(dqs_dly[dqs_i] & 0x4f) << 14);
+		}
+		udelay(2);
+		if (dramc_scan_readpipe() == 0) {
+			clk_dqs_count[dqs_i] = 1;
+			max_val = dqs_i;
+			if (min_val == 7)
+				min_val = dqs_i;
+		}
+	}
+
+	if (max_val < 7) {
+		dqs_index = (max_val + min_val) >> 1;
+		if ((max_val == (7-1)) && (min_val > 0))
+			dqs_index = (7 + dqs_index) >> 1;
+		else if ((max_val < (7-1)) && (min_val == 0))
+			dqs_index >>= 1;
+		if (!clk_dqs_count[dqs_index])
+			dqs_index = min_val;
+		for (cr_i = 1; cr_i < 5; cr_i++) {
+			clrsetbits_le32(&dram->dllcr[cr_i],
+					0x4f << 14,
+					(dqs_dly[dqs_index] & 0x4f) << 14);
+		}
+		udelay(2);
+		return dramc_scan_readpipe();
+	}
+
+fail:
+	clrbits_le32(&dram->dllcr[0], 0x3f << 6);
+	for (cr_i = 1; cr_i < 5; cr_i++)
+		clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14);
+	udelay(2);
+
+	return dramc_scan_readpipe();
+}
+
+static void dramc_clock_output_en(u32 on)
+{
+#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I)
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	if (on)
+		setbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT);
+	else
+		clrbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT);
+#endif
+}
+
+static const u16 tRFC_table[2][6] = {
+	/*       256Mb    512Mb    1Gb      2Gb      4Gb      8Gb      */
+	/* DDR2  75ns     105ns    127.5ns  195ns    327.5ns  invalid  */
+	{        77,      108,     131,     200,     336,     336 },
+	/* DDR3  invalid  90ns     110ns    160ns    300ns    350ns    */
+	{        93,      93,      113,     164,     308,     359 }
+};
+
+static void dramc_set_autorefresh_cycle(u32 clk, u32 type, u32 density)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 tRFC, tREFI;
+
+	tRFC = (tRFC_table[type][density] * clk + 1023) >> 10;
+	tREFI = (7987 * clk) >> 10;	/* <= 7.8us */
+
+	writel(DRAM_DRR_TREFI(tREFI) | DRAM_DRR_TRFC(tRFC), &dram->drr);
+}
+
+unsigned long dramc_init(struct dram_para *para)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+	u32 density;
+	int ret_val;
+
+	/* check input dram parameter structure */
+	if (!para)
+		return 0;
+
+	/* setup DRAM relative clock */
+	mctl_setup_dram_clock(para->clock);
+
+	/* reset external DRAM */
+	mctl_set_drive();
+
+	/* dram clock off */
+	dramc_clock_output_en(0);
+
+	mctl_itm_disable();
+	mctl_enable_dll0(para->tpr3);
+
+	/* configure external DRAM */
+	reg_val = 0x0;
+	if (para->type == DRAM_MEMORY_TYPE_DDR3)
+		reg_val |= DRAM_DCR_TYPE_DDR3;
+	reg_val |= DRAM_DCR_IO_WIDTH(para->io_width >> 3);
+
+	if (para->density == 256)
+		density = DRAM_DCR_CHIP_DENSITY_256M;
+	else if (para->density == 512)
+		density = DRAM_DCR_CHIP_DENSITY_512M;
+	else if (para->density == 1024)
+		density = DRAM_DCR_CHIP_DENSITY_1024M;
+	else if (para->density == 2048)
+		density = DRAM_DCR_CHIP_DENSITY_2048M;
+	else if (para->density == 4096)
+		density = DRAM_DCR_CHIP_DENSITY_4096M;
+	else if (para->density == 8192)
+		density = DRAM_DCR_CHIP_DENSITY_8192M;
+	else
+		density = DRAM_DCR_CHIP_DENSITY_256M;
+
+	reg_val |= DRAM_DCR_CHIP_DENSITY(density);
+	reg_val |= DRAM_DCR_BUS_WIDTH((para->bus_width >> 3) - 1);
+	reg_val |= DRAM_DCR_RANK_SEL(para->rank_num - 1);
+	reg_val |= DRAM_DCR_CMD_RANK_ALL;
+	reg_val |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE);
+	writel(reg_val, &dram->dcr);
+
+#ifdef CONFIG_SUN7I
+	setbits_le32(&dram->zqcr1, (0x1 << 24) | (0x1 << 1));
+	if (para->tpr4 & 0x2)
+		clrsetbits_le32(&dram->zqcr1, (0x1 << 24), (0x1 << 1));
+	dramc_clock_output_en(1);
+#endif
+
+#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I))
+	/* set odt impendance divide ratio */
+	reg_val = ((para->zq) >> 8) & 0xfffff;
+	reg_val |= ((para->zq) & 0xff) << 20;
+	reg_val |= (para->zq) & 0xf0000000;
+	writel(reg_val, &dram->zqcr0);
+#endif
+
+#ifdef CONFIG_SUN7I
+	/* Set CKE Delay to about 1ms */
+	setbits_le32(&dram->idcr, 0x1ffff);
+#endif
+
+#ifdef CONFIG_SUN7I
+	if ((readl(&dram->ppwrsctl) & 0x1) != 0x1)
+		mctl_ddr3_reset();
+	else
+		setbits_le32(&dram->mcr, DRAM_MCR_RESET);
+#endif
+
+	udelay(1);
+
+	await_completion(&dram->ccr, DRAM_CCR_INIT);
+
+	mctl_enable_dllx(para->tpr3);
+
+	/* set refresh period */
+	dramc_set_autorefresh_cycle(para->clock, para->type - 2, density);
+
+	/* set timing parameters */
+	writel(para->tpr0, &dram->tpr0);
+	writel(para->tpr1, &dram->tpr1);
+	writel(para->tpr2, &dram->tpr2);
+
+	if (para->type == DRAM_MEMORY_TYPE_DDR3) {
+		reg_val = DRAM_MR_BURST_LENGTH(0x0);
+#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I))
+		reg_val |= DRAM_MR_POWER_DOWN;
+#endif
+		reg_val |= DRAM_MR_CAS_LAT(para->cas - 4);
+		reg_val |= DRAM_MR_WRITE_RECOVERY(0x5);
+	} else if (para->type == DRAM_MEMORY_TYPE_DDR2) {
+		reg_val = DRAM_MR_BURST_LENGTH(0x2);
+		reg_val |= DRAM_MR_CAS_LAT(para->cas);
+		reg_val |= DRAM_MR_WRITE_RECOVERY(0x5);
+	}
+	writel(reg_val, &dram->mr);
+
+	writel(para->emr1, &dram->emr);
+	writel(para->emr2, &dram->emr2);
+	writel(para->emr3, &dram->emr3);
+
+	/* set DQS window mode */
+	clrsetbits_le32(&dram->ccr, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE);
+
+#ifdef CONFIG_SUN7I
+	/* Command rate timing mode 2T & 1T */
+	if (para->tpr4 & 0x1)
+		setbits_le32(&dram->ccr, DRAM_CCR_COMMAND_RATE_1T);
+#endif
+	/* reset external DRAM */
+	setbits_le32(&dram->ccr, DRAM_CCR_INIT);
+	await_completion(&dram->ccr, DRAM_CCR_INIT);
+
+#ifdef CONFIG_SUN7I
+	/* setup zq calibration manual */
+	reg_val = readl(&dram->ppwrsctl);
+	if ((reg_val & 0x1) == 1) {
+		/* super_standby_flag = 1 */
+
+		reg_val = readl(0x01c20c00 + 0x120); /* rtc */
+		reg_val &= 0x000fffff;
+		reg_val |= 0x17b00000;
+		writel(reg_val, &dram->zqcr0);
+
+		/* exit self-refresh state */
+		clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27);
+		/* check whether command has been executed */
+		await_completion(&dram->dcr, 0x1 << 31);
+
+		udelay(2);
+
+		/* dram pad hold off */
+		setbits_le32(&dram->ppwrsctl, 0x16510000);
+
+		await_completion(&dram->ppwrsctl, 0x1);
+
+		/* exit self-refresh state */
+		clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27);
+
+		/* check whether command has been executed */
+		await_completion(&dram->dcr, 0x1 << 31);
+
+		udelay(2);
+
+		/* issue a refresh command */
+		clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x13 << 27);
+		await_completion(&dram->dcr, 0x1 << 31);
+
+		udelay(2);
+	}
+#endif
+
+	/* scan read pipe value */
+	mctl_itm_enable();
+	if (para->tpr3 & (0x1 << 31)) {
+		ret_val = dramc_scan_dll_para();
+		if (ret_val == 0)
+			para->tpr3 =
+				(((readl(&dram->dllcr[0]) >> 6) & 0x3f) << 16) |
+				(((readl(&dram->dllcr[1]) >> 14) & 0xf) << 0) |
+				(((readl(&dram->dllcr[2]) >> 14) & 0xf) << 4) |
+				(((readl(&dram->dllcr[3]) >> 14) & 0xf) << 8) |
+				(((readl(&dram->dllcr[4]) >> 14) & 0xf) << 12
+				);
+	} else {
+		ret_val = dramc_scan_readpipe();
+	}
+
+	if (ret_val < 0)
+		return 0;
+
+	/* configure all host port */
+	mctl_configure_hostport();
+
+	return get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE);
+}
diff --git a/arch/arm/cpu/armv7/sunxi/pinmux.c b/arch/arm/cpu/armv7/sunxi/pinmux.c
new file mode 100644
index 0000000000000000000000000000000000000000..1f2843fcac4577ebcfa45212b27c9238399e7347
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/pinmux.c
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+
+int sunxi_gpio_set_cfgpin(u32 pin, u32 val)
+{
+	u32 bank = GPIO_BANK(pin);
+	u32 index = GPIO_CFG_INDEX(pin);
+	u32 offset = GPIO_CFG_OFFSET(pin);
+	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+	clrsetbits_le32(&pio->cfg[0] + index, 0xf << offset, val << offset);
+
+	return 0;
+}
+
+int sunxi_gpio_get_cfgpin(u32 pin)
+{
+	u32 cfg;
+	u32 bank = GPIO_BANK(pin);
+	u32 index = GPIO_CFG_INDEX(pin);
+	u32 offset = GPIO_CFG_OFFSET(pin);
+	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+	cfg = readl(&pio->cfg[0] + index);
+	cfg >>= offset;
+
+	return cfg & 0xf;
+}
+
+int sunxi_gpio_set_drv(u32 pin, u32 val)
+{
+	u32 bank = GPIO_BANK(pin);
+	u32 index = GPIO_DRV_INDEX(pin);
+	u32 offset = GPIO_DRV_OFFSET(pin);
+	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+	clrsetbits_le32(&pio->drv[0] + index, 0x3 << offset, val << offset);
+
+	return 0;
+}
+
+int sunxi_gpio_set_pull(u32 pin, u32 val)
+{
+	u32 bank = GPIO_BANK(pin);
+	u32 index = GPIO_PULL_INDEX(pin);
+	u32 offset = GPIO_PULL_OFFSET(pin);
+	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+	clrsetbits_le32(&pio->pull[0] + index, 0x3 << offset, val << offset);
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/sunxi/start.c b/arch/arm/cpu/armv7/sunxi/start.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b392fa8353d98b0f9ab9ad8bf2aa6c3c1ccc13a
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/start.c
@@ -0,0 +1 @@
+/* Intentionally empty. Only needed to get FEL SPL link line right */
diff --git a/arch/arm/cpu/armv7/sunxi/timer.c b/arch/arm/cpu/armv7/sunxi/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..36263896d86bee82873d7a0058625f8f98c89905
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/timer.c
@@ -0,0 +1,113 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/timer.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_MODE   (0x0 << 7)	/* continuous mode */
+#define TIMER_DIV    (0x0 << 4)	/* pre scale 1 */
+#define TIMER_SRC    (0x1 << 2)	/* osc24m */
+#define TIMER_RELOAD (0x1 << 1)	/* reload internal value */
+#define TIMER_EN     (0x1 << 0)	/* enable timer */
+
+#define TIMER_CLOCK		(24 * 1000 * 1000)
+#define COUNT_TO_USEC(x)	((x) / 24)
+#define USEC_TO_COUNT(x)	((x) * 24)
+#define TICKS_PER_HZ		(TIMER_CLOCK / CONFIG_SYS_HZ)
+#define TICKS_TO_HZ(x)		((x) / TICKS_PER_HZ)
+
+#define TIMER_LOAD_VAL		0xffffffff
+
+#define TIMER_NUM		0	/* we use timer 0 */
+
+/* read the 32-bit timer */
+static ulong read_timer(void)
+{
+	struct sunxi_timer_reg *timers =
+		(struct sunxi_timer_reg *)SUNXI_TIMER_BASE;
+	struct sunxi_timer *timer = &timers->timer[TIMER_NUM];
+
+	/*
+	 * The hardware timer counts down, therefore we invert to
+	 * produce an incrementing timer.
+	 */
+	return ~readl(&timer->val);
+}
+
+/* init timer register */
+int timer_init(void)
+{
+	struct sunxi_timer_reg *timers =
+		(struct sunxi_timer_reg *)SUNXI_TIMER_BASE;
+	struct sunxi_timer *timer = &timers->timer[TIMER_NUM];
+	writel(TIMER_LOAD_VAL, &timer->inter);
+	writel(TIMER_MODE | TIMER_DIV | TIMER_SRC | TIMER_RELOAD | TIMER_EN,
+	       &timer->ctl);
+
+	return 0;
+}
+
+/* timer without interrupts */
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+ulong get_timer_masked(void)
+{
+	/* current tick value */
+	ulong now = TICKS_TO_HZ(read_timer());
+
+	if (now >= gd->arch.lastinc)	/* normal (non rollover) */
+		gd->arch.tbl += (now - gd->arch.lastinc);
+	else {
+		/* rollover */
+		gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL)
+				- gd->arch.lastinc) + now;
+	}
+	gd->arch.lastinc = now;
+
+	return gd->arch.tbl;
+}
+
+/* delay x useconds */
+void __udelay(unsigned long usec)
+{
+	long tmo = USEC_TO_COUNT(usec);
+	ulong now, last = read_timer();
+
+	while (tmo > 0) {
+		now = read_timer();
+		if (now > last)	/* normal (non rollover) */
+			tmo -= now - last;
+		else		/* rollover */
+			tmo -= TIMER_LOAD_VAL - last + now;
+		last = now;
+	}
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
new file mode 100644
index 0000000000000000000000000000000000000000..364e35c32fea03c8947705d7969af04302ae6b37
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
@@ -0,0 +1,77 @@
+/*
+ * (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);
+	. = .;
+
+	. = 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/cpu/armv7/sunxi/u-boot-spl.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
new file mode 100644
index 0000000000000000000000000000000000000000..5008028aae829bf46cf2a648358fcb5cf9ef740b
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
@@ -0,0 +1,52 @@
+/*
+ * (C) Copyright 2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Based on omap-common/u-boot-spl.lds:
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *	Aneesh V <aneesh@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+		LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	.text      :
+	{
+		__start = .;
+		arch/arm/cpu/armv7/start.o	(.text)
+		*(.text*)
+	} > .sram
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+	. = ALIGN(4);
+	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+	. = ALIGN(4);
+	__image_copy_end = .;
+	_end = .;
+
+	.bss :
+	{
+		. = ALIGN(4);
+		__bss_start = .;
+		*(.bss*)
+		. = ALIGN(4);
+		__bss_end = .;
+	} > .sdram
+}
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index 33d3f3688ae83bc45f13a79e12c84a0848d20d05..4b11aa4f22272cfa1766b0482ff8b1797e15db6e 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -50,10 +50,10 @@ reset:
 	 */
 	adr	x0, vectors
 	switch_el x1, 3f, 2f, 1f
-3:	mrs	x0, scr_el3
+3:	msr	vbar_el3, x0
+	mrs	x0, scr_el3
 	orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */
 	msr	scr_el3, x0
-	msr	vbar_el3, x0
 	msr	cptr_el3, xzr			/* Enable FP/SIMD */
 	ldr	x0, =COUNTER_FREQUENCY
 	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */
diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
index 7f4debb912597d5a251cfa095b0309497b2528b0..cbb5a529da2b520fb841e8cc77f2357606abeb3b 100644
--- a/arch/arm/cpu/at91-common/spl.c
+++ b/arch/arm/cpu/at91-common/spl.c
@@ -20,6 +20,43 @@ static void at91_disable_wdt(void)
 	writel(AT91_WDT_MR_WDDIS, &wdt->mr);
 }
 
+static void switch_to_main_crystal_osc(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	u32 tmp;
+
+	tmp = readl(&pmc->mor);
+	tmp &= ~AT91_PMC_MOR_OSCOUNT(0xff);
+	tmp &= ~AT91_PMC_MOR_KEY(0xff);
+	tmp |= AT91_PMC_MOR_MOSCEN;
+	tmp |= AT91_PMC_MOR_OSCOUNT(8);
+	tmp |= AT91_PMC_MOR_KEY(0x37);
+	writel(tmp, &pmc->mor);
+	while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCS))
+		;
+
+	tmp = readl(&pmc->mor);
+	tmp &= ~AT91_PMC_MOR_OSCBYPASS;
+	tmp &= ~AT91_PMC_MOR_KEY(0xff);
+	tmp |= AT91_PMC_MOR_KEY(0x37);
+	writel(tmp, &pmc->mor);
+
+	tmp = readl(&pmc->mor);
+	tmp |= AT91_PMC_MOR_MOSCSEL;
+	tmp &= ~AT91_PMC_MOR_KEY(0xff);
+	tmp |= AT91_PMC_MOR_KEY(0x37);
+	writel(tmp, &pmc->mor);
+
+	while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCSELS))
+		;
+
+	tmp = readl(&pmc->mor);
+	tmp &= ~AT91_PMC_MOR_MOSCRCEN;
+	tmp &= ~AT91_PMC_MOR_KEY(0xff);
+	tmp |= AT91_PMC_MOR_KEY(0x37);
+	writel(tmp, &pmc->mor);
+}
+
 void at91_plla_init(u32 pllar)
 {
 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
@@ -76,6 +113,8 @@ u32 spl_boot_mode(void)
 
 void s_init(void)
 {
+	switch_to_main_crystal_osc();
+
 	/* disable watchdog */
 	at91_disable_wdt();
 
diff --git a/arch/arm/include/asm/arch-at91/at91_pmc.h b/arch/arm/include/asm/arch-at91/at91_pmc.h
index 4535608434c0b3de54e16596bc4c9e85b60ea7c9..04f6239fd0b846da6acd5e5227c861b517a8a72e 100644
--- a/arch/arm/include/asm/arch-at91/at91_pmc.h
+++ b/arch/arm/include/asm/arch-at91/at91_pmc.h
@@ -70,7 +70,10 @@ typedef struct at91_pmc {
 
 #define AT91_PMC_MOR_MOSCEN		0x01
 #define AT91_PMC_MOR_OSCBYPASS		0x02
+#define AT91_PMC_MOR_MOSCRCEN		0x08
 #define AT91_PMC_MOR_OSCOUNT(x)		((x & 0xff) << 8)
+#define AT91_PMC_MOR_KEY(x)		((x & 0xff) << 16)
+#define AT91_PMC_MOR_MOSCSEL		(1 << 24)
 
 #define AT91_PMC_PLLXR_DIV(x)		(x & 0xFF)
 #define AT91_PMC_PLLXR_PLLCOUNT(x)	((x & 0x3F) << 8)
@@ -142,6 +145,7 @@ typedef struct at91_pmc {
 #define AT91_PMC_IXR_PCKRDY1		0x00000200
 #define AT91_PMC_IXR_PCKRDY2		0x00000400
 #define AT91_PMC_IXR_PCKRDY3		0x00000800
+#define AT91_PMC_IXR_MOSCSELS		0x00010000
 
 #define		AT91_PMC_PCK		(1 <<  0)		/* Processor Clock */
 #define		AT91RM9200_PMC_UDP	(1 <<  1)		/* USB Devcice Port Clock [AT91RM9200 only] */
diff --git a/arch/arm/include/asm/arch-at91/at91sam9x5.h b/arch/arm/include/asm/arch-at91/at91sam9x5.h
index a47103851e48594c1a19b64d4d1a1ef2303a1e89..d49c18480dca68ac56c9eec2aa83ba549e7ee002 100644
--- a/arch/arm/include/asm/arch-at91/at91sam9x5.h
+++ b/arch/arm/include/asm/arch-at91/at91sam9x5.h
@@ -12,6 +12,9 @@
 #ifndef __AT91SAM9X5_H__
 #define __AT91SAM9X5_H__
 
+#define CONFIG_ARM926EJS	/* ARM926EJS Core */
+#define CONFIG_AT91FAMILY	/* it's a member of AT91 family */
+
 /*
  * Peripheral identifiers/interrupts.
  */
diff --git a/arch/arm/include/asm/arch-at91/hardware.h b/arch/arm/include/asm/arch-at91/hardware.h
index a63f97406020753baf0efd7ee936b747d9446bdf..d712a0dc9136c47f52eed8cbed253114163a7952 100644
--- a/arch/arm/include/asm/arch-at91/hardware.h
+++ b/arch/arm/include/asm/arch-at91/hardware.h
@@ -25,8 +25,6 @@
 # include <asm/arch/at91sam9x5.h>
 #elif defined(CONFIG_AT91CAP9)
 # include <asm/arch/at91cap9.h>
-#elif defined(CONFIG_AT91X40)
-# include <asm/arch/at91x40.h>
 #elif defined(CONFIG_SAMA5D3)
 # include <asm/arch/sama5d3.h>
 #else
diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
new file mode 100644
index 0000000000000000000000000000000000000000..5669f392fab7a38e56558cc2f74ea5c903009b30
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/clock.h
@@ -0,0 +1,29 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_CLOCK_H
+#define _SUNXI_CLOCK_H
+
+#include <linux/types.h>
+
+#define CLK_GATE_OPEN			0x1
+#define CLK_GATE_CLOSE			0x0
+
+/* clock control module regs definition */
+#include <asm/arch/clock_sun4i.h>
+
+#ifndef __ASSEMBLY__
+int clock_init(void);
+int clock_twi_onoff(int port, int state);
+void clock_set_pll1(unsigned int hz);
+unsigned int clock_get_pll6(void);
+void clock_init_safe(void);
+void clock_init_uart(void);
+#endif
+
+#endif /* _SUNXI_CLOCK_H */
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
new file mode 100644
index 0000000000000000000000000000000000000000..928f3f2670997285bdeb34aaa749e00d44a9d9fb
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
@@ -0,0 +1,256 @@
+/*
+ * sun4i, sun5i and sun7i clock register definitions
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_CLOCK_SUN4I_H
+#define _SUNXI_CLOCK_SUN4I_H
+
+struct sunxi_ccm_reg {
+	u32 pll1_cfg;		/* 0x00 pll1 control */
+	u32 pll1_tun;		/* 0x04 pll1 tuning */
+	u32 pll2_cfg;		/* 0x08 pll2 control */
+	u32 pll2_tun;		/* 0x0c pll2 tuning */
+	u32 pll3_cfg;		/* 0x10 pll3 control */
+	u8 res0[0x4];
+	u32 pll4_cfg;		/* 0x18 pll4 control */
+	u8 res1[0x4];
+	u32 pll5_cfg;		/* 0x20 pll5 control */
+	u32 pll5_tun;		/* 0x24 pll5 tuning */
+	u32 pll6_cfg;		/* 0x28 pll6 control */
+	u32 pll6_tun;		/* 0x2c pll6 tuning */
+	u32 pll7_cfg;		/* 0x30 pll7 control */
+	u32 pll1_tun2;		/* 0x34 pll5 tuning2 */
+	u8 res2[0x4];
+	u32 pll5_tun2;		/* 0x3c pll5 tuning2 */
+	u8 res3[0xc];
+	u32 pll_lock_dbg;	/* 0x4c pll lock time debug */
+	u32 osc24m_cfg;		/* 0x50 osc24m control */
+	u32 cpu_ahb_apb0_cfg;	/* 0x54 cpu,ahb and apb0 divide ratio */
+	u32 apb1_clk_div_cfg;	/* 0x58 apb1 clock dividor */
+	u32 axi_gate;		/* 0x5c axi module clock gating */
+	u32 ahb_gate0;		/* 0x60 ahb module clock gating 0 */
+	u32 ahb_gate1;		/* 0x64 ahb module clock gating 1 */
+	u32 apb0_gate;		/* 0x68 apb0 module clock gating */
+	u32 apb1_gate;		/* 0x6c apb1 module clock gating */
+	u8 res4[0x10];
+	u32 nand_sclk_cfg;	/* 0x80 nand sub clock control */
+	u32 ms_sclk_cfg;	/* 0x84 memory stick sub clock control */
+	u32 sd0_clk_cfg;	/* 0x88 sd0 clock control */
+	u32 sd1_clk_cfg;	/* 0x8c sd1 clock control */
+	u32 sd2_clk_cfg;	/* 0x90 sd2 clock control */
+	u32 sd3_clk_cfg;	/* 0x94 sd3 clock control */
+	u32 ts_clk_cfg;		/* 0x98 transport stream clock control */
+	u32 ss_clk_cfg;		/* 0x9c */
+	u32 spi0_clk_cfg;	/* 0xa0 */
+	u32 spi1_clk_cfg;	/* 0xa4 */
+	u32 spi2_clk_cfg;	/* 0xa8 */
+	u32 pata_clk_cfg;	/* 0xac */
+	u32 ir0_clk_cfg;	/* 0xb0 */
+	u32 ir1_clk_cfg;	/* 0xb4 */
+	u32 iis_clk_cfg;	/* 0xb8 */
+	u32 ac97_clk_cfg;	/* 0xbc */
+	u32 spdif_clk_cfg;	/* 0xc0 */
+	u32 keypad_clk_cfg;	/* 0xc4 */
+	u32 sata_clk_cfg;	/* 0xc8 */
+	u32 usb_clk_cfg;	/* 0xcc */
+	u32 gps_clk_cfg;	/* 0xd0 */
+	u32 spi3_clk_cfg;	/* 0xd4 */
+	u8 res5[0x28];
+	u32 dram_clk_cfg;	/* 0x100 */
+	u32 be0_clk_cfg;	/* 0x104 */
+	u32 be1_clk_cfg;	/* 0x108 */
+	u32 fe0_clk_cfg;	/* 0x10c */
+	u32 fe1_clk_cfg;	/* 0x110 */
+	u32 mp_clk_cfg;		/* 0x114 */
+	u32 lcd0_ch0_clk_cfg;	/* 0x118 */
+	u32 lcd1_ch0_clk_cfg;	/* 0x11c */
+	u32 csi_isp_clk_cfg;	/* 0x120 */
+	u8 res6[0x4];
+	u32 tvd_clk_reg;	/* 0x128 */
+	u32 lcd0_ch1_clk_cfg;	/* 0x12c */
+	u32 lcd1_ch1_clk_cfg;	/* 0x130 */
+	u32 csi0_clk_cfg;	/* 0x134 */
+	u32 csi1_clk_cfg;	/* 0x138 */
+	u32 ve_clk_cfg;		/* 0x13c */
+	u32 audio_codec_clk_cfg;	/* 0x140 */
+	u32 avs_clk_cfg;	/* 0x144 */
+	u32 ace_clk_cfg;	/* 0x148 */
+	u32 lvds_clk_cfg;	/* 0x14c */
+	u32 hdmi_clk_cfg;	/* 0x150 */
+	u32 mali_clk_cfg;	/* 0x154 */
+	u8 res7[0x4];
+	u32 mbus_clk_cfg;	/* 0x15c */
+	u8 res8[0x4];
+	u32 gmac_clk_cfg;	/* 0x164 */
+};
+
+/* apb1 bit field */
+#define APB1_CLK_SRC_OSC24M		(0x0 << 24)
+#define APB1_CLK_SRC_PLL6		(0x1 << 24)
+#define APB1_CLK_SRC_LOSC		(0x2 << 24)
+#define APB1_CLK_SRC_MASK		(0x3 << 24)
+#define APB1_CLK_RATE_N_1		(0x0 << 16)
+#define APB1_CLK_RATE_N_2		(0x1 << 16)
+#define APB1_CLK_RATE_N_4		(0x2 << 16)
+#define APB1_CLK_RATE_N_8		(0x3 << 16)
+#define APB1_CLK_RATE_N_MASK		(3 << 16)
+#define APB1_CLK_RATE_M(m)		(((m)-1) << 0)
+#define APB1_CLK_RATE_M_MASK            (0x1f << 0)
+
+/* apb1 gate field */
+#define APB1_GATE_UART_SHIFT	(16)
+#define APB1_GATE_UART_MASK		(0xff << APB1_GATE_UART_SHIFT)
+#define APB1_GATE_TWI_SHIFT	(0)
+#define APB1_GATE_TWI_MASK		(0xf << APB1_GATE_TWI_SHIFT)
+
+/* clock divide */
+#define AXI_DIV_SHIFT		(0)
+#define AXI_DIV_1			0
+#define AXI_DIV_2			1
+#define AXI_DIV_3			2
+#define AXI_DIV_4			3
+#define AHB_DIV_SHIFT		(4)
+#define AHB_DIV_1			0
+#define AHB_DIV_2			1
+#define AHB_DIV_4			2
+#define AHB_DIV_8			3
+#define APB0_DIV_SHIFT		(8)
+#define APB0_DIV_1			0
+#define APB0_DIV_2			1
+#define APB0_DIV_4			2
+#define APB0_DIV_8			3
+#define CPU_CLK_SRC_SHIFT	(16)
+#define CPU_CLK_SRC_OSC24M		1
+#define CPU_CLK_SRC_PLL1		2
+
+#define CCM_PLL1_CFG_ENABLE_SHIFT		31
+#define CCM_PLL1_CFG_VCO_RST_SHIFT		30
+#define CCM_PLL1_CFG_VCO_BIAS_SHIFT		26
+#define CCM_PLL1_CFG_PLL4_EXCH_SHIFT		25
+#define CCM_PLL1_CFG_BIAS_CUR_SHIFT		20
+#define CCM_PLL1_CFG_DIVP_SHIFT			16
+#define CCM_PLL1_CFG_LCK_TMR_SHIFT		13
+#define CCM_PLL1_CFG_FACTOR_N_SHIFT		8
+#define CCM_PLL1_CFG_FACTOR_K_SHIFT		4
+#define CCM_PLL1_CFG_SIG_DELT_PAT_IN_SHIFT	3
+#define CCM_PLL1_CFG_SIG_DELT_PAT_EN_SHIFT	2
+#define CCM_PLL1_CFG_FACTOR_M_SHIFT		0
+
+#define PLL1_CFG_DEFAULT	0xa1005000
+
+#define PLL6_CFG_DEFAULT	0xa1009911
+
+/* nand clock */
+#define NAND_CLK_SRC_OSC24		0
+#define NAND_CLK_DIV_N			0
+#define NAND_CLK_DIV_M			0
+
+/* gps clock */
+#define GPS_SCLK_GATING_OFF		0
+#define GPS_RESET			0
+
+/* ahb clock gate bit offset */
+#define AHB_GATE_OFFSET_GPS		26
+#define AHB_GATE_OFFSET_SATA		25
+#define AHB_GATE_OFFSET_PATA		24
+#define AHB_GATE_OFFSET_SPI3		23
+#define AHB_GATE_OFFSET_SPI2		22
+#define AHB_GATE_OFFSET_SPI1		21
+#define AHB_GATE_OFFSET_SPI0		20
+#define AHB_GATE_OFFSET_TS0		18
+#define AHB_GATE_OFFSET_EMAC		17
+#define AHB_GATE_OFFSET_ACE		16
+#define AHB_GATE_OFFSET_DLL		15
+#define AHB_GATE_OFFSET_SDRAM		14
+#define AHB_GATE_OFFSET_NAND		13
+#define AHB_GATE_OFFSET_MS		12
+#define AHB_GATE_OFFSET_MMC3		11
+#define AHB_GATE_OFFSET_MMC2		10
+#define AHB_GATE_OFFSET_MMC1		9
+#define AHB_GATE_OFFSET_MMC0		8
+#define AHB_GATE_OFFSET_MMC(n)		(AHB_GATE_OFFSET_MMC0 + (n))
+#define AHB_GATE_OFFSET_BIST		7
+#define AHB_GATE_OFFSET_DMA		6
+#define AHB_GATE_OFFSET_SS		5
+#define AHB_GATE_OFFSET_USB_OHCI1	4
+#define AHB_GATE_OFFSET_USB_EHCI1	3
+#define AHB_GATE_OFFSET_USB_OHCI0	2
+#define AHB_GATE_OFFSET_USB_EHCI0	1
+#define AHB_GATE_OFFSET_USB		0
+
+/* ahb clock gate bit offset (second register) */
+#define AHB_GATE_OFFSET_GMAC		17
+
+#define CCM_AHB_GATE_GPS (0x1 << 26)
+#define CCM_AHB_GATE_SDRAM (0x1 << 14)
+#define CCM_AHB_GATE_DLL (0x1 << 15)
+#define CCM_AHB_GATE_ACE (0x1 << 16)
+
+#define CCM_PLL5_CTRL_M(n) (((n) & 0x3) << 0)
+#define CCM_PLL5_CTRL_M_MASK CCM_PLL5_CTRL_M(0x3)
+#define CCM_PLL5_CTRL_M_X(n) ((n) - 1)
+#define CCM_PLL5_CTRL_M1(n) (((n) & 0x3) << 2)
+#define CCM_PLL5_CTRL_M1_MASK CCM_PLL5_CTRL_M1(0x3)
+#define CCM_PLL5_CTRL_M1_X(n) ((n) - 1)
+#define CCM_PLL5_CTRL_K(n) (((n) & 0x3) << 4)
+#define CCM_PLL5_CTRL_K_MASK CCM_PLL5_CTRL_K(0x3)
+#define CCM_PLL5_CTRL_K_X(n) ((n) - 1)
+#define CCM_PLL5_CTRL_LDO (0x1 << 7)
+#define CCM_PLL5_CTRL_N(n) (((n) & 0x1f) << 8)
+#define CCM_PLL5_CTRL_N_MASK CCM_PLL5_CTRL_N(0x1f)
+#define CCM_PLL5_CTRL_N_X(n) (n)
+#define CCM_PLL5_CTRL_P(n) (((n) & 0x3) << 16)
+#define CCM_PLL5_CTRL_P_MASK CCM_PLL5_CTRL_P(0x3)
+#define CCM_PLL5_CTRL_P_X(n) ((n) - 1)
+#define CCM_PLL5_CTRL_BW (0x1 << 18)
+#define CCM_PLL5_CTRL_VCO_GAIN (0x1 << 19)
+#define CCM_PLL5_CTRL_BIAS(n) (((n) & 0x1f) << 20)
+#define CCM_PLL5_CTRL_BIAS_MASK CCM_PLL5_CTRL_BIAS(0x1f)
+#define CCM_PLL5_CTRL_BIAS_X(n) ((n) - 1)
+#define CCM_PLL5_CTRL_VCO_BIAS (0x1 << 25)
+#define CCM_PLL5_CTRL_DDR_CLK (0x1 << 29)
+#define CCM_PLL5_CTRL_BYPASS (0x1 << 30)
+#define CCM_PLL5_CTRL_EN (0x1 << 31)
+
+#define CCM_PLL6_CTRL_N_SHIFT	8
+#define CCM_PLL6_CTRL_N_MASK	(0x1f << CCM_PLL6_CTRL_N_SHIFT)
+#define CCM_PLL6_CTRL_K_SHIFT	4
+#define CCM_PLL6_CTRL_K_MASK	(0x3 << CCM_PLL6_CTRL_K_SHIFT)
+
+#define CCM_GPS_CTRL_RESET (0x1 << 0)
+#define CCM_GPS_CTRL_GATE (0x1 << 1)
+
+#define CCM_DRAM_CTRL_DCLK_OUT (0x1 << 15)
+
+#define CCM_MBUS_CTRL_M(n) (((n) & 0xf) << 0)
+#define CCM_MBUS_CTRL_M_MASK CCM_MBUS_CTRL_M(0xf)
+#define CCM_MBUS_CTRL_M_X(n) ((n) - 1)
+#define CCM_MBUS_CTRL_N(n) (((n) & 0xf) << 16)
+#define CCM_MBUS_CTRL_N_MASK CCM_MBUS_CTRL_N(0xf)
+#define CCM_MBUS_CTRL_N_X(n) (((n) >> 3) ? 3 : (((n) >> 2) ? 2 : (((n) >> 1) ? 1 : 0)))
+#define CCM_MBUS_CTRL_CLK_SRC(n) (((n) & 0x3) << 24)
+#define CCM_MBUS_CTRL_CLK_SRC_MASK CCM_MBUS_CTRL_CLK_SRC(0x3)
+#define CCM_MBUS_CTRL_CLK_SRC_HOSC 0x0
+#define CCM_MBUS_CTRL_CLK_SRC_PLL6 0x1
+#define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2
+#define CCM_MBUS_CTRL_GATE (0x1 << 31)
+
+#define CCM_MMC_CTRL_OSCM24 (0x0 << 24)
+#define CCM_MMC_CTRL_PLL6   (0x1 << 24)
+#define CCM_MMC_CTRL_PLL5   (0x2 << 24)
+
+#define CCM_MMC_CTRL_ENABLE (0x1 << 31)
+
+#define CCM_GMAC_CTRL_TX_CLK_SRC_MII 0x0
+#define CCM_GMAC_CTRL_TX_CLK_SRC_EXT_RGMII 0x1
+#define CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII 0x2
+#define CCM_GMAC_CTRL_GPIT_MII (0x0 << 2)
+#define CCM_GMAC_CTRL_GPIT_RGMII (0x1 << 2)
+
+#endif /* _SUNXI_CLOCK_SUN4I_H */
diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..a987e51d576902d9ec94c6f4196a97e14e899e7f
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/cpu.h
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_CPU_H
+#define _SUNXI_CPU_H
+
+#define SUNXI_SRAM_A1_BASE		0x00000000
+#define SUNXI_SRAM_A1_SIZE		(16 * 1024)	/* 16 kiB */
+
+#define SUNXI_SRAM_A2_BASE		0x00004000	/* 16 kiB */
+#define SUNXI_SRAM_A3_BASE		0x00008000	/* 13 kiB */
+#define SUNXI_SRAM_A4_BASE		0x0000b400	/* 3 kiB */
+#define SUNXI_SRAM_D_BASE		0x00010000	/* 4 kiB */
+#define SUNXI_SRAM_B_BASE		0x00020000	/* 64 kiB (secure) */
+
+#define SUNXI_SRAMC_BASE		0x01c00000
+#define SUNXI_DRAMC_BASE		0x01c01000
+#define SUNXI_DMA_BASE			0x01c02000
+#define SUNXI_NFC_BASE			0x01c03000
+#define SUNXI_TS_BASE			0x01c04000
+#define SUNXI_SPI0_BASE			0x01c05000
+#define SUNXI_SPI1_BASE			0x01c06000
+#define SUNXI_MS_BASE			0x01c07000
+#define SUNXI_TVD_BASE			0x01c08000
+#define SUNXI_CSI0_BASE			0x01c09000
+#define SUNXI_TVE0_BASE			0x01c0a000
+#define SUNXI_EMAC_BASE			0x01c0b000
+#define SUNXI_LCD0_BASE			0x01c0C000
+#define SUNXI_LCD1_BASE			0x01c0d000
+#define SUNXI_VE_BASE			0x01c0e000
+#define SUNXI_MMC0_BASE			0x01c0f000
+#define SUNXI_MMC1_BASE			0x01c10000
+#define SUNXI_MMC2_BASE			0x01c11000
+#define SUNXI_MMC3_BASE			0x01c12000
+#define SUNXI_USB0_BASE			0x01c13000
+#define SUNXI_USB1_BASE			0x01c14000
+#define SUNXI_SS_BASE			0x01c15000
+#define SUNXI_HDMI_BASE			0x01c16000
+#define SUNXI_SPI2_BASE			0x01c17000
+#define SUNXI_SATA_BASE			0x01c18000
+#define SUNXI_PATA_BASE			0x01c19000
+#define SUNXI_ACE_BASE			0x01c1a000
+#define SUNXI_TVE1_BASE			0x01c1b000
+#define SUNXI_USB2_BASE			0x01c1c000
+#define SUNXI_CSI1_BASE			0x01c1d000
+#define SUNXI_TZASC_BASE		0x01c1e000
+#define SUNXI_SPI3_BASE			0x01c1f000
+
+#define SUNXI_CCM_BASE			0x01c20000
+#define SUNXI_INTC_BASE			0x01c20400
+#define SUNXI_PIO_BASE			0x01c20800
+#define SUNXI_TIMER_BASE		0x01c20c00
+#define SUNXI_SPDIF_BASE		0x01c21000
+#define SUNXI_AC97_BASE			0x01c21400
+#define SUNXI_IR0_BASE			0x01c21800
+#define SUNXI_IR1_BASE			0x01c21c00
+
+#define SUNXI_IIS_BASE			0x01c22400
+#define SUNXI_LRADC_BASE		0x01c22800
+#define SUNXI_AD_DA_BASE		0x01c22c00
+#define SUNXI_KEYPAD_BASE		0x01c23000
+#define SUNXI_TZPC_BASE			0x01c23400
+#define SUNXI_SID_BASE			0x01c23800
+#define SUNXI_SJTAG_BASE		0x01c23c00
+
+#define SUNXI_TP_BASE			0x01c25000
+#define SUNXI_PMU_BASE			0x01c25400
+#define SUNXI_CPUCFG_BASE              0x01c25c00
+
+#define SUNXI_UART0_BASE		0x01c28000
+#define SUNXI_UART1_BASE		0x01c28400
+#define SUNXI_UART2_BASE		0x01c28800
+#define SUNXI_UART3_BASE		0x01c28c00
+#define SUNXI_UART4_BASE		0x01c29000
+#define SUNXI_UART5_BASE		0x01c29400
+#define SUNXI_UART6_BASE		0x01c29800
+#define SUNXI_UART7_BASE		0x01c29c00
+#define SUNXI_PS2_0_BASE		0x01c2a000
+#define SUNXI_PS2_1_BASE		0x01c2a400
+
+#define SUNXI_TWI0_BASE			0x01c2ac00
+#define SUNXI_TWI1_BASE			0x01c2b000
+#define SUNXI_TWI2_BASE			0x01c2b400
+
+#define SUNXI_CAN_BASE			0x01c2bc00
+
+#define SUNXI_SCR_BASE			0x01c2c400
+
+#define SUNXI_GPS_BASE			0x01c30000
+#define SUNXI_MALI400_BASE		0x01c40000
+#define SUNXI_GMAC_BASE			0x01c50000
+
+/* module sram */
+#define SUNXI_SRAM_C_BASE		0x01d00000
+
+#define SUNXI_DE_FE0_BASE		0x01e00000
+#define SUNXI_DE_FE1_BASE		0x01e20000
+#define SUNXI_DE_BE0_BASE		0x01e60000
+#define SUNXI_DE_BE1_BASE		0x01e40000
+#define SUNXI_MP_BASE			0x01e80000
+#define SUNXI_AVG_BASE			0x01ea0000
+
+/* CoreSight Debug Module */
+#define SUNXI_CSDM_BASE			0x3f500000
+
+#define SUNXI_DDRII_DDRIII_BASE		0x40000000	/* 2 GiB */
+
+#define SUNXI_BROM_BASE			0xffff0000	/* 32 kiB */
+
+#define SUNXI_CPU_CFG			(SUNXI_TIMER_BASE + 0x13c)
+
+#ifndef __ASSEMBLY__
+void sunxi_board_init(void);
+void sunxi_reset(void);
+#endif /* __ASSEMBLY__ */
+
+#endif /* _CPU_H */
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
new file mode 100644
index 0000000000000000000000000000000000000000..67fbfad07eafda131c96e4fff63cbeef3766cfb4
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Berg Xing <bergxing@allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Sunxi platform dram register definition.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_H
+#define _SUNXI_DRAM_H
+
+#include <linux/types.h>
+
+struct sunxi_dram_reg {
+	u32 ccr;		/* 0x00 controller configuration register */
+	u32 dcr;		/* 0x04 dram configuration register */
+	u32 iocr;		/* 0x08 i/o configuration register */
+	u32 csr;		/* 0x0c controller status register */
+	u32 drr;		/* 0x10 dram refresh register */
+	u32 tpr0;		/* 0x14 dram timing parameters register 0 */
+	u32 tpr1;		/* 0x18 dram timing parameters register 1 */
+	u32 tpr2;		/* 0x1c dram timing parameters register 2 */
+	u32 gdllcr;		/* 0x20 global dll control register */
+	u8 res0[0x28];
+	u32 rslr0;		/* 0x4c rank system latency register */
+	u32 rslr1;		/* 0x50 rank system latency register */
+	u8 res1[0x8];
+	u32 rdgr0;		/* 0x5c rank dqs gating register */
+	u32 rdgr1;		/* 0x60 rank dqs gating register */
+	u8 res2[0x34];
+	u32 odtcr;		/* 0x98 odt configuration register */
+	u32 dtr0;		/* 0x9c data training register 0 */
+	u32 dtr1;		/* 0xa0 data training register 1 */
+	u32 dtar;		/* 0xa4 data training address register */
+	u32 zqcr0;		/* 0xa8 zq control register 0 */
+	u32 zqcr1;		/* 0xac zq control register 1 */
+	u32 zqsr;		/* 0xb0 zq status register */
+	u32 idcr;		/* 0xb4 initializaton delay configure reg */
+	u8 res3[0x138];
+	u32 mr;			/* 0x1f0 mode register */
+	u32 emr;		/* 0x1f4 extended mode register */
+	u32 emr2;		/* 0x1f8 extended mode register */
+	u32 emr3;		/* 0x1fc extended mode register */
+	u32 dllctr;		/* 0x200 dll control register */
+	u32 dllcr[5];		/* 0x204 dll control register 0(byte 0) */
+	/* 0x208 dll control register 1(byte 1) */
+	/* 0x20c dll control register 2(byte 2) */
+	/* 0x210 dll control register 3(byte 3) */
+	/* 0x214 dll control register 4(byte 4) */
+	u32 dqtr0;		/* 0x218 dq timing register */
+	u32 dqtr1;		/* 0x21c dq timing register */
+	u32 dqtr2;		/* 0x220 dq timing register */
+	u32 dqtr3;		/* 0x224 dq timing register */
+	u32 dqstr;		/* 0x228 dqs timing register */
+	u32 dqsbtr;		/* 0x22c dqsb timing register */
+	u32 mcr;		/* 0x230 mode configure register */
+	u8 res[0x8];
+	u32 ppwrsctl;		/* 0x23c pad power save control */
+	u32 apr;		/* 0x240 arbiter period register */
+	u32 pldtr;		/* 0x244 priority level data threshold reg */
+	u8 res5[0x8];
+	u32 hpcr[32];		/* 0x250 host port configure register */
+	u8 res6[0x10];
+	u32 csel;		/* 0x2e0 controller select register */
+};
+
+struct dram_para {
+	u32 clock;
+	u32 type;
+	u32 rank_num;
+	u32 density;
+	u32 io_width;
+	u32 bus_width;
+	u32 cas;
+	u32 zq;
+	u32 odt_en;
+	u32 size;
+	u32 tpr0;
+	u32 tpr1;
+	u32 tpr2;
+	u32 tpr3;
+	u32 tpr4;
+	u32 tpr5;
+	u32 emr1;
+	u32 emr2;
+	u32 emr3;
+};
+
+#define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5)
+#define DRAM_CCR_DQS_GATE (0x1 << 14)
+#define DRAM_CCR_DQS_DRIFT_COMP (0x1 << 17)
+#define DRAM_CCR_ITM_OFF (0x1 << 28)
+#define DRAM_CCR_DATA_TRAINING (0x1 << 30)
+#define DRAM_CCR_INIT (0x1 << 31)
+
+#define DRAM_MEMORY_TYPE_DDR1 1
+#define DRAM_MEMORY_TYPE_DDR2 2
+#define DRAM_MEMORY_TYPE_DDR3 3
+#define DRAM_MEMORY_TYPE_LPDDR2 4
+#define DRAM_MEMORY_TYPE_LPDDR 5
+#define DRAM_DCR_TYPE (0x1 << 0)
+#define DRAM_DCR_TYPE_DDR2 0x0
+#define DRAM_DCR_TYPE_DDR3 0x1
+#define DRAM_DCR_IO_WIDTH(n) (((n) & 0x3) << 1)
+#define DRAM_DCR_IO_WIDTH_MASK DRAM_DCR_IO_WIDTH(0x3)
+#define DRAM_DCR_IO_WIDTH_8BIT 0x0
+#define DRAM_DCR_IO_WIDTH_16BIT 0x1
+#define DRAM_DCR_CHIP_DENSITY(n) (((n) & 0x7) << 3)
+#define DRAM_DCR_CHIP_DENSITY_MASK DRAM_DCR_CHIP_DENSITY(0x7)
+#define DRAM_DCR_CHIP_DENSITY_256M 0x0
+#define DRAM_DCR_CHIP_DENSITY_512M 0x1
+#define DRAM_DCR_CHIP_DENSITY_1024M 0x2
+#define DRAM_DCR_CHIP_DENSITY_2048M 0x3
+#define DRAM_DCR_CHIP_DENSITY_4096M 0x4
+#define DRAM_DCR_CHIP_DENSITY_8192M 0x5
+#define DRAM_DCR_BUS_WIDTH(n) (((n) & 0x7) << 6)
+#define DRAM_DCR_BUS_WIDTH_MASK DRAM_DCR_BUS_WIDTH(0x7)
+#define DRAM_DCR_BUS_WIDTH_32BIT 0x3
+#define DRAM_DCR_BUS_WIDTH_16BIT 0x1
+#define DRAM_DCR_BUS_WIDTH_8BIT 0x0
+#define DRAM_DCR_NR_DLLCR_32BIT 5
+#define DRAM_DCR_NR_DLLCR_16BIT 3
+#define DRAM_DCR_NR_DLLCR_8BIT 2
+#define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10)
+#define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3)
+#define DRAM_DCR_CMD_RANK_ALL (0x1 << 12)
+#define DRAM_DCR_MODE(n) (((n) & 0x3) << 13)
+#define DRAM_DCR_MODE_MASK DRAM_DCR_MODE(0x3)
+#define DRAM_DCR_MODE_SEQ 0x0
+#define DRAM_DCR_MODE_INTERLEAVE 0x1
+
+#define DRAM_CSR_FAILED (0x1 << 20)
+
+#define DRAM_DRR_TRFC(n) ((n) & 0xff)
+#define DRAM_DRR_TREFI(n) (((n) & 0xffff) << 8)
+#define DRAM_DRR_BURST(n) ((((n) - 1) & 0xf) << 24)
+
+#define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0)
+#define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3)
+#define DRAM_MCR_MODE_DQ_OUT(n) (((n) & 0x3) << 2)
+#define DRAM_MCR_MODE_DQ_OUT_MASK DRAM_MCR_MODE_DQ_OUT(0x3)
+#define DRAM_MCR_MODE_ADDR_OUT(n) (((n) & 0x3) << 4)
+#define DRAM_MCR_MODE_ADDR_OUT_MASK DRAM_MCR_MODE_ADDR_OUT(0x3)
+#define DRAM_MCR_MODE_DQ_IN_OUT(n) (((n) & 0x3) << 6)
+#define DRAM_MCR_MODE_DQ_IN_OUT_MASK DRAM_MCR_MODE_DQ_IN_OUT(0x3)
+#define DRAM_MCR_MODE_DQ_TURNON_DELAY(n) (((n) & 0x7) << 8)
+#define DRAM_MCR_MODE_DQ_TURNON_DELAY_MASK DRAM_MCR_MODE_DQ_TURNON_DELAY(0x7)
+#define DRAM_MCR_MODE_ADDR_IN (0x1 << 11)
+#define DRAM_MCR_RESET (0x1 << 12)
+#define DRAM_MCR_MODE_EN(n) (((n) & 0x3) << 13)
+#define DRAM_MCR_MODE_EN_MASK DRAM_MCR_MOD_EN(0x3)
+#define DRAM_MCR_DCLK_OUT (0x1 << 16)
+
+#define DRAM_DLLCR_NRESET (0x1 << 30)
+#define DRAM_DLLCR_DISABLE (0x1 << 31)
+
+#define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20)
+#define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff)
+
+#define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0)
+#define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3)
+
+#define DRAM_MR_BURST_LENGTH(n) (((n) & 0x7) << 0)
+#define DRAM_MR_BURST_LENGTH_MASK DRAM_MR_BURST_LENGTH(0x7)
+#define DRAM_MR_CAS_LAT(n) (((n) & 0x7) << 4)
+#define DRAM_MR_CAS_LAT_MASK DRAM_MR_CAS_LAT(0x7)
+#define DRAM_MR_WRITE_RECOVERY(n) (((n) & 0x7) << 9)
+#define DRAM_MR_WRITE_RECOVERY_MASK DRAM_MR_WRITE_RECOVERY(0x7)
+#define DRAM_MR_POWER_DOWN (0x1 << 12)
+
+#define DRAM_CSEL_MAGIC 0x16237495
+
+unsigned long sunxi_dram_init(void);
+unsigned long dramc_init(struct dram_para *para);
+
+#endif /* _SUNXI_DRAM_H */
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..892479c18339684ff85fbaaf80e17fadde44bd5f
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -0,0 +1,147 @@
+/*
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_GPIO_H
+#define _SUNXI_GPIO_H
+
+#include <linux/types.h>
+
+/*
+ * sunxi has 9 banks of gpio, they are:
+ * PA0 - PA17 | PB0 - PB23 | PC0 - PC24
+ * PD0 - PD27 | PE0 - PE31 | PF0 - PF5
+ * PG0 - PG9  | PH0 - PH27 | PI0 - PI12
+ */
+
+#define SUNXI_GPIO_A	0
+#define SUNXI_GPIO_B	1
+#define SUNXI_GPIO_C	2
+#define SUNXI_GPIO_D	3
+#define SUNXI_GPIO_E	4
+#define SUNXI_GPIO_F	5
+#define SUNXI_GPIO_G	6
+#define SUNXI_GPIO_H	7
+#define SUNXI_GPIO_I	8
+#define SUNXI_GPIO_BANKS 9
+
+struct sunxi_gpio {
+	u32 cfg[4];
+	u32 dat;
+	u32 drv[2];
+	u32 pull[2];
+};
+
+/* gpio interrupt control */
+struct sunxi_gpio_int {
+	u32 cfg[3];
+	u32 ctl;
+	u32 sta;
+	u32 deb;		/* interrupt debounce */
+};
+
+struct sunxi_gpio_reg {
+	struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
+	u8 res[0xbc];
+	struct sunxi_gpio_int gpio_int;
+};
+
+#define BANK_TO_GPIO(bank) \
+	&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]
+
+#define GPIO_BANK(pin)		((pin) >> 5)
+#define GPIO_NUM(pin)		((pin) & 0x1f)
+
+#define GPIO_CFG_INDEX(pin)	(((pin) & 0x1f) >> 3)
+#define GPIO_CFG_OFFSET(pin)	((((pin) & 0x1f) & 0x7) << 2)
+
+#define GPIO_DRV_INDEX(pin)   (((pin) & 0x1f) >> 4)
+#define GPIO_DRV_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
+
+#define GPIO_PULL_INDEX(pin)	(((pin) & 0x1f) >> 4)
+#define GPIO_PULL_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
+
+/* GPIO bank sizes */
+#define SUNXI_GPIO_A_NR		32
+#define SUNXI_GPIO_B_NR		32
+#define SUNXI_GPIO_C_NR		32
+#define SUNXI_GPIO_D_NR		32
+#define SUNXI_GPIO_E_NR		32
+#define SUNXI_GPIO_F_NR		32
+#define SUNXI_GPIO_G_NR		32
+#define SUNXI_GPIO_H_NR		32
+#define SUNXI_GPIO_I_NR		32
+
+#define SUNXI_GPIO_NEXT(__gpio) \
+	((__gpio##_START) + (__gpio##_NR) + 0)
+
+enum sunxi_gpio_number {
+	SUNXI_GPIO_A_START = 0,
+	SUNXI_GPIO_B_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_A),
+	SUNXI_GPIO_C_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_B),
+	SUNXI_GPIO_D_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_C),
+	SUNXI_GPIO_E_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_D),
+	SUNXI_GPIO_F_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_E),
+	SUNXI_GPIO_G_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_F),
+	SUNXI_GPIO_H_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_G),
+	SUNXI_GPIO_I_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_H),
+};
+
+/* SUNXI GPIO number definitions */
+#define SUNXI_GPA(_nr)	(SUNXI_GPIO_A_START + (_nr))
+#define SUNXI_GPB(_nr)	(SUNXI_GPIO_B_START + (_nr))
+#define SUNXI_GPC(_nr)	(SUNXI_GPIO_C_START + (_nr))
+#define SUNXI_GPD(_nr)	(SUNXI_GPIO_D_START + (_nr))
+#define SUNXI_GPE(_nr)	(SUNXI_GPIO_E_START + (_nr))
+#define SUNXI_GPF(_nr)	(SUNXI_GPIO_F_START + (_nr))
+#define SUNXI_GPG(_nr)	(SUNXI_GPIO_G_START + (_nr))
+#define SUNXI_GPH(_nr)	(SUNXI_GPIO_H_START + (_nr))
+#define SUNXI_GPI(_nr)	(SUNXI_GPIO_I_START + (_nr))
+
+/* GPIO pin function config */
+#define SUNXI_GPIO_INPUT	0
+#define SUNXI_GPIO_OUTPUT	1
+
+#define SUNXI_GPA0_EMAC		2
+#define SUN7I_GPA0_GMAC		5
+
+#define SUNXI_GPB0_TWI0		2
+
+#define SUN4I_GPB22_UART0_TX	2
+#define SUN4I_GPB23_UART0_RX	2
+
+#define SUN5I_GPB19_UART0_TX	2
+#define SUN5I_GPB20_UART0_RX	2
+
+#define SUN5I_GPG3_UART1_TX	4
+#define SUN5I_GPG4_UART1_RX	4
+
+#define SUNXI_GPC6_SDC2		3
+
+#define SUNXI_GPF0_SDC0		2
+
+#define SUNXI_GPF2_SDC0		2
+#define SUNXI_GPF2_UART0_TX	4
+#define SUNXI_GPF4_UART0_RX	4
+
+#define SUN4I_GPG0_SDC1		4
+
+#define SUN4I_GPH22_SDC1	5
+
+#define SUN4I_GPI4_SDC3		2
+
+/* GPIO pin pull-up/down config */
+#define SUNXI_GPIO_PULL_DISABLE	0
+#define SUNXI_GPIO_PULL_UP	1
+#define SUNXI_GPIO_PULL_DOWN	2
+
+int sunxi_gpio_set_cfgpin(u32 pin, u32 val);
+int sunxi_gpio_get_cfgpin(u32 pin);
+int sunxi_gpio_set_drv(u32 pin, u32 val);
+int sunxi_gpio_set_pull(u32 pin, u32 val);
+
+#endif /* _SUNXI_GPIO_H */
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
new file mode 100644
index 0000000000000000000000000000000000000000..53196e3b024c68f3232a1596f29910f16f2131f0
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -0,0 +1,124 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Aaron <leafy.myeh@allwinnertech.com>
+ *
+ * MMC register definition for allwinner sunxi platform.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_MMC_H
+#define _SUNXI_MMC_H
+
+#include <linux/types.h>
+
+struct sunxi_mmc {
+	u32 gctrl;		/* 0x00 global control */
+	u32 clkcr;		/* 0x04 clock control */
+	u32 timeout;		/* 0x08 time out */
+	u32 width;		/* 0x0c bus width */
+	u32 blksz;		/* 0x10 block size */
+	u32 bytecnt;		/* 0x14 byte count */
+	u32 cmd;		/* 0x18 command */
+	u32 arg;		/* 0x1c argument */
+	u32 resp0;		/* 0x20 response 0 */
+	u32 resp1;		/* 0x24 response 1 */
+	u32 resp2;		/* 0x28 response 2 */
+	u32 resp3;		/* 0x2c response 3 */
+	u32 imask;		/* 0x30 interrupt mask */
+	u32 mint;		/* 0x34 masked interrupt status */
+	u32 rint;		/* 0x38 raw interrupt status */
+	u32 status;		/* 0x3c status */
+	u32 ftrglevel;		/* 0x40 FIFO threshold watermark*/
+	u32 funcsel;		/* 0x44 function select */
+	u32 cbcr;		/* 0x48 CIU byte count */
+	u32 bbcr;		/* 0x4c BIU byte count */
+	u32 dbgc;		/* 0x50 debug enable */
+	u32 res0[11];
+	u32 dmac;		/* 0x80 internal DMA control */
+	u32 dlba;		/* 0x84 internal DMA descr list base address */
+	u32 idst;		/* 0x88 internal DMA status */
+	u32 idie;		/* 0x8c internal DMA interrupt enable */
+	u32 chda;		/* 0x90 */
+	u32 cbda;		/* 0x94 */
+	u32 res1[26];
+	u32 fifo;		/* 0x100 FIFO access address */
+};
+
+#define SUNXI_MMC_CLK_POWERSAVE		(0x1 << 17)
+#define SUNXI_MMC_CLK_ENABLE		(0x1 << 16)
+#define SUNXI_MMC_CLK_DIVIDER_MASK	(0xff)
+
+#define SUNXI_MMC_GCTRL_SOFT_RESET	(0x1 << 0)
+#define SUNXI_MMC_GCTRL_FIFO_RESET	(0x1 << 1)
+#define SUNXI_MMC_GCTRL_DMA_RESET	(0x1 << 2)
+#define SUNXI_MMC_GCTRL_RESET		(SUNXI_MMC_GCTRL_SOFT_RESET|\
+					 SUNXI_MMC_GCTRL_FIFO_RESET|\
+					 SUNXI_MMC_GCTRL_DMA_RESET)
+#define SUNXI_MMC_GCTRL_DMA_ENABLE	(0x1 << 5)
+#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB   (0x1 << 31)
+
+#define SUNXI_MMC_CMD_RESP_EXPIRE	(0x1 << 6)
+#define SUNXI_MMC_CMD_LONG_RESPONSE	(0x1 << 7)
+#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC	(0x1 << 8)
+#define SUNXI_MMC_CMD_DATA_EXPIRE	(0x1 << 9)
+#define SUNXI_MMC_CMD_WRITE		(0x1 << 10)
+#define SUNXI_MMC_CMD_AUTO_STOP		(0x1 << 12)
+#define SUNXI_MMC_CMD_WAIT_PRE_OVER	(0x1 << 13)
+#define SUNXI_MMC_CMD_SEND_INIT_SEQ	(0x1 << 15)
+#define SUNXI_MMC_CMD_UPCLK_ONLY	(0x1 << 21)
+#define SUNXI_MMC_CMD_START		(0x1 << 31)
+
+#define SUNXI_MMC_RINT_RESP_ERROR		(0x1 << 1)
+#define SUNXI_MMC_RINT_COMMAND_DONE		(0x1 << 2)
+#define SUNXI_MMC_RINT_DATA_OVER		(0x1 << 3)
+#define SUNXI_MMC_RINT_TX_DATA_REQUEST		(0x1 << 4)
+#define SUNXI_MMC_RINT_RX_DATA_REQUEST		(0x1 << 5)
+#define SUNXI_MMC_RINT_RESP_CRC_ERROR		(0x1 << 6)
+#define SUNXI_MMC_RINT_DATA_CRC_ERROR		(0x1 << 7)
+#define SUNXI_MMC_RINT_RESP_TIMEOUT		(0x1 << 8)
+#define SUNXI_MMC_RINT_DATA_TIMEOUT		(0x1 << 9)
+#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE	(0x1 << 10)
+#define SUNXI_MMC_RINT_FIFO_RUN_ERROR		(0x1 << 11)
+#define SUNXI_MMC_RINT_HARD_WARE_LOCKED		(0x1 << 12)
+#define SUNXI_MMC_RINT_START_BIT_ERROR		(0x1 << 13)
+#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE	(0x1 << 14)
+#define SUNXI_MMC_RINT_END_BIT_ERROR		(0x1 << 15)
+#define SUNXI_MMC_RINT_SDIO_INTERRUPT		(0x1 << 16)
+#define SUNXI_MMC_RINT_CARD_INSERT		(0x1 << 30)
+#define SUNXI_MMC_RINT_CARD_REMOVE		(0x1 << 31)
+#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT      \
+	(SUNXI_MMC_RINT_RESP_ERROR |		\
+	 SUNXI_MMC_RINT_RESP_CRC_ERROR |	\
+	 SUNXI_MMC_RINT_DATA_CRC_ERROR |	\
+	 SUNXI_MMC_RINT_RESP_TIMEOUT |		\
+	 SUNXI_MMC_RINT_DATA_TIMEOUT |		\
+	 SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE |	\
+	 SUNXI_MMC_RINT_FIFO_RUN_ERROR |	\
+	 SUNXI_MMC_RINT_HARD_WARE_LOCKED |	\
+	 SUNXI_MMC_RINT_START_BIT_ERROR |	\
+	 SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */
+#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT	\
+	(SUNXI_MMC_RINT_AUTO_COMMAND_DONE |	\
+	 SUNXI_MMC_RINT_DATA_OVER |		\
+	 SUNXI_MMC_RINT_COMMAND_DONE |		\
+	 SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
+
+#define SUNXI_MMC_STATUS_RXWL_FLAG		(0x1 << 0)
+#define SUNXI_MMC_STATUS_TXWL_FLAG		(0x1 << 1)
+#define SUNXI_MMC_STATUS_FIFO_EMPTY		(0x1 << 2)
+#define SUNXI_MMC_STATUS_FIFO_FULL		(0x1 << 3)
+#define SUNXI_MMC_STATUS_CARD_PRESENT		(0x1 << 8)
+#define SUNXI_MMC_STATUS_CARD_DATA_BUSY		(0x1 << 9)
+#define SUNXI_MMC_STATUS_DATA_FSM_BUSY		(0x1 << 10)
+
+#define SUNXI_MMC_IDMAC_RESET		(0x1 << 0)
+#define SUNXI_MMC_IDMAC_FIXBURST	(0x1 << 1)
+#define SUNXI_MMC_IDMAC_ENABLE		(0x1 << 7)
+
+#define SUNXI_MMC_IDIE_TXIRQ		(0x1 << 0)
+#define SUNXI_MMC_IDIE_RXIRQ		(0x1 << 1)
+
+int sunxi_mmc_init(int sdc_no);
+#endif /* _SUNXI_MMC_H */
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff871bcaeee689188b3305a3e0c7fffe27c16c65
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -0,0 +1,20 @@
+/*
+ * This is a copy of omap3/spl.h:
+ *
+ * (C) Copyright 2012
+ * Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef	_ASM_ARCH_SPL_H_
+#define	_ASM_SPL_H_
+
+#define BOOT_DEVICE_NONE	0
+#define BOOT_DEVICE_XIP		1
+#define BOOT_DEVICE_NAND	2
+#define BOOT_DEVICE_ONE_NAND	3
+#define BOOT_DEVICE_MMC2	5 /*emmc*/
+#define BOOT_DEVICE_MMC1	6
+#define BOOT_DEVICE_XIPWAIT	7
+#define BOOT_DEVICE_MMC2_2      0xff
+#endif
diff --git a/arch/arm/include/asm/arch-sunxi/sys_proto.h b/arch/arm/include/asm/arch-sunxi/sys_proto.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3e636e1d9b6ae9ce1ff331a9660ad538ecc3028
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/sys_proto.h
@@ -0,0 +1,16 @@
+/*
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SYS_PROTO_H_
+#define _SYS_PROTO_H_
+
+#include <linux/types.h>
+
+void sdelay(unsigned long);
+
+#endif
diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h
new file mode 100644
index 0000000000000000000000000000000000000000..6aacfd7b39696db1f498570974f9aec017f4eace
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/timer.h
@@ -0,0 +1,88 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Configuration settings for the Allwinner A10-evb board.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_TIMER_H_
+#define _SUNXI_TIMER_H_
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/* General purpose timer */
+struct sunxi_timer {
+	u32 ctl;
+	u32 inter;
+	u32 val;
+	u8 res[4];
+};
+
+/* Audio video sync*/
+struct sunxi_avs {
+	u32 ctl;		/* 0x80 */
+	u32 cnt0;		/* 0x84 */
+	u32 cnt1;		/* 0x88 */
+	u32 div;		/* 0x8c */
+};
+
+/* 64 bit counter */
+struct sunxi_64cnt {
+	u32 ctl;		/* 0xa0 */
+	u32 lo;			/* 0xa4 */
+	u32 hi;			/* 0xa8 */
+};
+
+/* Watchdog */
+struct sunxi_wdog {
+	u32 ctl;		/* 0x90 */
+	u32 mode;		/* 0x94 */
+};
+
+/* Rtc */
+struct sunxi_rtc {
+	u32 ctl;		/* 0x100 */
+	u32 yymmdd;		/* 0x104 */
+	u32 hhmmss;		/* 0x108 */
+};
+
+/* Alarm */
+struct sunxi_alarm {
+	u32 ddhhmmss;		/* 0x10c */
+	u32 hhmmss;		/* 0x110 */
+	u32 en;			/* 0x114 */
+	u32 irqen;		/* 0x118 */
+	u32 irqsta;		/* 0x11c */
+};
+
+/* Timer general purpose register */
+struct sunxi_tgp {
+	u32 tgpd;
+};
+
+struct sunxi_timer_reg {
+	u32 tirqen;		/* 0x00 */
+	u32 tirqsta;		/* 0x04 */
+	u8 res1[8];
+	struct sunxi_timer timer[6];	/* We have 6 timers */
+	u8 res2[16];
+	struct sunxi_avs avs;
+	struct sunxi_wdog wdog;
+	u8 res3[8];
+	struct sunxi_64cnt cnt64;
+	u8 res4[0x58];
+	struct sunxi_rtc rtc;
+	struct sunxi_alarm alarm;
+	struct sunxi_tgp tgp[4];
+	u8 res5[8];
+	u32 cpu_cfg;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/arm/include/asm/arch-vf610/imx-regs.h b/arch/arm/include/asm/arch-vf610/imx-regs.h
index c2f976184664872567f7f8f019a7f43ccb1ccc11..0c28e1b8403a4f52a89c1e26117ea5a558323b23 100644
--- a/arch/arm/include/asm/arch-vf610/imx-regs.h
+++ b/arch/arm/include/asm/arch-vf610/imx-regs.h
@@ -215,6 +215,7 @@
 #define DDRMC_CR139_PHY_WRLV_EN(v)			((v) & 0xff)
 #define DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(v)	(((v) & 0x1f) << 27)
 #define DDRMC_CR154_PAD_ZQ_MODE(v)			(((v) & 0x3) << 21)
+#define DDRMC_CR154_DDR_SEL_PAD_CONTR(v)		(((v) & 0x3) << 18)
 #define DDRMC_CR155_AXI0_AWCACHE			(1 << 10)
 #define DDRMC_CR155_PAD_ODT_BYTE1(v)			((v) & 0x7)
 #define DDRMC_CR158_TWR(v)				((v) & 0x3f)
diff --git a/board/atmel/at91sam9m10g45ek/at91sam9m10g45ek.c b/board/atmel/at91sam9m10g45ek/at91sam9m10g45ek.c
index b7e2efd2fce14bee705c3630ba9ee1a1347f1407..57881164c5a72682145df07e170128dfcefd41b4 100644
--- a/board/atmel/at91sam9m10g45ek/at91sam9m10g45ek.c
+++ b/board/atmel/at91sam9m10g45ek/at91sam9m10g45ek.c
@@ -16,6 +16,7 @@
 #include <asm/arch/clk.h>
 #include <lcd.h>
 #include <atmel_lcdc.h>
+#include <atmel_mci.h>
 #if defined(CONFIG_RESET_PHY_R) && defined(CONFIG_MACB)
 #include <net.h>
 #endif
@@ -217,6 +218,15 @@ void lcd_show_board_info(void)
 #endif /* CONFIG_LCD_INFO */
 #endif
 
+#ifdef CONFIG_GENERIC_ATMEL_MCI
+int board_mmc_init(bd_t *bis)
+{
+	at91_mci_hw_init();
+
+	return atmel_mci_init((void *)ATMEL_BASE_MCI0);
+}
+#endif
+
 int board_early_init_f(void)
 {
 	at91_seriald_hw_init();
diff --git a/board/atmel/sama5d3_xplained/sama5d3_xplained.c b/board/atmel/sama5d3_xplained/sama5d3_xplained.c
index 39f2dc6475d13a98dfcd63707965602d4033ae4e..92ed4e81d3902ea5b8c53107e6ac833b5693c967 100644
--- a/board/atmel/sama5d3_xplained/sama5d3_xplained.c
+++ b/board/atmel/sama5d3_xplained/sama5d3_xplained.c
@@ -17,6 +17,9 @@
 #include <atmel_mci.h>
 #include <net.h>
 #include <netdev.h>
+#include <spl.h>
+#include <asm/arch/atmel_mpddrc.h>
+#include <asm/arch/at91_wdt.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -128,3 +131,87 @@ int board_mmc_init(bd_t *bis)
 	return 0;
 }
 #endif
+
+/* SPL */
+#ifdef CONFIG_SPL_BUILD
+void spl_board_init(void)
+{
+#ifdef CONFIG_SYS_USE_MMC
+	sama5d3_xplained_mci0_hw_init();
+#elif CONFIG_SYS_USE_NANDFLASH
+	sama5d3_xplained_nand_hw_init();
+#endif
+}
+
+static void ddr2_conf(struct atmel_mpddr *ddr2)
+{
+	ddr2->md = (ATMEL_MPDDRC_MD_DBW_32_BITS | ATMEL_MPDDRC_MD_DDR2_SDRAM);
+
+	ddr2->cr = (ATMEL_MPDDRC_CR_NC_COL_10 |
+		    ATMEL_MPDDRC_CR_NR_ROW_14 |
+		    ATMEL_MPDDRC_CR_CAS_DDR_CAS3 |
+		    ATMEL_MPDDRC_CR_ENRDM_ON |
+		    ATMEL_MPDDRC_CR_NB_8BANKS |
+		    ATMEL_MPDDRC_CR_NDQS_DISABLED |
+		    ATMEL_MPDDRC_CR_DECOD_INTERLEAVED |
+		    ATMEL_MPDDRC_CR_UNAL_SUPPORTED);
+	/*
+	 * As the DDR2-SDRAm device requires a refresh time is 7.8125us
+	 * when DDR run at 133MHz, so it needs (7.8125us * 133MHz / 10^9) clocks
+	 */
+	ddr2->rtr = 0x411;
+
+	ddr2->tpr0 = (6 << ATMEL_MPDDRC_TPR0_TRAS_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TRCD_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TWR_OFFSET |
+		      8 << ATMEL_MPDDRC_TPR0_TRC_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TRP_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TRRD_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TWTR_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR0_TMRD_OFFSET);
+
+	ddr2->tpr1 = (2 << ATMEL_MPDDRC_TPR1_TXP_OFFSET |
+		      200 << ATMEL_MPDDRC_TPR1_TXSRD_OFFSET |
+		      28 << ATMEL_MPDDRC_TPR1_TXSNR_OFFSET |
+		      26 << ATMEL_MPDDRC_TPR1_TRFC_OFFSET);
+
+	ddr2->tpr2 = (7 << ATMEL_MPDDRC_TPR2_TFAW_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR2_TRTP_OFFSET |
+		      2 << ATMEL_MPDDRC_TPR2_TRPA_OFFSET |
+		      7 << ATMEL_MPDDRC_TPR2_TXARDS_OFFSET |
+		      8 << ATMEL_MPDDRC_TPR2_TXARD_OFFSET);
+}
+
+void mem_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	struct atmel_mpddr ddr2;
+
+	ddr2_conf(&ddr2);
+
+	/* enable MPDDR clock */
+	at91_periph_clk_enable(ATMEL_ID_MPDDRC);
+	writel(0x4, &pmc->scer);
+
+	/* DDRAM2 Controller initialize */
+	ddr2_init(ATMEL_BASE_DDRCS, &ddr2);
+}
+
+void at91_pmc_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	u32 tmp;
+
+	tmp = AT91_PMC_PLLAR_29 |
+	      AT91_PMC_PLLXR_PLLCOUNT(0x3f) |
+	      AT91_PMC_PLLXR_MUL(43) |
+	      AT91_PMC_PLLXR_DIV(1);
+	at91_plla_init(tmp);
+
+	writel(0x3 << 8, &pmc->pllicpr);
+
+	tmp = AT91_PMC_MCKR_MDIV_4 |
+	      AT91_PMC_MCKR_CSS_PLLA;
+	at91_mck_init(tmp);
+}
+#endif
diff --git a/board/freescale/vf610twr/vf610twr.c b/board/freescale/vf610twr/vf610twr.c
index 4ee74c019883785b5cf14df09a5fc19b48e6cabb..d64d3aa872205f237fce290ae4ec0187c1ead705 100644
--- a/board/freescale/vf610twr/vf610twr.c
+++ b/board/freescale/vf610twr/vf610twr.c
@@ -217,7 +217,8 @@ void ddr_ctrl_init(void)
 		&ddrmr->cr[139]);
 
 	writel(DDRMC_CR154_PAD_ZQ_EARLY_CMP_EN_TIMER(13) |
-		DDRMC_CR154_PAD_ZQ_MODE(1), &ddrmr->cr[154]);
+		DDRMC_CR154_PAD_ZQ_MODE(1) |
+		DDRMC_CR154_DDR_SEL_PAD_CONTR(3), &ddrmr->cr[154]);
 	writel(DDRMC_CR155_AXI0_AWCACHE | DDRMC_CR155_PAD_ODT_BYTE1(2),
 		&ddrmr->cr[155]);
 	writel(DDRMC_CR158_TWR(6), &ddrmr->cr[158]);
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..cbf8f086a95af88f16c081e99d5eaf6b2cf83a1c
--- /dev/null
+++ b/board/sunxi/Makefile
@@ -0,0 +1,13 @@
+#
+# (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+#
+# Based on some other board Makefile
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+obj-y	+= board.o
+obj-$(CONFIG_SUNXI_GMAC)	+= gmac.o
+obj-$(CONFIG_CUBIETRUCK)	+= dram_cubietruck.o
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
new file mode 100644
index 0000000000000000000000000000000000000000..b05d0b9b18c9a5fdc7442de3286edb9838da95bd
--- /dev/null
+++ b/board/sunxi/board.c
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Some board init for the Allwinner A10-evb board.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mmc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* add board specific code here */
+int board_init(void)
+{
+	int id_pfr1;
+
+	gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
+
+	asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1));
+	debug("id_pfr1: 0x%08x\n", id_pfr1);
+	/* Generic Timer Extension available? */
+	if ((id_pfr1 >> 16) & 0xf) {
+		debug("Setting CNTFRQ\n");
+		/* CNTFRQ == 24 MHz */
+		asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r"(24000000));
+	}
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE);
+
+	return 0;
+}
+
+#ifdef CONFIG_GENERIC_MMC
+static void mmc_pinmux_setup(int sdc)
+{
+	unsigned int pin;
+
+	switch (sdc) {
+	case 0:
+		/* D1-PF0, D0-PF1, CLK-PF2, CMD-PF3, D3-PF4, D4-PF5 */
+		for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) {
+			sunxi_gpio_set_cfgpin(pin, SUNXI_GPF0_SDC0);
+			sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+			sunxi_gpio_set_drv(pin, 2);
+		}
+		break;
+
+	case 1:
+		/* CMD-PH22, CLK-PH23, D0~D3-PH24~27 : 5 */
+		for (pin = SUNXI_GPH(22); pin <= SUNXI_GPH(27); pin++) {
+			sunxi_gpio_set_cfgpin(pin, SUN4I_GPH22_SDC1);
+			sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+			sunxi_gpio_set_drv(pin, 2);
+		}
+		break;
+
+	case 2:
+		/* CMD-PC6, CLK-PC7, D0-PC8, D1-PC9, D2-PC10, D3-PC11 */
+		for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(11); pin++) {
+			sunxi_gpio_set_cfgpin(pin, SUNXI_GPC6_SDC2);
+			sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+			sunxi_gpio_set_drv(pin, 2);
+		}
+		break;
+
+	case 3:
+		/* CMD-PI4, CLK-PI5, D0~D3-PI6~9 : 2 */
+		for (pin = SUNXI_GPI(4); pin <= SUNXI_GPI(9); pin++) {
+			sunxi_gpio_set_cfgpin(pin, SUN4I_GPI4_SDC3);
+			sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+			sunxi_gpio_set_drv(pin, 2);
+		}
+		break;
+
+	default:
+		printf("sunxi: invalid MMC slot %d for pinmux setup\n", sdc);
+		break;
+	}
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT);
+	sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT);
+#if !defined (CONFIG_SPL_BUILD) && defined (CONFIG_MMC_SUNXI_SLOT_EXTRA)
+	mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA);
+	sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT_EXTRA);
+#endif
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_SPL_BUILD
+void sunxi_board_init(void)
+{
+	unsigned long ramsize;
+
+	printf("DRAM:");
+	ramsize = sunxi_dram_init();
+	printf(" %lu MiB\n", ramsize >> 20);
+	if (!ramsize)
+		hang();
+}
+#endif
diff --git a/board/sunxi/dram_cubietruck.c b/board/sunxi/dram_cubietruck.c
new file mode 100644
index 0000000000000000000000000000000000000000..fbcd68771fe5d1fd0938f618536acad935c8798b
--- /dev/null
+++ b/board/sunxi/dram_cubietruck.c
@@ -0,0 +1,31 @@
+/* this file is generated, don't edit it yourself */
+
+#include <common.h>
+#include <asm/arch/dram.h>
+
+static struct dram_para dram_para = {
+	.clock = 432,
+	.type = 3,
+	.rank_num = 1,
+	.density = 4096,
+	.io_width = 8,
+	.bus_width = 32,
+	.cas = 9,
+	.zq = 0x7f,
+	.odt_en = 0,
+	.size = 2048,
+	.tpr0 = 0x42d899b7,
+	.tpr1 = 0xa090,
+	.tpr2 = 0x22a00,
+	.tpr3 = 0x0,
+	.tpr4 = 0x1,
+	.tpr5 = 0x0,
+	.emr1 = 0x4,
+	.emr2 = 0x10,
+	.emr3 = 0x0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+	return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/gmac.c b/board/sunxi/gmac.c
new file mode 100644
index 0000000000000000000000000000000000000000..e48328d9e8f545af327d57107a121bcefc20fa3f
--- /dev/null
+++ b/board/sunxi/gmac.c
@@ -0,0 +1,32 @@
+#include <common.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+int sunxi_gmac_initialize(bd_t *bis)
+{
+	int pin;
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* Set up clock gating */
+	setbits_le32(&ccm->ahb_gate1, 0x1 << AHB_GATE_OFFSET_GMAC);
+
+	/* Set MII clock */
+	setbits_le32(&ccm->gmac_clk_cfg, CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII |
+		CCM_GMAC_CTRL_GPIT_RGMII);
+
+	/* Configure pin mux settings for GMAC */
+	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(16); pin++) {
+		/* skip unused pins in RGMII mode */
+		if (pin == SUNXI_GPA(9) || pin == SUNXI_GPA(14))
+			continue;
+		sunxi_gpio_set_cfgpin(pin, SUN7I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 3);
+	}
+
+	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_RGMII);
+}
diff --git a/boards.cfg b/boards.cfg
index 81e28ba48efe97336d5f3186bf8a4a830dd83921..4760a1f47ba2a44912b17ca21edea2c1abf5e8ca 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -103,6 +103,7 @@ Active  arm         arm926ejs      at91        atmel           at91sam9263ek
 Active  arm         arm926ejs      at91        atmel           at91sam9263ek       at91sam9263ek_norflash                at91sam9263ek:AT91SAM9263,SYS_USE_NORFLASH                                                                                        Stelian Pop <stelian@popies.net>
 Active  arm         arm926ejs      at91        atmel           at91sam9263ek       at91sam9263ek_norflash_boot           at91sam9263ek:AT91SAM9263,SYS_USE_BOOT_NORFLASH                                                                                   Stelian Pop <stelian@popies.net>
 Active  arm         arm926ejs      at91        atmel           at91sam9m10g45ek    at91sam9m10g45ek_nandflash            at91sam9m10g45ek:AT91SAM9M10G45,SYS_USE_NANDFLASH                                                                                 Bo Shen<voice.shen@atmel.com>
+Active  arm         arm926ejs      at91        atmel           at91sam9m10g45ek    at91sam9m10g45ek_mmc                  at91sam9m10g45ek:AT91SAM9M10G45,SYS_USE_MMC                                                                                       Bo Shen<voice.shen@atmel.com>
 Active  arm         arm926ejs      at91        atmel           at91sam9n12ek       at91sam9n12ek_mmc                     at91sam9n12ek:AT91SAM9N12,SYS_USE_MMC                                                                                             Josh Wu <josh.wu@atmel.com>
 Active  arm         arm926ejs      at91        atmel           at91sam9n12ek       at91sam9n12ek_nandflash               at91sam9n12ek:AT91SAM9N12,SYS_USE_NANDFLASH                                                                                       Josh Wu <josh.wu@atmel.com>
 Active  arm         arm926ejs      at91        atmel           at91sam9n12ek       at91sam9n12ek_spiflash                at91sam9n12ek:AT91SAM9N12,SYS_USE_SPIFLASH                                                                                        Josh Wu <josh.wu@atmel.com>
@@ -296,7 +297,7 @@ Active  arm         armv7          exynos      samsung         smdkv310
 Active  arm         armv7          exynos      samsung         trats               trats                                 -                                                                                                                                 Lukasz Majewski <l.majewski@samsung.com>
 Active  arm         armv7          exynos      samsung         trats2              trats2                                -                                                                                                                                 Piotr Wilczek <p.wilczek@samsung.com>
 Active  arm         armv7          exynos      samsung         universal_c210      s5pc210_universal                     -                                                                                                                                 Przemyslaw Marczak <p.marczak@samsung.com>
-Active  arm         armv7          highbank    -               highbank            highbank                              -                                                                                                                                 Rob Herring <rob.herring@calxeda.com>
+Active  arm         armv7          highbank    -               highbank            highbank                              -                                                                                                                                 Rob Herring <robh@kernel.org>
 Active  arm         armv7          keystone    ti              k2hk_evm            k2hk_evm                              -                                                                                                                                 Vitaly Andrianov <vitalya@ti.com>
 Active  arm         armv7          mx5         denx            m53evk              m53evk                                m53evk:IMX_CONFIG=board/denx/m53evk/imximage.cfg                                                                                  Marek Vasut <marek.vasut@gmail.com>
 Active  arm         armv7          mx5         esg             ima3-mx53           ima3-mx53                             ima3-mx53:IMX_CONFIG=board/esg/ima3-mx53/imximage.cfg                                                                             -
@@ -380,6 +381,8 @@ Active  arm         armv7          rmobile     renesas         lager
 Active  arm         armv7          s5pc1xx     samsung         goni                s5p_goni                              -                                                                                                                                 Przemyslaw Marczak <p.marczak@samsung.com>
 Active  arm         armv7          s5pc1xx     samsung         smdkc100            smdkc100                              -                                                                                                                                 Minkyu Kang <mk7.kang@samsung.com>
 Active  arm         armv7          socfpga     altera          socfpga             socfpga_cyclone5                      -                                                                                                                                 -
+Active  arm         armv7          sunxi       -               sunxi               Cubietruck                            sun7i:CUBIETRUCK,SPL,SUNXI_GMAC,RGMII                                                                                             -
+Active  arm         armv7          sunxi       -               sunxi               Cubietruck_FEL                        sun7i:CUBIETRUCK,SPL_FEL,SUNXI_GMAC,RGMII                                                                                         -
 Active  arm         armv7          u8500       st-ericsson     snowball            snowball                              -                                                                                                                                 Mathieu Poirier <mathieu.poirier@linaro.org>
 Active  arm         armv7          u8500       st-ericsson     u8500               u8500_href                            -                                                                                                                                 -
 Active  arm         armv7          vf610       freescale       vf610twr            vf610twr                              vf610twr:IMX_CONFIG=board/freescale/vf610twr/imximage.cfg                                                                         Alison Wang <b18965@freescale.com>
diff --git a/common/image.c b/common/image.c
index fa4864d24c3001571153b0f84634843e59dfca04..26eb89a2b29b56875736f78acdaccae4c3ebf883 100644
--- a/common/image.c
+++ b/common/image.c
@@ -139,6 +139,7 @@ static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
 	{	IH_TYPE_UBLIMAGE,   "ublimage",   "Davinci UBL image",},
 	{	IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
+	{	IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
 	{	-1,		    "",		  "",			},
 };
 
diff --git a/doc/README.atmel_pmecc b/doc/README.atmel_pmecc
index cf8373b54e826c8877acca3382e21cf9ed3e7197..cc0f73db8f1c70dbca708b5529ed5fee35e8a87e 100644
--- a/doc/README.atmel_pmecc
+++ b/doc/README.atmel_pmecc
@@ -27,3 +27,24 @@ Take AT91SAM9X5EK as an example, the board definition file likes:
 #define CONFIG_ATMEL_NAND_HW_PMECC	1
 #define CONFIG_PMECC_CAP		2
 #define CONFIG_PMECC_SECTOR_SIZE	512
+
+How to enable PMECC header for direct programmable boot.bin
+-----------------------------------------------------------
+2014-05-19 Andreas Bießmann <andreas.devel@googlemail.com>
+
+The usual way to program SPL into NAND flash is to use the SAM-BA Atmel tool.
+This however is often not usable when doing field updates. To be able to
+program a SPL binary into NAND flash we need to add the PMECC header to the
+binary before. Chapter '12.4.4.1 NAND Flash Boot: NAND Flash Detection' in
+sama5d3 SoC spec (as of 03. April 2014) defines how this PMECC header has to
+look like. In order to do so we have a new image type added to mkimage to
+generate this PMECC header and integrated this into the build process of SPL.
+
+To enable the generation of atmel PMECC header for SPL one need to define
+CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER. The required parameters are taken from
+board configuration and compiled into the host tools atmel_pmecc_params. This
+tool will be called in build process to parametrize mkimage for atmelimage
+type. The mkimage tool has intentionally _not_ compiled in those parameters.
+
+The mkimage image type atmelimage also set the 6'th interrupt vector to the
+correct value. This feature can also be used to setup a boot.bin for MMC boot.
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 0b70071871ce8046577fab9453c195d2281bc81d..6517af162815ea8e5715dabb390ed46de12f4617 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -34,6 +34,7 @@ static struct at91_port *at91_pio_get_port(unsigned port)
 #endif
 #endif
 	default:
+		printf("Error: at91_gpio: Fail to get PIO base!\n");
 		return NULL;
 	}
 }
@@ -200,7 +201,7 @@ int at91_set_pio_output(unsigned port, u32 pin, int value)
 	struct at91_port *at91_port = at91_pio_get_port(port);
 	u32 mask;
 
-	if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+	if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) {
 		mask = 1 << pin;
 		writel(mask, &at91_port->idr);
 		writel(mask, &at91_port->pudr);
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 4c6ab9e05b1653173eedd39ecafe39c56e754ed1..34febf52f0ee993b2172236dbd03a4fa7020789c 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
 obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
 obj-$(CONFIG_DWMMC) += dw_mmc.o
 obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
+obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
 obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
 obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index acca0269e585a702fd9dfac5877a0bc449ab2b27..a57a9b1faff2f31079dc2349fd2240f82f56a894 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -243,9 +243,10 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 #ifdef DEBUG
 			if (data->flags & MMC_DATA_READ)
 			{
+				u32 cnt = word_count * 4;
 				printf("Read Data:\n");
-				print_buffer(0, data->dest, 1,
-					word_count*4, 0);
+				print_buffer(0, data->dest + cnt * block_count,
+					     1, cnt, 0);
 			}
 #endif
 #ifdef DEBUG
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb7b1158d6563f876c7d629cf04c477da24d0df7
--- /dev/null
+++ b/drivers/mmc/sunxi_mmc.c
@@ -0,0 +1,503 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Aaron <leafy.myeh@allwinnertech.com>
+ *
+ * MMC driver for allwinner sunxi platform.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/mmc.h>
+
+struct sunxi_mmc_des {
+	u32 reserved1_1:1;
+	u32 dic:1;		/* disable interrupt on completion */
+	u32 last_des:1;		/* 1-this data buffer is the last buffer */
+	u32 first_des:1;		/* 1-data buffer is the first buffer,
+				   0-data buffer contained in the next
+				   descriptor is 1st buffer */
+	u32 des_chain:1;	/* 1-the 2nd address in the descriptor is the
+				   next descriptor address */
+	u32 end_of_ring:1;	/* 1-last descriptor flag when using dual
+				   data buffer in descriptor */
+	u32 reserved1_2:24;
+	u32 card_err_sum:1;	/* transfer error flag */
+	u32 own:1;		/* des owner:1-idma owns it, 0-host owns it */
+#define SDXC_DES_NUM_SHIFT 16
+#define SDXC_DES_BUFFER_MAX_LEN	(1 << SDXC_DES_NUM_SHIFT)
+	u32 data_buf1_sz:16;
+	u32 data_buf2_sz:16;
+	u32 buf_addr_ptr1;
+	u32 buf_addr_ptr2;
+};
+
+struct sunxi_mmc_host {
+	unsigned mmc_no;
+	uint32_t *mclkreg;
+	unsigned database;
+	unsigned fatal_err;
+	unsigned mod_clk;
+	struct sunxi_mmc *reg;
+	struct mmc_config cfg;
+};
+
+/* support 4 mmc hosts */
+struct sunxi_mmc_host mmc_host[4];
+
+static int mmc_resource_init(int sdc_no)
+{
+	struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	debug("init mmc %d resource\n", sdc_no);
+
+	switch (sdc_no) {
+	case 0:
+		mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
+		mmchost->mclkreg = &ccm->sd0_clk_cfg;
+		break;
+	case 1:
+		mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
+		mmchost->mclkreg = &ccm->sd1_clk_cfg;
+		break;
+	case 2:
+		mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
+		mmchost->mclkreg = &ccm->sd2_clk_cfg;
+		break;
+	case 3:
+		mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
+		mmchost->mclkreg = &ccm->sd3_clk_cfg;
+		break;
+	default:
+		printf("Wrong mmc number %d\n", sdc_no);
+		return -1;
+	}
+	mmchost->database = (unsigned int)mmchost->reg + 0x100;
+	mmchost->mmc_no = sdc_no;
+
+	return 0;
+}
+
+static int mmc_clk_io_on(int sdc_no)
+{
+	unsigned int pll_clk;
+	unsigned int divider;
+	struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	debug("init mmc %d clock and io\n", sdc_no);
+
+	/* config ahb clock */
+	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
+
+	/* config mod clock */
+	pll_clk = clock_get_pll6();
+	/* should be close to 100 MHz but no more, so round up */
+	divider = ((pll_clk + 99999999) / 100000000) - 1;
+	writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL6 | divider,
+	       mmchost->mclkreg);
+	mmchost->mod_clk = pll_clk / (divider + 1);
+
+	return 0;
+}
+
+static int mmc_update_clk(struct mmc *mmc)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned int cmd;
+	unsigned timeout_msecs = 2000;
+
+	cmd = SUNXI_MMC_CMD_START |
+	      SUNXI_MMC_CMD_UPCLK_ONLY |
+	      SUNXI_MMC_CMD_WAIT_PRE_OVER;
+	writel(cmd, &mmchost->reg->cmd);
+	while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) {
+		if (!timeout_msecs--)
+			return -1;
+		udelay(1000);
+	}
+
+	/* clock update sets various irq status bits, clear these */
+	writel(readl(&mmchost->reg->rint), &mmchost->reg->rint);
+
+	return 0;
+}
+
+static int mmc_config_clock(struct mmc *mmc, unsigned div)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned rval = readl(&mmchost->reg->clkcr);
+
+	/* Disable Clock */
+	rval &= ~SUNXI_MMC_CLK_ENABLE;
+	writel(rval, &mmchost->reg->clkcr);
+	if (mmc_update_clk(mmc))
+		return -1;
+
+	/* Change Divider Factor */
+	rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
+	rval |= div;
+	writel(rval, &mmchost->reg->clkcr);
+	if (mmc_update_clk(mmc))
+		return -1;
+	/* Re-enable Clock */
+	rval |= SUNXI_MMC_CLK_ENABLE;
+	writel(rval, &mmchost->reg->clkcr);
+
+	if (mmc_update_clk(mmc))
+		return -1;
+
+	return 0;
+}
+
+static void mmc_set_ios(struct mmc *mmc)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned int clkdiv = 0;
+
+	debug("set ios: bus_width: %x, clock: %d, mod_clk: %d\n",
+	      mmc->bus_width, mmc->clock, mmchost->mod_clk);
+
+	/* Change clock first */
+	clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2;
+	if (mmc->clock) {
+		if (mmc_config_clock(mmc, clkdiv)) {
+			mmchost->fatal_err = 1;
+			return;
+		}
+	}
+
+	/* Change bus width */
+	if (mmc->bus_width == 8)
+		writel(0x2, &mmchost->reg->width);
+	else if (mmc->bus_width == 4)
+		writel(0x1, &mmchost->reg->width);
+	else
+		writel(0x0, &mmchost->reg->width);
+}
+
+static int mmc_core_init(struct mmc *mmc)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+
+	/* Reset controller */
+	writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
+
+	return 0;
+}
+
+static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	const int reading = !!(data->flags & MMC_DATA_READ);
+	const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
+					      SUNXI_MMC_STATUS_FIFO_FULL;
+	unsigned i;
+	unsigned byte_cnt = data->blocksize * data->blocks;
+	unsigned timeout_msecs = 2000;
+	unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
+
+	for (i = 0; i < (byte_cnt >> 2); i++) {
+		while (readl(&mmchost->reg->status) & status_bit) {
+			if (!timeout_msecs--)
+				return -1;
+			udelay(1000);
+		}
+
+		if (reading)
+			buff[i] = readl(mmchost->database);
+		else
+			writel(buff[i], mmchost->database);
+	}
+
+	return 0;
+}
+
+static int mmc_trans_data_by_dma(struct mmc *mmc, struct mmc_data *data)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned byte_cnt = data->blocksize * data->blocks;
+	unsigned char *buff;
+	unsigned des_idx = 0;
+	unsigned buff_frag_num =
+		(byte_cnt + SDXC_DES_BUFFER_MAX_LEN - 1) >> SDXC_DES_NUM_SHIFT;
+	unsigned remain;
+	unsigned i, rval;
+	ALLOC_CACHE_ALIGN_BUFFER(struct sunxi_mmc_des, pdes, buff_frag_num);
+
+	buff = data->flags & MMC_DATA_READ ?
+	    (unsigned char *)data->dest : (unsigned char *)data->src;
+	remain = byte_cnt & (SDXC_DES_BUFFER_MAX_LEN - 1);
+
+	flush_cache((unsigned long)buff, (unsigned long)byte_cnt);
+	for (i = 0; i < buff_frag_num; i++, des_idx++) {
+		memset((void *)&pdes[des_idx], 0, sizeof(struct sunxi_mmc_des));
+		pdes[des_idx].des_chain = 1;
+		pdes[des_idx].own = 1;
+		pdes[des_idx].dic = 1;
+		if (buff_frag_num > 1 && i != buff_frag_num - 1)
+			pdes[des_idx].data_buf1_sz = 0; /* 0 == max_len */
+		else
+			pdes[des_idx].data_buf1_sz = remain;
+
+		pdes[des_idx].buf_addr_ptr1 =
+		    (u32) buff + i * SDXC_DES_BUFFER_MAX_LEN;
+		if (i == 0)
+			pdes[des_idx].first_des = 1;
+
+		if (i == buff_frag_num - 1) {
+			pdes[des_idx].dic = 0;
+			pdes[des_idx].last_des = 1;
+			pdes[des_idx].end_of_ring = 1;
+			pdes[des_idx].buf_addr_ptr2 = 0;
+		} else {
+			pdes[des_idx].buf_addr_ptr2 = (u32)&pdes[des_idx + 1];
+		}
+	}
+	flush_cache((unsigned long)pdes,
+		    sizeof(struct sunxi_mmc_des) * (des_idx + 1));
+
+	rval = readl(&mmchost->reg->gctrl);
+	/* Enable DMA */
+	writel(rval | SUNXI_MMC_GCTRL_DMA_RESET | SUNXI_MMC_GCTRL_DMA_ENABLE,
+	       &mmchost->reg->gctrl);
+	/* Reset iDMA */
+	writel(SUNXI_MMC_IDMAC_RESET, &mmchost->reg->dmac);
+	/* Enable iDMA */
+	writel(SUNXI_MMC_IDMAC_FIXBURST | SUNXI_MMC_IDMAC_ENABLE,
+	       &mmchost->reg->dmac);
+	rval = readl(&mmchost->reg->idie) &
+		~(SUNXI_MMC_IDIE_TXIRQ|SUNXI_MMC_IDIE_RXIRQ);
+	if (data->flags & MMC_DATA_WRITE)
+		rval |= SUNXI_MMC_IDIE_TXIRQ;
+	else
+		rval |= SUNXI_MMC_IDIE_RXIRQ;
+	writel(rval, &mmchost->reg->idie);
+	writel((u32) pdes, &mmchost->reg->dlba);
+	writel((0x2 << 28) | (0x7 << 16) | (0x01 << 3),
+	       &mmchost->reg->ftrglevel);
+
+	return 0;
+}
+
+static void mmc_enable_dma_accesses(struct mmc *mmc, int dma)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+
+	unsigned int gctrl = readl(&mmchost->reg->gctrl);
+	if (dma)
+		gctrl &= ~SUNXI_MMC_GCTRL_ACCESS_BY_AHB;
+	else
+		gctrl |= SUNXI_MMC_GCTRL_ACCESS_BY_AHB;
+	writel(gctrl, &mmchost->reg->gctrl);
+}
+
+static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs,
+			 unsigned int done_bit, const char *what)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned int status;
+
+	do {
+		status = readl(&mmchost->reg->rint);
+		if (!timeout_msecs-- ||
+		    (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
+			debug("%s timeout %x\n", what,
+			      status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
+			return TIMEOUT;
+		}
+		udelay(1000);
+	} while (!(status & done_bit));
+
+	return 0;
+}
+
+static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data)
+{
+	struct sunxi_mmc_host *mmchost = mmc->priv;
+	unsigned int cmdval = SUNXI_MMC_CMD_START;
+	unsigned int timeout_msecs;
+	int error = 0;
+	unsigned int status = 0;
+	unsigned int usedma = 0;
+	unsigned int bytecnt = 0;
+
+	if (mmchost->fatal_err)
+		return -1;
+	if (cmd->resp_type & MMC_RSP_BUSY)
+		debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
+	if (cmd->cmdidx == 12)
+		return 0;
+
+	if (!cmd->cmdidx)
+		cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
+	if (cmd->resp_type & MMC_RSP_PRESENT)
+		cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
+	if (cmd->resp_type & MMC_RSP_136)
+		cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
+	if (cmd->resp_type & MMC_RSP_CRC)
+		cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
+
+	if (data) {
+		if ((u32) data->dest & 0x3) {
+			error = -1;
+			goto out;
+		}
+
+		cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
+		if (data->flags & MMC_DATA_WRITE)
+			cmdval |= SUNXI_MMC_CMD_WRITE;
+		if (data->blocks > 1)
+			cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
+		writel(data->blocksize, &mmchost->reg->blksz);
+		writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt);
+	}
+
+	debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no,
+	      cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
+	writel(cmd->cmdarg, &mmchost->reg->arg);
+
+	if (!data)
+		writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
+
+	/*
+	 * transfer data and check status
+	 * STATREG[2] : FIFO empty
+	 * STATREG[3] : FIFO full
+	 */
+	if (data) {
+		int ret = 0;
+
+		bytecnt = data->blocksize * data->blocks;
+		debug("trans data %d bytes\n", bytecnt);
+#if defined(CONFIG_MMC_SUNXI_USE_DMA) && !defined(CONFIG_SPL_BUILD)
+		if (bytecnt > 64) {
+#else
+		if (0) {
+#endif
+			usedma = 1;
+			mmc_enable_dma_accesses(mmc, 1);
+			ret = mmc_trans_data_by_dma(mmc, data);
+			writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
+		} else {
+			mmc_enable_dma_accesses(mmc, 0);
+			writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
+			ret = mmc_trans_data_by_cpu(mmc, data);
+		}
+		if (ret) {
+			error = readl(&mmchost->reg->rint) & \
+				SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
+			error = TIMEOUT;
+			goto out;
+		}
+	}
+
+	error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
+	if (error)
+		goto out;
+
+	if (data) {
+		timeout_msecs = usedma ? 120 * bytecnt : 120;
+		debug("cacl timeout %x msec\n", timeout_msecs);
+		error = mmc_rint_wait(mmc, timeout_msecs,
+				      data->blocks > 1 ?
+				      SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
+				      SUNXI_MMC_RINT_DATA_OVER,
+				      "data");
+		if (error)
+			goto out;
+	}
+
+	if (cmd->resp_type & MMC_RSP_BUSY) {
+		timeout_msecs = 2000;
+		do {
+			status = readl(&mmchost->reg->status);
+			if (!timeout_msecs--) {
+				debug("busy timeout\n");
+				error = TIMEOUT;
+				goto out;
+			}
+			udelay(1000);
+		} while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
+	}
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = readl(&mmchost->reg->resp3);
+		cmd->response[1] = readl(&mmchost->reg->resp2);
+		cmd->response[2] = readl(&mmchost->reg->resp1);
+		cmd->response[3] = readl(&mmchost->reg->resp0);
+		debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
+		      cmd->response[3], cmd->response[2],
+		      cmd->response[1], cmd->response[0]);
+	} else {
+		cmd->response[0] = readl(&mmchost->reg->resp0);
+		debug("mmc resp 0x%08x\n", cmd->response[0]);
+	}
+out:
+	if (data && usedma) {
+		/* IDMASTAREG
+		 * IDST[0] : idma tx int
+		 * IDST[1] : idma rx int
+		 * IDST[2] : idma fatal bus error
+		 * IDST[4] : idma descriptor invalid
+		 * IDST[5] : idma error summary
+		 * IDST[8] : idma normal interrupt sumary
+		 * IDST[9] : idma abnormal interrupt sumary
+		 */
+		status = readl(&mmchost->reg->idst);
+		writel(status, &mmchost->reg->idst);
+		writel(0, &mmchost->reg->idie);
+		writel(0, &mmchost->reg->dmac);
+		writel(readl(&mmchost->reg->gctrl) & ~SUNXI_MMC_GCTRL_DMA_ENABLE,
+		       &mmchost->reg->gctrl);
+	}
+	if (error < 0) {
+		writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
+		mmc_update_clk(mmc);
+	}
+	writel(0xffffffff, &mmchost->reg->rint);
+	writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
+	       &mmchost->reg->gctrl);
+
+	return error;
+}
+
+static const struct mmc_ops sunxi_mmc_ops = {
+	.send_cmd	= mmc_send_cmd,
+	.set_ios	= mmc_set_ios,
+	.init		= mmc_core_init,
+};
+
+int sunxi_mmc_init(int sdc_no)
+{
+	struct mmc_config *cfg = &mmc_host[sdc_no].cfg;
+
+	memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host));
+
+	cfg->name = "SUNXI SD/MMC";
+	cfg->ops  = &sunxi_mmc_ops;
+
+	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	cfg->host_caps = MMC_MODE_4BIT;
+	cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+	cfg->f_min = 400000;
+	cfg->f_max = 52000000;
+
+	mmc_resource_init(sdc_no);
+	mmc_clk_io_on(sdc_no);
+
+	if (mmc_create(cfg, &mmc_host[sdc_no]) == NULL)
+		return -1;
+
+	return 0;
+}
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 78751b2600c683a9bb9079c0a28b8c7beeab266c..7186e3b491ecabd6128720a6284a1ef42d4b93c0 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -249,7 +249,7 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
 	rx_descs_init(dev);
 	tx_descs_init(dev);
 
-	writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode);
+	writel(FIXEDBURST | PRIORXTX_41 | DMA_PBL, &dma_p->busmode);
 
 	writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
 	       &dma_p->opmode);
@@ -280,10 +280,18 @@ static int dw_eth_send(struct eth_device *dev, void *packet, int length)
 	u32 desc_num = priv->tx_currdescnum;
 	struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
 
-	/* Invalidate only "status" field for the following check */
-	invalidate_dcache_range((unsigned long)&desc_p->txrx_status,
-				(unsigned long)&desc_p->txrx_status +
-				sizeof(desc_p->txrx_status));
+	/*
+	 * Strictly we only need to invalidate the "txrx_status" field
+	 * for the following check, but on some platforms we cannot
+	 * invalidate only 4 bytes, so roundup to
+	 * ARCH_DMA_MINALIGN. This is safe because the individual
+	 * descriptors in the array are each aligned to
+	 * ARCH_DMA_MINALIGN.
+	 */
+	invalidate_dcache_range(
+		(unsigned long)desc_p,
+		(unsigned long)desc_p +
+		roundup(sizeof(desc_p->txrx_status), ARCH_DMA_MINALIGN));
 
 	/* Check if the descriptor is owned by CPU */
 	if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
@@ -351,7 +359,7 @@ static int dw_eth_recv(struct eth_device *dev)
 		/* Invalidate received data */
 		invalidate_dcache_range((unsigned long)desc_p->dmamac_addr,
 					(unsigned long)desc_p->dmamac_addr +
-					length);
+					roundup(length, ARCH_DMA_MINALIGN));
 
 		NetReceive(desc_p->dmamac_addr, length);
 
@@ -414,7 +422,8 @@ int designware_initialize(ulong base_addr, u32 interface)
 	 * Since the priv structure contains the descriptors which need a strict
 	 * buswidth alignment, memalign is used to allocate memory
 	 */
-	priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev));
+	priv = (struct dw_eth_dev *) memalign(ARCH_DMA_MINALIGN,
+					      sizeof(struct dw_eth_dev));
 	if (!priv) {
 		free(dev);
 		return -ENOMEM;
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 382b0c7f0a66c2a9dd4dab562a13f16f780e2bda..ce51102052eafad7e2b8fdb764f3cf91b33c5d2e 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -77,18 +77,18 @@ struct eth_dma_regs {
 
 #define DW_DMA_BASE_OFFSET	(0x1000)
 
+/* Default DMA Burst length */
+#ifndef CONFIG_DW_GMAC_DEFAULT_DMA_PBL
+#define CONFIG_DW_GMAC_DEFAULT_DMA_PBL 8
+#endif
+
 /* Bus mode register definitions */
 #define FIXEDBURST		(1 << 16)
 #define PRIORXTX_41		(3 << 14)
 #define PRIORXTX_31		(2 << 14)
 #define PRIORXTX_21		(1 << 14)
 #define PRIORXTX_11		(0 << 14)
-#define BURST_1			(1 << 8)
-#define BURST_2			(2 << 8)
-#define BURST_4			(4 << 8)
-#define BURST_8			(8 << 8)
-#define BURST_16		(16 << 8)
-#define BURST_32		(32 << 8)
+#define DMA_PBL			(CONFIG_DW_GMAC_DEFAULT_DMA_PBL<<8)
 #define RXHIGHPRIO		(1 << 1)
 #define DMAMAC_SRST		(1 << 0)
 
@@ -215,15 +215,14 @@ struct dmamacdescr {
 #endif
 
 struct dw_eth_dev {
-	u32 interface;
-	u32 tx_currdescnum;
-	u32 rx_currdescnum;
-
 	struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
 	struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM];
+	char txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+	char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
 
-	char txbuffs[TX_TOTAL_BUFSIZE];
-	char rxbuffs[RX_TOTAL_BUFSIZE];
+	u32 interface;
+	u32 tx_currdescnum;
+	u32 rx_currdescnum;
 
 	struct eth_mac_regs *mac_regs_p;
 	struct eth_dma_regs *dma_regs_p;
diff --git a/include/configs/at91sam9m10g45ek.h b/include/configs/at91sam9m10g45ek.h
index ccfda71c959d6e0ebc91b10b2ebc586e1290f550..341b21df270c305a767fb2a0aad78c6696b96d9f 100644
--- a/include/configs/at91sam9m10g45ek.h
+++ b/include/configs/at91sam9m10g45ek.h
@@ -22,7 +22,6 @@
 #define CONFIG_SYS_AT91_MAIN_CLOCK      12000000 /* from 12 MHz crystal */
 
 #define CONFIG_AT91SAM9M10G45EK
-#define CONFIG_AT91FAMILY
 
 #define CONFIG_CMDLINE_TAG		/* enable passing of ATAGs	*/
 #define CONFIG_SETUP_MEMORY_TAGS
@@ -34,6 +33,8 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
+#define CONFIG_SYS_GENERIC_BOARD
+
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
 #define CONFIG_AT91_GPIO
@@ -115,6 +116,20 @@
 
 #endif
 
+/* MMC */
+#define CONFIG_CMD_MMC
+
+#ifdef CONFIG_CMD_MMC
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_GENERIC_ATMEL_MCI
+#endif
+
+#if defined(CONFIG_CMD_USB) || defined(CONFIG_CMD_MMC)
+#define CONFIG_CMD_FAT
+#define CONFIG_DOS_PARTITION
+#endif
+
 /* Ethernet */
 #define CONFIG_MACB
 #define CONFIG_RMII
@@ -126,7 +141,6 @@
 #define CONFIG_USB_EHCI
 #define CONFIG_USB_EHCI_ATMEL
 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS	2
-#define CONFIG_DOS_PARTITION
 #define CONFIG_USB_STORAGE
 
 #define CONFIG_SYS_LOAD_ADDR		0x22000000	/* load address */
@@ -134,6 +148,7 @@
 #define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE
 #define CONFIG_SYS_MEMTEST_END		0x23e00000
 
+#ifdef CONFIG_SYS_USE_NANDFLASH
 /* bootstrap + u-boot + env in nandflash */
 #define CONFIG_ENV_IS_IN_NAND
 #define CONFIG_ENV_OFFSET		0xc0000
@@ -149,6 +164,24 @@
 	"256k(env),256k(env_redundant),256k(spare),"			\
 	"512k(dtb),6M(kernel)ro,-(rootfs) "				\
 	"root=/dev/mtdblock7 rw rootfstype=jffs2"
+#elif CONFIG_SYS_USE_MMC
+/* bootstrap + u-boot + env + linux in mmc */
+#define FAT_ENV_INTERFACE	"mmc"
+#define FAT_ENV_DEVICE		0
+#define FAT_ENV_PART		1
+#define FAT_ENV_FILE		"uboot.env"
+#define CONFIG_ENV_IS_IN_FAT
+#define CONFIG_FAT_WRITE
+#define CONFIG_ENV_SIZE		0x4000
+
+#define CONFIG_BOOTARGS		"console=ttyS0,115200 " \
+				"mtdparts=atmel_nand:" \
+				"8M(bootstrap/uboot/kernel)ro,-(rootfs) " \
+				"root=/dev/mmcblk0p2 rw rootwait"
+#define CONFIG_BOOTCOMMAND	"fatload mmc 0:1 0x71000000 dtb; " \
+				"fatload mmc 0:1 0x72000000 zImage; " \
+				"bootz 0x72000000 - 0x71000000"
+#endif
 
 #define CONFIG_BAUDRATE			115200
 
diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h
index e23549d44431cf3793879aa70e37ff714046a7c5..9b0e588c6b825a51b3d0be91e0c20519358a6eda 100644
--- a/include/configs/at91sam9n12ek.h
+++ b/include/configs/at91sam9n12ek.h
@@ -18,9 +18,6 @@
 
 #define CONFIG_SYS_TEXT_BASE		0x26f00000
 
-#define CONFIG_ARM926EJS
-#define CONFIG_AT91FAMILY
-
 /* ARM asynchronous clock */
 #define CONFIG_SYS_AT91_SLOW_CLOCK	32768		/* slow clock xtal */
 #define CONFIG_SYS_AT91_MAIN_CLOCK	16000000	/* main clock xtal */
diff --git a/include/configs/at91sam9x5ek.h b/include/configs/at91sam9x5ek.h
index f0a6757ff66578044b84f1d628a3442bce502caf..b1d4baaff9501c3711ebddb3c7be1602c3f031a0 100644
--- a/include/configs/at91sam9x5ek.h
+++ b/include/configs/at91sam9x5ek.h
@@ -18,7 +18,6 @@
 #define CONFIG_SYS_AT91_MAIN_CLOCK	12000000	/* 12 MHz crystal */
 
 #define CONFIG_AT91SAM9X5EK
-#define CONFIG_AT91FAMILY
 
 #define CONFIG_CMDLINE_TAG		/* enable passing of ATAGs */
 #define CONFIG_SETUP_MEMORY_TAGS
@@ -30,6 +29,8 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
+#define CONFIG_SYS_GENERIC_BOARD
+
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
 #define CONFIG_AT91_GPIO
diff --git a/include/configs/corvus.h b/include/configs/corvus.h
index 959e188d9ad162a51c39668183c317dc3348ffa2..6171060e9cd41ae9396a657e03508d1df166e0ed 100644
--- a/include/configs/corvus.h
+++ b/include/configs/corvus.h
@@ -27,15 +27,12 @@
 
 #define CONFIG_SYS_TEXT_BASE  0x73f00000
 
-#define CONFIG_AT91_LEGACY
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
 
 /* ARM asynchronous clock */
 #define CONFIG_SYS_AT91_SLOW_CLOCK      32768
 #define CONFIG_SYS_AT91_MAIN_CLOCK      12000000 /* from 12 MHz crystal */
 
-#define CONFIG_AT91FAMILY
-
 #define CONFIG_CMDLINE_TAG		/* enable passing of ATAGs	*/
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_INITRD_TAG
diff --git a/include/configs/cpu9260.h b/include/configs/cpu9260.h
index 39f7062388970a2bc6fdd62abfdc03020ed3430c..1feaefd14e6b7998903637ec2d8178f97e170f53 100644
--- a/include/configs/cpu9260.h
+++ b/include/configs/cpu9260.h
@@ -32,7 +32,6 @@
 
 #include <asm/arch/hardware.h>
 
-#define CONFIG_AT91FAMILY
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_BOARD_EARLY_INIT_F
diff --git a/include/configs/ethernut5.h b/include/configs/ethernut5.h
index 480d8678c6f8f2756313ed86ff2271ff30441125..c81fc44b121c5e28db83dea0642b5892a7799b18 100644
--- a/include/configs/ethernut5.h
+++ b/include/configs/ethernut5.h
@@ -23,8 +23,6 @@
 #define CONFIG_MACH_TYPE MACH_TYPE_ETHERNUT5
 
 /* CPU information */
-#define CONFIG_ARM926EJS
-#define CONFIG_AT91FAMILY
 #define CONFIG_DISPLAY_CPUINFO		/* Display at console. */
 #define CONFIG_ARCH_CPU_INIT
 
diff --git a/include/configs/highbank.h b/include/configs/highbank.h
index a6202cfab446ca30b806f153860fe0f7b92728cb..da1c837cc7a6efdd28b1f75355b2c6697ac95de9 100644
--- a/include/configs/highbank.h
+++ b/include/configs/highbank.h
@@ -13,6 +13,7 @@
 #define CONFIG_SYS_THUMB_BUILD
 
 #define CONFIG_SYS_NO_FLASH
+#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_OF_BOARD_SETUP
 #define CONFIG_FIT
diff --git a/include/configs/lsxl.h b/include/configs/lsxl.h
index 96a889fe87e36bf74abd9aafe55cff7807471dd4..f5f49613c89365fc6c35a55db8fa3cb1d858099f 100644
--- a/include/configs/lsxl.h
+++ b/include/configs/lsxl.h
@@ -66,6 +66,7 @@
 #define CONFIG_CMD_SF
 #define CONFIG_CMD_SPI
 #define CONFIG_CMD_USB
+#define CONFIG_CMD_FS_GENERIC
 
 #define CONFIG_DOS_PARTITION
 #define CONFIG_EFI_PARTITION
@@ -109,20 +110,41 @@
 #define CONFIG_LOADADDR		0x00800000
 #define CONFIG_BOOTCOMMAND	"run bootcmd_${bootsource}"
 #define CONFIG_BOOTARGS		"console=ttyS0,115200 root=/dev/sda2"
+
+#if defined(CONFIG_LSXHL)
+#define CONFIG_FDTFILE "kirkwood-lsxhl.dtb"
+#elif defined(CONFIG_LSCHLV2)
+#define CONFIG_FDTFILE "kirkwood-lschlv2.dtb"
+#else
+#error "Unsupported board"
+#endif
+
 #define CONFIG_EXTRA_ENV_SETTINGS					\
-	"bootsource=hdd\0"						\
+	"bootsource=legacy\0"						\
 	"hdpart=0:1\0"							\
-	"bootcmd_net=bootp 0x00100000 uImage "				\
-		"&& tftpboot 0x00800000 uInitrd "			\
+	"kernel_addr=0x00800000\0"					\
+	"ramdisk_addr=0x01000000\0"					\
+	"fdt_addr=0x01ff0000\0"						\
+	"bootcmd_legacy=ide reset "					\
+		"&& load ide ${hdpart} 0x00100000 /uImage.buffalo "	\
+		"&& load ide ${hdpart} 0x00800000 /initrd.buffalo "	\
 		"&& bootm 0x00100000 0x00800000\0"			\
+	"bootcmd_net=bootp ${kernel_addr} uImage "			\
+		"&& tftpboot ${ramdisk_addr} uInitrd "			\
+		"&& tftpboot ${fdt_addr} " CONFIG_FDTFILE " "		\
+		"&& bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"	\
 	"bootcmd_hdd=ide reset "					\
-		"&& ext2load ide ${hdpart} 0x00100000 /uImage "		\
-		"&& ext2load ide ${hdpart} 0x00800000 /uInitrd "	\
-		"&& bootm 0x00100000 0x00800000\0"			\
+		"&& load ide ${hdpart} ${kernel_addr} /uImage "		\
+		"&& load ide ${hdpart} ${ramdisk_addr} /uInitrd "	\
+		"&& load ide ${hdpart} ${fdt_addr} "			\
+			"/" CONFIG_FDTFILE " "				\
+		"&& bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"	\
 	"bootcmd_usb=usb start "					\
-		"&& fatload usb 0:1 0x00100000 /uImage "		\
-		"&& fatload usb 0:1 0x00800000 /uInitrd "		\
-		"&& bootm 0x00100000 0x00800000\0"			\
+		"&& load usb 0:1 ${kernel_addr} /uImage "		\
+		"&& load usb 0:1 ${ramdisk_addr} /uInitrd "		\
+		"&& load usb 0:1 ${fdt_addr} "				\
+			"/" CONFIG_FDTFILE " "				\
+		"&& bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"	\
 	"bootcmd_rescue=run config_nc_dhcp; run nc\0"			\
 	"eraseenv=sf probe 0 "						\
 		"&& sf erase " __stringify(CONFIG_ENV_OFFSET)		\
@@ -161,6 +183,7 @@
 #undef CONFIG_SYS_IDE_MAXDEVICE
 #define CONFIG_SYS_IDE_MAXDEVICE	1
 #define CONFIG_SYS_ATA_IDE0_OFFSET	MV_SATA_PORT0_OFFSET
+#define CONFIG_SYS_64BIT_LBA
 #endif
 
 #endif /* _CONFIG_LSXL_H */
diff --git a/include/configs/sama5d3_xplained.h b/include/configs/sama5d3_xplained.h
index 41c946d1ec8aeaf2f9af41cacad0ac2ad447e5a5..f72ab0bad01c74da3b8d67a96b1b75f07d3aa7fe 100644
--- a/include/configs/sama5d3_xplained.h
+++ b/include/configs/sama5d3_xplained.h
@@ -18,15 +18,20 @@
 #define CONFIG_SYS_AT91_SLOW_CLOCK      32768
 #define CONFIG_SYS_AT91_MAIN_CLOCK      12000000 /* from 12 MHz crystal */
 
-#define CONFIG_AT91FAMILY
 #define CONFIG_ARCH_CPU_INIT
+
+#ifndef CONFIG_SPL_BUILD
 #define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_DISPLAY_CPUINFO
 
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT		/* Device Tree support */
 
+#define CONFIG_SYS_GENERIC_BOARD
+
 /* general purpose I/O */
 #define CONFIG_AT91_GPIO
 
@@ -74,8 +79,12 @@
 #define CONFIG_SYS_SDRAM_BASE           ATMEL_BASE_DDRCS
 #define CONFIG_SYS_SDRAM_SIZE		0x10000000
 
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_SYS_INIT_SP_ADDR		0x310000
+#else
 #define CONFIG_SYS_INIT_SP_ADDR \
 	(CONFIG_SYS_SDRAM_BASE + 4 * 1024 - GENERATED_GBL_DATA_SIZE)
+#endif
 
 /* NAND flash */
 #define CONFIG_CMD_NAND
@@ -199,4 +208,46 @@
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(4 * 1024 * 1024)
 
+/* SPL */
+#define CONFIG_SPL
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_TEXT_BASE		0x300000
+#define CONFIG_SPL_MAX_SIZE		0x10000
+#define CONFIG_SPL_BSS_START_ADDR	0x20000000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x80000
+#define CONFIG_SYS_SPL_MALLOC_START	0x20080000
+#define CONFIG_SYS_SPL_MALLOC_SIZE	0x80000
+
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_GPIO_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+
+#define CONFIG_SPL_BOARD_INIT
+#define CONFIG_SYS_MONITOR_LEN		(512 << 10)
+
+#ifdef CONFIG_SYS_USE_MMC
+#define CONFIG_SPL_LDSCRIPT		arch/arm/cpu/at91-common/u-boot-spl.lds
+#define CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS	0x400
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 0x200
+#define CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION	1
+#define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME	"u-boot.img"
+#define CONFIG_SPL_FAT_SUPPORT
+#define CONFIG_SPL_LIBDISK_SUPPORT
+
+#elif CONFIG_SYS_USE_NANDFLASH
+#define CONFIG_SPL_NAND_SUPPORT
+#define CONFIG_SPL_NAND_DRIVERS
+#define CONFIG_SPL_NAND_BASE
+#define CONFIG_SYS_NAND_U_BOOT_OFFS	0x40000
+#define CONFIG_SYS_NAND_5_ADDR_CYCLE
+#define CONFIG_SYS_NAND_PAGE_SIZE	0x800
+#define CONFIG_SYS_NAND_PAGE_COUNT	64
+#define CONFIG_SYS_NAND_OOBSIZE		64
+#define CONFIG_SYS_NAND_BLOCK_SIZE	0x20000
+#define CONFIG_SYS_NAND_BAD_BLOCK_POS	0x0
+
+#endif
+
 #endif
diff --git a/include/configs/sama5d3xek.h b/include/configs/sama5d3xek.h
index 516be85fe08d9a1af60624826465a237448c5d6b..da2718044cf18b9f11641f3a695203411c7205fc 100644
--- a/include/configs/sama5d3xek.h
+++ b/include/configs/sama5d3xek.h
@@ -21,7 +21,6 @@
 #define CONFIG_SYS_AT91_SLOW_CLOCK      32768
 #define CONFIG_SYS_AT91_MAIN_CLOCK      12000000 /* from 12 MHz crystal */
 
-#define CONFIG_AT91FAMILY
 #define CONFIG_ARCH_CPU_INIT
 
 #ifndef CONFIG_SPL_BUILD
@@ -34,6 +33,8 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT		/* Device Tree support */
 
+#define CONFIG_SYS_GENERIC_BOARD
+
 /* general purpose I/O */
 #define CONFIG_AT91_GPIO
 
@@ -281,6 +282,7 @@
 #define CONFIG_SYS_NAND_OOBSIZE		64
 #define CONFIG_SYS_NAND_BLOCK_SIZE	0x20000
 #define CONFIG_SYS_NAND_BAD_BLOCK_POS	0x0
+#define CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER
 
 #elif CONFIG_SYS_USE_SERIALFLASH
 #define CONFIG_SPL_SPI_SUPPORT
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
new file mode 100644
index 0000000000000000000000000000000000000000..9b693f7039769babd00c04272f529d69b78360d6
--- /dev/null
+++ b/include/configs/sun7i.h
@@ -0,0 +1,24 @@
+/*
+ * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * Configuration settings for the Allwinner A20 (sun7i) CPU
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * A20 specific configuration
+ */
+#define CONFIG_SUN7I		/* sun7i SoC generation */
+
+#define CONFIG_SYS_PROMPT		"sun7i# "
+
+/*
+ * Include common sunxi configuration where most the settings are
+ */
+#include <configs/sunxi-common.h>
+
+#endif /* __CONFIG_H */
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d72d62f14d14abcfb7e616010edd2db964d8650
--- /dev/null
+++ b/include/configs/sunxi-common.h
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2012-2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * Configuration settings for the Allwinner sunxi series of boards.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_COMMON_CONFIG_H
+#define _SUNXI_COMMON_CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+#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 */
+
+#define CONFIG_SYS_TEXT_BASE		0x4a000000
+
+/*
+ * Display CPU information
+ */
+#define CONFIG_DISPLAY_CPUINFO
+
+/* Serial & console */
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+/* ns16550 reg in the low bits of cpu reg */
+#define CONFIG_SYS_NS16550_REG_SIZE	-4
+#define CONFIG_SYS_NS16550_CLK		24000000
+#define CONFIG_SYS_NS16550_COM1		SUNXI_UART0_BASE
+#define CONFIG_SYS_NS16550_COM2		SUNXI_UART1_BASE
+#define CONFIG_SYS_NS16550_COM3		SUNXI_UART2_BASE
+#define CONFIG_SYS_NS16550_COM4		SUNXI_UART3_BASE
+
+/* DRAM Base */
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+#define CONFIG_SYS_INIT_RAM_ADDR	0x0
+#define CONFIG_SYS_INIT_RAM_SIZE	0x8000	/* 32 KiB */
+
+#define CONFIG_SYS_INIT_SP_OFFSET \
+	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
+
+#define CONFIG_NR_DRAM_BANKS		1
+#define PHYS_SDRAM_0			CONFIG_SYS_SDRAM_BASE
+#define PHYS_SDRAM_0_SIZE		0x80000000 /* 2 GiB */
+
+#define CONFIG_CMD_MEMORY
+#define CONFIG_CMD_SETEXPR
+
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_INITRD_TAG
+
+/* mmc config */
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_CMD_MMC
+#define CONFIG_MMC_SUNXI
+#define CONFIG_MMC_SUNXI_SLOT		0
+#define CONFIG_MMC_SUNXI_USE_DMA
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
+
+/* 4MB of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + (4 << 20))
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_CMD_ECHO
+#define CONFIG_SYS_CBSIZE	256	/* Console I/O Buffer Size */
+#define CONFIG_SYS_PBSIZE	384	/* Print Buffer Size */
+#define CONFIG_SYS_MAXARGS	16	/* max number of command args */
+#define CONFIG_SYS_GENERIC_BOARD
+
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_LOAD_ADDR		0x48000000 /* default load address */
+
+/* standalone support */
+#define CONFIG_STANDALONE_LOAD_ADDR	0x48000000
+
+#define CONFIG_SYS_HZ			1000
+
+/* baudrate */
+#define CONFIG_BAUDRATE			115200
+
+/* The stack sizes are set up in start.S using the settings below */
+#define CONFIG_STACKSIZE		(256 << 10)	/* 256 KiB */
+
+/* FLASH and environment organization */
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_MONITOR_LEN		(512 << 10)	/* 512 KiB */
+#define CONFIG_IDENT_STRING		" Allwinner Technology"
+
+#define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
+#define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"bootm_size=0x10000000\0"
+
+#define CONFIG_SYS_BOOT_GET_CMDLINE
+
+#include <config_cmd_default.h>
+
+#define CONFIG_FAT_WRITE	/* enable write access */
+
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+
+#ifdef CONFIG_SPL_FEL
+
+#define CONFIG_SPL
+#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 */
+
+#else /* CONFIG_SPL */
+
+#define CONFIG_SPL_BSS_START_ADDR	0x4ff80000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x80000		/* 512 KiB */
+
+#define CONFIG_SPL_TEXT_BASE		0x20		/* sram start+header */
+#define CONFIG_SPL_MAX_SIZE		0x5fe0		/* 24KB on sun4i/sun7i */
+
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#define CONFIG_SPL_MMC_SUPPORT
+
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/sunxi/u-boot-spl.lds"
+
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR	80	/* 40KiB */
+#define CONFIG_SPL_PAD_TO		32768		/* decimal for 'dd' */
+
+#endif /* CONFIG_SPL */
+
+/* end of 32 KiB in sram */
+#define LOW_LEVEL_SRAM_STACK		0x00008000 /* End of sram */
+#define CONFIG_SPL_STACK		LOW_LEVEL_SRAM_STACK
+#define CONFIG_SYS_SPL_MALLOC_START	0x4ff00000
+#define CONFIG_SYS_SPL_MALLOC_SIZE	0x00080000	/* 512 KiB */
+
+#undef CONFIG_CMD_FPGA
+#undef CONFIG_CMD_NET
+#undef CONFIG_CMD_NFS
+
+#define CONFIG_CONS_INDEX              1       /* UART0 */
+
+#ifdef CONFIG_SUNXI_GMAC
+#define CONFIG_DESIGNWARE_ETH		/* GMAC can use designware driver */
+#define CONFIG_DW_AUTONEG
+#define CONFIG_PHY_GIGE			/* GMAC can use gigabit PHY	*/
+#define CONFIG_PHY_ADDR		1
+#define CONFIG_MII			/* MII PHY management		*/
+#define CONFIG_PHYLIB
+#endif
+
+#ifdef CONFIG_CMD_NET
+#define CONFIG_CMD_NFS
+#define CONFIG_CMD_DNS
+#define CONFIG_NETCONSOLE
+#define CONFIG_BOOTP_DNS2
+#define CONFIG_BOOTP_SEND_HOSTNAME
+#endif
+
+#if !defined CONFIG_ENV_IS_IN_MMC && \
+    !defined CONFIG_ENV_IS_IN_NAND && \
+    !defined CONFIG_ENV_IS_IN_FAT && \
+    !defined CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+#include <config_distro_defaults.h>
+#endif
+
+#endif /* _SUNXI_COMMON_CONFIG_H */
diff --git a/include/configs/vl_ma2sc.h b/include/configs/vl_ma2sc.h
index 14c6e675c1b8429b463d2b0672683a378f22581f..bef821f3371a2227dd505ba59e72c895cfd3d6af 100644
--- a/include/configs/vl_ma2sc.h
+++ b/include/configs/vl_ma2sc.h
@@ -13,8 +13,6 @@
 
 /*--------------------------------------------------------------------------*/
 
-#define CONFIG_ARM926EJS		/* This is an ARM926EJS Core	*/
-#define CONFIG_AT91FAMILY
 #define CONFIG_AT91SAM9263		/* It's an Atmel AT91SAM9263 SoC*/
 #define CONFIG_VL_MA2SC			/* on an VL_MA2SC Board	*/
 #define CONFIG_ARCH_CPU_INIT
diff --git a/include/image.h b/include/image.h
index 18861686cc139db06342d9ab8974f54ffa624d31..41e56abe15ce22e9244fc5ab348b26025f6463cd 100644
--- a/include/image.h
+++ b/include/image.h
@@ -225,6 +225,7 @@ struct lmb;
 #define IH_TYPE_PBLIMAGE	15	/* Freescale PBL Boot Image	*/
 #define IH_TYPE_MXSIMAGE	16	/* Freescale MXSBoot Image	*/
 #define IH_TYPE_GPIMAGE		17	/* TI Keystone GPHeader Image	*/
+#define IH_TYPE_ATMELIMAGE	18	/* ATMEL ROM bootable Image	*/
 
 /*
  * Compression Types
diff --git a/include/netdev.h b/include/netdev.h
index e211f1841f60d7dac07d43d4dd9297a720854ac2..63481eca22688080f5b26e7da99013af88f06c1d 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -78,6 +78,7 @@ int sh_eth_initialize(bd_t *bis);
 int skge_initialize(bd_t *bis);
 int smc91111_initialize(u8 dev_num, int base_addr);
 int smc911x_initialize(u8 dev_num, int base_addr);
+int sunxi_gmac_initialize(bd_t *bis);
 int sunxi_wemac_initialize(bd_t *bis);
 int tsi108_eth_initialize(bd_t *bis);
 int uec_standard_init(bd_t *bis);
diff --git a/spl/Makefile b/spl/Makefile
index 55500fd8970042fb537d1df90f65529af2236877..bf677aa42a6027fb7a069f20507a793eea819df8 100644
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -183,12 +183,29 @@ MKIMAGEFLAGS_MLO.byteswap = -T omapimage -n byteswap -a $(CONFIG_SPL_TEXT_BASE)
 MLO MLO.byteswap: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkimage)
 
+MKIMAGEFLAGS_boot.bin = -T atmelimage
+
+ifeq ($(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER),y)
+MKIMAGEFLAGS_boot.bin += -n $(shell $(obj)/../tools/atmel_pmecc_params)
+
+boot.bin: $(obj)/../tools/atmel_pmecc_params
+endif
+
+boot.bin: $(obj)/u-boot-spl.bin
+	$(call if_changed,mkimage)
+
 ALL-y	+= $(obj)/$(SPL_BIN).bin
 
 ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)/$(BOARD)-spl.bin
 endif
 
+ifdef CONFIG_SUNXI
+ifndef CONFIG_SPL_FEL
+ALL-y	+= $(obj)/sunxi-spl.bin
+endif
+endif
+
 all:	$(ALL-y)
 
 ifdef CONFIG_SAMSUNG
@@ -216,6 +233,13 @@ ifneq ($(CONFIG_SPL_TEXT_BASE),)
 LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_SPL_TEXT_BASE)
 endif
 
+ifdef CONFIG_SUNXI
+quiet_cmd_mksunxiboot = MKSUNXI $@
+cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
+$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin
+	$(call if_changed,mksunxiboot)
+endif
+
 quiet_cmd_u-boot-spl = LD      $@
       cmd_u-boot-spl = cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
 		       $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
diff --git a/tools/.gitignore b/tools/.gitignore
index b1e997fc3ee0018efb954ad858201e01ca3c3d82..725db906e840a3c2a035d05b67a93c110072e944 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -11,6 +11,7 @@
 /mkexynosspl
 /mpc86x_clk
 /mxsboot
+/mksunxiboot
 /ncb
 /proftool
 /relocate-rela
diff --git a/tools/Makefile b/tools/Makefile
index 6e43a0150d41d200bdd4097bcdc2c5a3af792277..761055764bf6ab1e27bd8f4c27602879244effe6 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -38,6 +38,8 @@ ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y
 ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y
 CONFIG_BUILD_ENVCRC ?= $(ENVCRC-y)
 
+hostprogs-$(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER) += atmel_pmecc_params$(SFX)
+
 # TODO: CONFIG_CMD_LICENSE does not work
 hostprogs-$(CONFIG_CMD_LICENSE) += bin2header$(SFX)
 hostprogs-$(CONFIG_LCD_LOGO) += bmp_logo$(SFX)
@@ -69,6 +71,7 @@ RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o rsa-verify.o rsa-checksum.o
 
 # common objs for dumpimage and mkimage
 dumpimage-mkimage-objs := aisimage.o \
+			atmelimage.o \
 			$(FIT_SIG_OBJS-y) \
 			crc32.o \
 			default_image.o \
@@ -131,6 +134,8 @@ hostprogs-$(CONFIG_MX23) += mxsboot$(SFX)
 hostprogs-$(CONFIG_MX28) += mxsboot$(SFX)
 HOSTCFLAGS_mxsboot$(SFX).o := -pedantic
 
+hostprogs-$(CONFIG_SUNXI) += mksunxiboot$(SFX)
+
 hostprogs-$(CONFIG_NETCONSOLE) += ncb$(SFX)
 hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
 
diff --git a/tools/atmel_pmecc_params.c b/tools/atmel_pmecc_params.c
new file mode 100644
index 0000000000000000000000000000000000000000..8eaf27f80493576a3d3724db620c6e505e493bd7
--- /dev/null
+++ b/tools/atmel_pmecc_params.c
@@ -0,0 +1,51 @@
+/*
+ * (C) Copyright 2014 Andreas Bießmann <andreas.devel@googlemail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * This is a host tool for generating an appropriate string out of board
+ * configuration. The string is required for correct generation of PMECC
+ * header which in turn is required for NAND flash booting of Atmel AT91 style
+ * hardware.
+ *
+ * See doc/README.atmel_pmecc for more information.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+static int pmecc_get_ecc_bytes(int cap, int sector_size)
+{
+	int m = 12 + sector_size / 512;
+	return (m * cap + 7) / 8;
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned int use_pmecc = 0;
+	unsigned int sector_per_page;
+	unsigned int sector_size = CONFIG_PMECC_SECTOR_SIZE;
+	unsigned int oob_size = CONFIG_SYS_NAND_OOBSIZE;
+	unsigned int ecc_bits = CONFIG_PMECC_CAP;
+	unsigned int ecc_offset;
+
+#ifdef CONFIG_ATMEL_NAND_HW_PMECC
+	use_pmecc = 1;
+#endif
+
+	sector_per_page = CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_PMECC_SECTOR_SIZE;
+	ecc_offset = oob_size -
+		pmecc_get_ecc_bytes(ecc_bits, sector_size) * sector_per_page;
+
+	printf("usePmecc=%d,", use_pmecc);
+	printf("sectorPerPage=%d,", sector_per_page);
+	printf("sectorSize=%d,", sector_size);
+	printf("spareSize=%d,", oob_size);
+	printf("eccBits=%d,", ecc_bits);
+	printf("eccOffset=%d", ecc_offset);
+	printf("\n");
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/tools/atmelimage.c b/tools/atmelimage.c
new file mode 100644
index 0000000000000000000000000000000000000000..c8101d2ddc221803c2e07f1991be35abcc69d055
--- /dev/null
+++ b/tools/atmelimage.c
@@ -0,0 +1,342 @@
+/*
+ * (C) Copyright 2014
+ * Andreas Bießmann <andreas.devel@googlemail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include "mkimage.h"
+
+#include <image.h>
+
+#define pr_err(fmt, args...) fprintf(stderr, "atmelimage Error: " fmt, ##args)
+
+static int atmel_check_image_type(uint8_t type)
+{
+	if (type == IH_TYPE_ATMELIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static uint32_t nand_pmecc_header[52];
+
+/*
+ * A helper struct for parsing the mkimage -n parameter
+ *
+ * Keep in same order as the configs array!
+ */
+static struct pmecc_config {
+	int use_pmecc;
+	int sector_per_page;
+	int spare_size;
+	int ecc_bits;
+	int sector_size;
+	int ecc_offset;
+} pmecc;
+
+/*
+ * Strings used for configure the PMECC header via -n mkimage switch
+ *
+ * We estimate a coma separated list of key=value pairs. The mkimage -n
+ * parameter argument should not contain any whitespace.
+ *
+ * Keep in same order as struct pmecc_config!
+ */
+static const char * const configs[] = {
+	"usePmecc",
+	"sectorPerPage",
+	"spareSize",
+	"eccBits",
+	"sectorSize",
+	"eccOffset"
+};
+
+static int atmel_find_pmecc_parameter_in_token(const char *token)
+{
+	size_t pos;
+	char *param;
+
+	debug("token: '%s'\n", token);
+
+	for (pos = 0; pos < ARRAY_SIZE(configs); pos++) {
+		if (strncmp(token, configs[pos], strlen(configs[pos])) == 0) {
+			param = strstr(token, "=");
+			if (!param)
+				goto err;
+
+			param++;
+			debug("\t%s parameter: '%s'\n", configs[pos], param);
+
+			switch (pos) {
+			case 0:
+				pmecc.use_pmecc = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			case 1:
+				pmecc.sector_per_page = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			case 2:
+				pmecc.spare_size = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			case 3:
+				pmecc.ecc_bits = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			case 4:
+				pmecc.sector_size = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			case 5:
+				pmecc.ecc_offset = strtol(param, NULL, 10);
+				return EXIT_SUCCESS;
+			}
+		}
+	}
+
+err:
+	pr_err("Could not find parameter in token '%s'\n", token);
+	return EXIT_FAILURE;
+}
+
+static int atmel_parse_pmecc_params(char *txt)
+{
+	char *token;
+
+	token = strtok(txt, ",");
+	while (token != NULL) {
+		if (atmel_find_pmecc_parameter_in_token(token))
+			return EXIT_FAILURE;
+
+		token = strtok(NULL, ",");
+	}
+
+	return EXIT_SUCCESS;
+}
+
+static int atmel_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	uint32_t *ints = (uint32_t *)ptr;
+	size_t pos;
+	size_t size = image_size;
+
+	/* check if we have an PMECC header attached */
+	for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
+		if (ints[pos] >> 28 != 0xC)
+			break;
+
+	if (pos == ARRAY_SIZE(nand_pmecc_header)) {
+		ints += ARRAY_SIZE(nand_pmecc_header);
+		size -= sizeof(nand_pmecc_header);
+	}
+
+	/* check the seven interrupt vectors of binary */
+	for (pos = 0; pos < 7; pos++) {
+		debug("atmelimage: interrupt vector #%d is 0x%08X\n", pos+1,
+		      ints[pos]);
+		/*
+		 * all vectors except the 6'th one must contain valid
+		 * LDR or B Opcode
+		 */
+		if (pos == 5)
+			/* 6'th vector has image size set, check later */
+			continue;
+		if ((ints[pos] & 0xff000000) == 0xea000000)
+			/* valid B Opcode */
+			continue;
+		if ((ints[pos] & 0xfffff000) == 0xe59ff000)
+			/* valid LDR (I=0, P=1, U=1, B=0, W=0, L=1) */
+			continue;
+		/* ouch, one of the checks has missed ... */
+		return 1;
+	}
+
+	return ints[5] != cpu_to_le32(size);
+}
+
+static void atmel_print_pmecc_header(const uint32_t word)
+{
+	int val;
+
+	printf("\t\tPMECC header\n");
+
+	printf("\t\t====================\n");
+
+	val = (word >> 18) & 0x1ff;
+	printf("\t\teccOffset: %9i\n", val);
+
+	val = (((word >> 16) & 0x3) == 0) ? 512 : 1024;
+	printf("\t\tsectorSize: %8i\n", val);
+
+	if (((word >> 13) & 0x7) <= 2)
+		val = (2 << ((word >> 13) & 0x7));
+	else
+		val = (12 << (((word >> 13) & 0x7) - 3));
+	printf("\t\teccBitReq: %9i\n", val);
+
+	val = (word >> 4) & 0x1ff;
+	printf("\t\tspareSize: %9i\n", val);
+
+	val = (1 << ((word >> 1) & 0x3));
+	printf("\t\tnbSectorPerPage: %3i\n", val);
+
+	printf("\t\tusePmecc: %10i\n", word & 0x1);
+	printf("\t\t====================\n");
+}
+
+static void atmel_print_header(const void *ptr)
+{
+	uint32_t *ints = (uint32_t *)ptr;
+	size_t pos;
+
+	/* check if we have an PMECC header attached */
+	for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
+		if (ints[pos] >> 28 != 0xC)
+			break;
+
+	if (pos == ARRAY_SIZE(nand_pmecc_header)) {
+		printf("Image Type:\tATMEL ROM-Boot Image with PMECC Header\n");
+		atmel_print_pmecc_header(ints[0]);
+		pos += 5;
+	} else {
+		printf("Image Type:\tATMEL ROM-Boot Image without PMECC Header\n");
+		pos = 5;
+	}
+	printf("\t\t6'th vector has %u set\n", le32_to_cpu(ints[pos]));
+}
+
+static void atmel_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	/* just save the image size into 6'th interrupt vector */
+	uint32_t *ints = (uint32_t *)ptr;
+	size_t cnt;
+	size_t pos = 5;
+	size_t size = sbuf->st_size;
+
+	for (cnt = 0; cnt < ARRAY_SIZE(nand_pmecc_header); cnt++)
+		if (ints[cnt] >> 28 != 0xC)
+			break;
+
+	if (cnt == ARRAY_SIZE(nand_pmecc_header)) {
+		pos += ARRAY_SIZE(nand_pmecc_header);
+		size -= sizeof(nand_pmecc_header);
+	}
+
+	ints[pos] = cpu_to_le32(size);
+}
+
+static int atmel_check_params(struct image_tool_params *params)
+{
+	if (strlen(params->imagename) > 0)
+		if (atmel_parse_pmecc_params(params->imagename))
+			return EXIT_FAILURE;
+
+	return !(!params->eflag &&
+		!params->fflag &&
+		!params->xflag &&
+		((params->dflag && !params->lflag) ||
+		 (params->lflag && !params->dflag)));
+}
+
+static int atmel_vrec_header(struct image_tool_params *params,
+				struct image_type_params *tparams)
+{
+	uint32_t tmp;
+	size_t pos;
+
+	if (strlen(params->imagename) == 0)
+		return EXIT_SUCCESS;
+
+	tmp = 0xC << 28;
+
+	tmp |= (pmecc.ecc_offset & 0x1ff) << 18;
+
+	switch (pmecc.sector_size) {
+	case 512:
+		tmp |= 0 << 16;
+		break;
+	case 1024:
+		tmp |= 1 << 16;
+		break;
+
+	default:
+		pr_err("Wrong sectorSize (%i) for PMECC header\n",
+		       pmecc.sector_size);
+		return EXIT_FAILURE;
+	}
+
+	switch (pmecc.ecc_bits) {
+	case 2:
+		tmp |= 0 << 13;
+		break;
+	case 4:
+		tmp |= 1 << 13;
+		break;
+	case 8:
+		tmp |= 2 << 13;
+		break;
+	case 12:
+		tmp |= 3 << 13;
+		break;
+	case 24:
+		tmp |= 4 << 13;
+		break;
+
+	default:
+		pr_err("Wrong eccBits (%i) for PMECC header\n",
+		       pmecc.ecc_bits);
+		 return EXIT_FAILURE;
+	}
+
+	tmp |= (pmecc.spare_size & 0x1ff) << 4;
+
+	switch (pmecc.sector_per_page) {
+	case 1:
+		tmp |= 0 << 1;
+		break;
+	case 2:
+		tmp |= 1 << 1;
+		break;
+	case 4:
+		tmp |= 2 << 1;
+		break;
+	case 8:
+		tmp |= 3 << 1;
+		break;
+
+	default:
+		pr_err("Wrong sectorPerPage (%i) for PMECC header\n",
+		       pmecc.sector_per_page);
+		return EXIT_FAILURE;
+	}
+
+	if (pmecc.use_pmecc)
+		tmp |= 1;
+
+	for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
+		nand_pmecc_header[pos] = tmp;
+
+	debug("PMECC header filled 52 times with 0x%08X\n", tmp);
+
+	tparams->header_size = sizeof(nand_pmecc_header);
+	tparams->hdr = nand_pmecc_header;
+
+	return EXIT_SUCCESS;
+}
+
+static struct image_type_params atmelimage_params = {
+	.name		= "ATMEL ROM-Boot Image support",
+	.header_size	= 0,
+	.hdr		= NULL,
+	.check_image_type = atmel_check_image_type,
+	.verify_header	= atmel_verify_header,
+	.print_header	= atmel_print_header,
+	.set_header	= atmel_set_header,
+	.check_params	= atmel_check_params,
+	.vrec_header	= atmel_vrec_header,
+};
+
+void init_atmel_image_type(void)
+{
+	register_image_type(&atmelimage_params);
+}
diff --git a/tools/imagetool.c b/tools/imagetool.c
index da72115e53230a53444078df089186d932bec54b..32d6278edb95fe8be0a8d17a0050e7c84d72c8d4 100644
--- a/tools/imagetool.c
+++ b/tools/imagetool.c
@@ -27,6 +27,8 @@ void register_image_tool(imagetool_register_t image_register)
 	 */
 	register_func = image_register;
 
+	/* Init ATMEL ROM Boot Image generation/list support */
+	init_atmel_image_type();
 	/* Init Freescale PBL Boot image generation/list support */
 	init_pbl_image_type();
 	/* Init Kirkwood Boot image generation/list support */
diff --git a/tools/imagetool.h b/tools/imagetool.h
index a3e9d302eb3f9de7324a5055521b9008b24bcfa5..c480687ec13884c43cb99ac39a977847198aa375 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -159,6 +159,7 @@ void register_image_type(struct image_type_params *tparams);
  * Supported image types init functions
  */
 void init_default_image_type(void);
+void init_atmel_image_type(void);
 void init_pbl_image_type(void);
 void init_ais_image_type(void);
 void init_kwb_image_type(void);
diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c
new file mode 100644
index 0000000000000000000000000000000000000000..da7c9f0ddc004adf9f7402a876a400ecc16cdf93
--- /dev/null
+++ b/tools/mksunxiboot.c
@@ -0,0 +1,142 @@
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * a simple tool to generate bootable image for sunxi platform.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* boot head definition from sun4i boot code */
+struct boot_file_head {
+	uint32_t b_instruction;	/* one intruction jumping to real code */
+	uint8_t magic[8];	/* ="eGON.BT0" or "eGON.BT1", not C-style str */
+	uint32_t check_sum;	/* generated by PC */
+	uint32_t length;	/* generated by PC */
+	/*
+	 * We use a simplified header, only filling in what is needed
+	 * by the boot ROM. To be compatible with Allwinner tools we
+	 * would need to implement the proper fields here instead of
+	 * padding.
+	 */
+	uint8_t pad[12];		/* align to 32 bytes */
+};
+
+#define BOOT0_MAGIC                     "eGON.BT0"
+#define STAMP_VALUE                     0x5F0A6C39
+
+/* check sum functon from sun4i boot code */
+int gen_check_sum(struct boot_file_head *head_p)
+{
+	uint32_t length;
+	uint32_t *buf;
+	uint32_t loop;
+	uint32_t i;
+	uint32_t sum;
+
+	length = 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 */
+	loop = length >> 2;
+
+	/* calculate the sum */
+	for (i = 0, sum = 0; i < loop; i++)
+		sum += buf[i];
+
+	/* write back check sum */
+	head_p->check_sum = sum;
+
+	return 0;
+}
+
+#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
+#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
+
+#define SUN4I_SRAM_SIZE 0x7600	/* 0x7748+ is used by BROM */
+#define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head))
+#define BLOCK_SIZE 512
+
+struct boot_img {
+	struct boot_file_head header;
+	char code[SRAM_LOAD_MAX_SIZE];
+	char pad[BLOCK_SIZE];
+};
+
+int main(int argc, char *argv[])
+{
+	int fd_in, fd_out;
+	struct boot_img img;
+	unsigned file_size, load_size;
+	int count;
+
+	if (argc < 2) {
+		printf("\tThis program makes an input bin file to sun4i " \
+		       "bootable image.\n" \
+		       "\tUsage: %s input_file out_putfile\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	fd_in = open(argv[1], O_RDONLY);
+	if (fd_in < 0) {
+		perror("Open input file");
+		return EXIT_FAILURE;
+	}
+
+	memset(img.pad, 0, BLOCK_SIZE);
+
+	/* get input file size */
+	file_size = lseek(fd_in, 0, SEEK_END);
+
+	if (file_size > SRAM_LOAD_MAX_SIZE) {
+		fprintf(stderr, "ERROR: File too large!\n");
+		return EXIT_FAILURE;
+	} else {
+		load_size = ALIGN(file_size, sizeof(int));
+	}
+
+	fd_out = open(argv[2], O_WRONLY | O_CREAT, 0666);
+	if (fd_out < 0) {
+		perror("Open output file");
+		return EXIT_FAILURE;
+	}
+
+	/* read file to buffer to calculate checksum */
+	lseek(fd_in, 0, SEEK_SET);
+	count = read(fd_in, img.code, load_size);
+	if (count != load_size) {
+		perror("Reading input image");
+		return EXIT_FAILURE;
+	}
+
+	/* fill the header */
+	img.header.b_instruction =	/* b instruction */
+		0xEA000000 |	/* jump to the first instr after the header */
+		((sizeof(struct boot_file_head) / sizeof(int) - 2)
+		 & 0x00FFFFFF);
+	memcpy(img.header.magic, BOOT0_MAGIC, 8);	/* no '0' termination */
+	img.header.length =
+		ALIGN(load_size + sizeof(struct boot_file_head), BLOCK_SIZE);
+	gen_check_sum(&img.header);
+
+	count = write(fd_out, &img, img.header.length);
+	if (count != img.header.length) {
+		perror("Writing output");
+		return EXIT_FAILURE;
+	}
+
+	close(fd_in);
+	close(fd_out);
+
+	return EXIT_SUCCESS;
+}