Merge branch 'master' of http://git.denx.de/u-boot-sunxi
diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
index a0e49d1..49f4032 100644
--- a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
+++ b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
@@ -180,6 +180,21 @@
 }
 #endif
 
+void clock_set_pll3(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (clk == 0) {
+		clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN);
+		return;
+	}
+
+	/* PLL3 rate = 3000000 * m */
+	writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE |
+	       CCM_PLL3_CTRL_M(clk / 3000000), &ccm->pll3_cfg);
+}
+
 unsigned int clock_get_pll5p(void)
 {
 	struct sunxi_ccm_reg *const ccm =
@@ -200,3 +215,15 @@
 	int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1;
 	return 24000000 * n * k / 2;
 }
+
+void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz)
+{
+	int pll = clock_get_pll5p();
+	int div = 1;
+
+	while ((pll / div) > hz)
+		div++;
+
+	writel(CCM_DE_CTRL_GATE | CCM_DE_CTRL_RST | CCM_DE_CTRL_PLL5P |
+	       CCM_DE_CTRL_M(div), clk_cfg);
+}
diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun6i.c b/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
index 16ab6f3..8e949c6 100644
--- a/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
+++ b/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
@@ -127,6 +127,23 @@
 }
 #endif
 
+void clock_set_pll3(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	const int m = 8; /* 3 MHz steps just like sun4i, sun5i and sun7i */
+
+	if (clk == 0) {
+		clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN);
+		return;
+	}
+
+	/* PLL3 rate = 24000000 * n / m */
+	writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE |
+	       CCM_PLL3_CTRL_N(clk / (24000000 / m)) | CCM_PLL3_CTRL_M(m),
+	       &ccm->pll3_cfg);
+}
+
 void clock_set_pll5(unsigned int clk)
 {
 	struct sunxi_ccm_reg * const ccm =
@@ -151,3 +168,15 @@
 	int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1;
 	return 24000000 * n * k / 2;
 }
+
+void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz)
+{
+	int pll = clock_get_pll6() * 2;
+	int div = 1;
+
+	while ((pll / div) > hz)
+		div++;
+
+	writel(CCM_DE_CTRL_GATE | CCM_DE_CTRL_PLL6_2X | CCM_DE_CTRL_M(div),
+	       clk_cfg);
+}
diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun4i.c b/arch/arm/cpu/armv7/sunxi/dram_sun4i.c
index dc9fdb9..ec8aaa7 100644
--- a/arch/arm/cpu/armv7/sunxi/dram_sun4i.c
+++ b/arch/arm/cpu/armv7/sunxi/dram_sun4i.c
@@ -428,9 +428,9 @@
 #ifdef CONFIG_MACH_SUN4I
 	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	if (on)
-		setbits_le32(&ccm->dram_clk_cfg, CCM_DRAM_CTRL_DCLK_OUT);
+		setbits_le32(&ccm->dram_clk_gate, CCM_DRAM_CTRL_DCLK_OUT);
 	else
-		clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAM_CTRL_DCLK_OUT);
+		clrbits_le32(&ccm->dram_clk_gate, CCM_DRAM_CTRL_DCLK_OUT);
 #endif
 }
 
diff --git a/arch/arm/cpu/armv7/sunxi/dram_sun6i.c b/arch/arm/cpu/armv7/sunxi/dram_sun6i.c
index 10a6241..699173c 100644
--- a/arch/arm/cpu/armv7/sunxi/dram_sun6i.c
+++ b/arch/arm/cpu/armv7/sunxi/dram_sun6i.c
@@ -142,9 +142,6 @@
 
 	writel((MCTL_TITMSRST << 18) | (MCTL_TDLLLOCK << 6) | MCTL_TDLLSRST,
 	       &mctl_phy->ptr0);
-	/* Unknown magic performed by boot0 */
-	if ((readl(SUNXI_RTC_BASE + 0x20c) & 3) == 2)
-		setbits_le32(&mctl_phy->ptr0, 1 << 18);
 
 	writel((MCTL_TDINIT1 << 19) | MCTL_TDINIT0, &mctl_phy->ptr1);
 	writel((MCTL_TDINIT3 << 17) | MCTL_TDINIT2, &mctl_phy->ptr2);
diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
index b40c16b..64acff3 100644
--- a/arch/arm/include/asm/arch-sunxi/clock.h
+++ b/arch/arm/include/asm/arch-sunxi/clock.h
@@ -25,9 +25,11 @@
 int clock_init(void);
 int clock_twi_onoff(int port, int state);
 void clock_set_pll1(unsigned int hz);
+void clock_set_pll3(unsigned int hz);
 void clock_set_pll5(unsigned int hz);
 unsigned int clock_get_pll5p(void);
 unsigned int clock_get_pll6(void);
+void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz);
 void clock_init_safe(void);
 void clock_init_uart(void);
 #endif
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
index 9dca800..eb88969 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
@@ -62,7 +62,7 @@
 	u32 gps_clk_cfg;	/* 0xd0 */
 	u32 spi3_clk_cfg;	/* 0xd4 */
 	u8 res5[0x28];
-	u32 dram_clk_cfg;	/* 0x100 */
+	u32 dram_clk_gate;	/* 0x100 */
 	u32 be0_clk_cfg;	/* 0x104 */
 	u32 be1_clk_cfg;	/* 0x108 */
 	u32 fe0_clk_cfg;	/* 0x10c */
@@ -186,12 +186,20 @@
 
 /* ahb clock gate bit offset (second register) */
 #define AHB_GATE_OFFSET_GMAC		17
+#define AHB_GATE_OFFSET_DE_BE0		12
+#define AHB_GATE_OFFSET_HDMI		11
+#define AHB_GATE_OFFSET_LCD1		5
+#define AHB_GATE_OFFSET_LCD0		4
 
 #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_PLL3_CTRL_M(n)		(((n) & 0x7f) << 0)
+#define CCM_PLL3_CTRL_INTEGER_MODE	(0x1 << 15)
+#define CCM_PLL3_CTRL_EN		(0x1 << 31)
+
 #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)
@@ -253,6 +261,34 @@
 
 #define CCM_MMC_CTRL_ENABLE (0x1 << 31)
 
+#define CCM_DRAM_GATE_OFFSET_DE_BE0	26
+
+#define CCM_LCD_CH0_CTRL_PLL3		(0 << 24)
+#define CCM_LCD_CH0_CTRL_PLL7		(1 << 24)
+#define CCM_LCD_CH0_CTRL_PLL3_2X	(2 << 24)
+#define CCM_LCD_CH0_CTRL_PLL7_2X	(3 << 24)
+#define CCM_LCD_CH0_CTRL_RST		(0x1 << 30)
+#define CCM_LCD_CH0_CTRL_GATE		(0x1 << 31)
+
+#define CCM_LCD_CH1_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+/* We leave bit 11 set to 0, so sclk1 == sclk2 */
+#define CCM_LCD_CH1_CTRL_PLL3		(0 << 24)
+#define CCM_LCD_CH1_CTRL_PLL7		(1 << 24)
+#define CCM_LCD_CH1_CTRL_PLL3_2X	(2 << 24)
+#define CCM_LCD_CH1_CTRL_PLL7_2X	(3 << 24)
+/* Enable / disable both ch1 sclk1 and sclk2 at the same time */
+#define CCM_LCD_CH1_CTRL_GATE		(0x1 << 31 | 0x1 << 15)
+
+#define CCM_HDMI_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_HDMI_CTRL_PLL_MASK		(3 << 24)
+#define CCM_HDMI_CTRL_PLL3		(0 << 24)
+#define CCM_HDMI_CTRL_PLL7		(1 << 24)
+#define CCM_HDMI_CTRL_PLL3_2X		(2 << 24)
+#define CCM_HDMI_CTRL_PLL7_2X		(3 << 24)
+/* No separate ddc gate on sun4i, sun5i and sun7i */
+#define CCM_HDMI_CTRL_DDC_GATE		0
+#define CCM_HDMI_CTRL_GATE		(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
@@ -266,4 +302,13 @@
 #define CCM_USB_CTRL_PHY1_CLK 0
 #define CCM_USB_CTRL_PHY2_CLK 0
 
+/* CCM bits common to all Display Engine (and IEP) clock ctrl regs */
+#define CCM_DE_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_DE_CTRL_PLL_MASK		(3 << 24)
+#define CCM_DE_CTRL_PLL3		(0 << 24)
+#define CCM_DE_CTRL_PLL7		(1 << 24)
+#define CCM_DE_CTRL_PLL5P		(2 << 24)
+#define CCM_DE_CTRL_RST			(1 << 30)
+#define CCM_DE_CTRL_GATE		(1 << 31)
+
 #endif /* _SUNXI_CLOCK_SUN4I_H */
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index e16a764..3599054 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -176,13 +176,18 @@
 #define CCM_PLL1_CTRL_MAGIC		(0x1 << 16)
 #define CCM_PLL1_CTRL_EN		(0x1 << 31)
 
+#define CCM_PLL3_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_PLL3_CTRL_N(n)		((((n) - 1) & 0x7f) << 8)
+#define CCM_PLL3_CTRL_INTEGER_MODE	(0x1 << 24)
+#define CCM_PLL3_CTRL_EN		(0x1 << 31)
+
 #define CCM_PLL5_CTRL_M(n)		((((n) - 1) & 0x3) << 0)
 #define CCM_PLL5_CTRL_K(n)		((((n) - 1) & 0x3) << 4)
 #define CCM_PLL5_CTRL_N(n)		((((n) - 1) & 0x1f) << 8)
 #define CCM_PLL5_CTRL_UPD		(0x1 << 20)
 #define CCM_PLL5_CTRL_EN		(0x1 << 31)
 
-#define PLL6_CFG_DEFAULT		0x90041811
+#define PLL6_CFG_DEFAULT		0x90041811 /* 600 MHz */
 
 #define CCM_PLL6_CTRL_N_SHIFT		8
 #define CCM_PLL6_CTRL_N_MASK		(0x1f << CCM_PLL6_CTRL_N_SHIFT)
@@ -193,17 +198,26 @@
 
 #define AXI_GATE_OFFSET_DRAM		0
 
+/* ahb_gate0 offsets */
 #define AHB_GATE_OFFSET_USB_OHCI1	30
 #define AHB_GATE_OFFSET_USB_OHCI0	29
 #define AHB_GATE_OFFSET_USB_EHCI1	27
 #define AHB_GATE_OFFSET_USB_EHCI0	26
 #define AHB_GATE_OFFSET_MCTL		14
+#define AHB_GATE_OFFSET_GMAC		17
 #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))
 
+/* ahb_gate1 offsets */
+#define AHB_GATE_OFFSET_DRC0		25
+#define AHB_GATE_OFFSET_DE_BE0		12
+#define AHB_GATE_OFFSET_HDMI		11
+#define AHB_GATE_OFFSET_LCD1		5
+#define AHB_GATE_OFFSET_LCD0		4
+
 #define CCM_MMC_CTRL_OSCM24 (0x0 << 24)
 #define CCM_MMC_CTRL_PLL6   (0x1 << 24)
 
@@ -216,6 +230,12 @@
 #define CCM_USB_CTRL_PHY1_CLK (0x1 << 9)
 #define CCM_USB_CTRL_PHY2_CLK (0x1 << 10)
 
+#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)
+
 #define MDFS_CLK_DEFAULT		0x81000002 /* PLL6 / 3 */
 
 #define CCM_DRAMCLK_CFG_DIV0(x)		((x - 1) << 8)
@@ -223,8 +243,35 @@
 #define CCM_DRAMCLK_CFG_UPD		(0x1 << 16)
 #define CCM_DRAMCLK_CFG_RST		(0x1 << 31)
 
+#define CCM_DRAM_GATE_OFFSET_DE_BE0	26
+
+#define CCM_LCD_CH0_CTRL_PLL3		(0 << 24)
+#define CCM_LCD_CH0_CTRL_PLL7		(1 << 24)
+#define CCM_LCD_CH0_CTRL_PLL3_2X	(2 << 24)
+#define CCM_LCD_CH0_CTRL_PLL7_2X	(3 << 24)
+#define CCM_LCD_CH0_CTRL_MIPI_PLL	(4 << 24)
+#define CCM_LCD_CH0_CTRL_GATE		(0x1 << 31)
+
+#define CCM_LCD_CH1_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_LCD_CH1_CTRL_PLL3		(0 << 24)
+#define CCM_LCD_CH1_CTRL_PLL7		(1 << 24)
+#define CCM_LCD_CH1_CTRL_PLL3_2X	(2 << 24)
+#define CCM_LCD_CH1_CTRL_PLL7_2X	(3 << 24)
+#define CCM_LCD_CH1_CTRL_GATE		(0x1 << 31)
+
+#define CCM_HDMI_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_HDMI_CTRL_PLL_MASK		(3 << 24)
+#define CCM_HDMI_CTRL_PLL3		(0 << 24)
+#define CCM_HDMI_CTRL_PLL7		(1 << 24)
+#define CCM_HDMI_CTRL_PLL3_2X		(2 << 24)
+#define CCM_HDMI_CTRL_PLL7_2X		(3 << 24)
+#define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
+#define CCM_HDMI_CTRL_GATE		(0x1 << 31)
+
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
 
+/* ahb_reset0 offsets */
+#define AHB_RESET_OFFSET_GMAC		17
 #define AHB_RESET_OFFSET_MCTL		14
 #define AHB_RESET_OFFSET_MMC3		11
 #define AHB_RESET_OFFSET_MMC2		10
@@ -232,10 +279,28 @@
 #define AHB_RESET_OFFSET_MMC0		8
 #define AHB_RESET_OFFSET_MMC(n)		(AHB_RESET_OFFSET_MMC0 + (n))
 
+/* ahb_reset0 offsets */
+#define AHB_RESET_OFFSET_DRC0		25
+#define AHB_RESET_OFFSET_DE_BE0		12
+#define AHB_RESET_OFFSET_HDMI		11
+#define AHB_RESET_OFFSET_LCD1		5
+#define AHB_RESET_OFFSET_LCD0		4
+
 /* apb2 reset */
 #define APB2_RESET_UART_SHIFT		(16)
 #define APB2_RESET_UART_MASK		(0xff << APB2_RESET_UART_SHIFT)
 #define APB2_RESET_TWI_SHIFT		(0)
 #define APB2_RESET_TWI_MASK		(0xf << APB2_RESET_TWI_SHIFT)
 
+/* CCM bits common to all Display Engine (and IEP) clock ctrl regs */
+#define CCM_DE_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_DE_CTRL_PLL_MASK		(0xf << 24)
+#define CCM_DE_CTRL_PLL3		(0 << 24)
+#define CCM_DE_CTRL_PLL7		(1 << 24)
+#define CCM_DE_CTRL_PLL6_2X		(2 << 24)
+#define CCM_DE_CTRL_PLL8		(3 << 24)
+#define CCM_DE_CTRL_PLL9		(4 << 24)
+#define CCM_DE_CTRL_PLL10		(5 << 24)
+#define CCM_DE_CTRL_GATE		(1 << 31)
+
 #endif /* _SUNXI_CLOCK_SUN6I_H */
diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
index bdee89e..2c92b5c 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu.h
@@ -99,9 +99,13 @@
 
 #define SUNXI_SCR_BASE			0x01c2c400
 
+#ifndef CONFIG_MACH_SUN6I
 #define SUNXI_GPS_BASE			0x01c30000
 #define SUNXI_MALI400_BASE		0x01c40000
 #define SUNXI_GMAC_BASE			0x01c50000
+#else
+#define SUNXI_GMAC_BASE			0x01c30000
+#endif
 
 #define SUNXI_DRAM_COM_BASE		0x01c62000
 #define SUNXI_DRAM_CTL0_BASE		0x01c63000
diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h
new file mode 100644
index 0000000..ddb71c1
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/display.h
@@ -0,0 +1,187 @@
+/*
+ * Sunxi platform display controller register and constant defines
+ *
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DISPLAY_H
+#define _SUNXI_DISPLAY_H
+
+struct sunxi_de_be_reg {
+	u8 res0[0x800];			/* 0x000 */
+	u32 mode;			/* 0x800 */
+	u32 backcolor;			/* 0x804 */
+	u32 disp_size;			/* 0x808 */
+	u8 res1[0x4];			/* 0x80c */
+	u32 layer0_size;		/* 0x810 */
+	u32 layer1_size;		/* 0x814 */
+	u32 layer2_size;		/* 0x818 */
+	u32 layer3_size;		/* 0x81c */
+	u32 layer0_pos;			/* 0x820 */
+	u32 layer1_pos;			/* 0x824 */
+	u32 layer2_pos;			/* 0x828 */
+	u32 layer3_pos;			/* 0x82c */
+	u8 res2[0x10];			/* 0x830 */
+	u32 layer0_stride;		/* 0x840 */
+	u32 layer1_stride;		/* 0x844 */
+	u32 layer2_stride;		/* 0x848 */
+	u32 layer3_stride;		/* 0x84c */
+	u32 layer0_addr_low32b;		/* 0x850 */
+	u32 layer1_addr_low32b;		/* 0x854 */
+	u32 layer2_addr_low32b;		/* 0x858 */
+	u32 layer3_addr_low32b;		/* 0x85c */
+	u32 layer0_addr_high4b;		/* 0x860 */
+	u32 layer1_addr_high4b;		/* 0x864 */
+	u32 layer2_addr_high4b;		/* 0x868 */
+	u32 layer3_addr_high4b;		/* 0x86c */
+	u32 reg_ctrl;			/* 0x870 */
+	u8 res3[0xc];			/* 0x874 */
+	u32 color_key_max;		/* 0x880 */
+	u32 color_key_min;		/* 0x884 */
+	u32 color_key_config;		/* 0x888 */
+	u8 res4[0x4];			/* 0x88c */
+	u32 layer0_attr0_ctrl;		/* 0x890 */
+	u32 layer1_attr0_ctrl;		/* 0x894 */
+	u32 layer2_attr0_ctrl;		/* 0x898 */
+	u32 layer3_attr0_ctrl;		/* 0x89c */
+	u32 layer0_attr1_ctrl;		/* 0x8a0 */
+	u32 layer1_attr1_ctrl;		/* 0x8a4 */
+	u32 layer2_attr1_ctrl;		/* 0x8a8 */
+	u32 layer3_attr1_ctrl;		/* 0x8ac */
+};
+
+struct sunxi_lcdc_reg {
+	u32 ctrl;			/* 0x00 */
+	u32 int0;			/* 0x04 */
+	u32 int1;			/* 0x08 */
+	u8 res0[0x04];			/* 0x0c */
+	u32 frame_ctrl;			/* 0x10 */
+	u8 res1[0x2c];			/* 0x14 */
+	u32 tcon0_ctrl;			/* 0x40 */
+	u32 tcon0_dclk;			/* 0x44 */
+	u32 tcon0_basic_timing0;	/* 0x48 */
+	u32 tcon0_basic_timing1;	/* 0x4c */
+	u32 tcon0_basic_timing2;	/* 0x50 */
+	u32 tcon0_basic_timing3;	/* 0x54 */
+	u32 tcon0_hv_intf;		/* 0x58 */
+	u8 res2[0x04];			/* 0x5c */
+	u32 tcon0_cpu_intf;		/* 0x60 */
+	u32 tcon0_cpu_wr_dat;		/* 0x64 */
+	u32 tcon0_cpu_rd_dat0;		/* 0x68 */
+	u32 tcon0_cpu_rd_dat1;		/* 0x6c */
+	u32 tcon0_ttl_timing0;		/* 0x70 */
+	u32 tcon0_ttl_timing1;		/* 0x74 */
+	u32 tcon0_ttl_timing2;		/* 0x78 */
+	u32 tcon0_ttl_timing3;		/* 0x7c */
+	u32 tcon0_ttl_timing4;		/* 0x80 */
+	u32 tcon0_lvds_intf;		/* 0x84 */
+	u32 tcon0_io_polarity;		/* 0x88 */
+	u32 tcon0_io_tristate;		/* 0x8c */
+	u32 tcon1_ctrl;			/* 0x90 */
+	u32 tcon1_timing_source;	/* 0x94 */
+	u32 tcon1_timing_scale;		/* 0x98 */
+	u32 tcon1_timing_out;		/* 0x9c */
+	u32 tcon1_timing_h;		/* 0xa0 */
+	u32 tcon1_timing_v;		/* 0xa4 */
+	u32 tcon1_timing_sync;		/* 0xa8 */
+	u8 res3[0x44];			/* 0xac */
+	u32 tcon1_io_polarity;		/* 0xf0 */
+	u32 tcon1_io_tristate;		/* 0xf4 */
+};
+
+struct sunxi_hdmi_reg {
+	u32 version_id;			/* 0x000 */
+	u32 ctrl;			/* 0x004 */
+	u32 irq;			/* 0x008 */
+	u32 hpd;			/* 0x00c */
+	u32 video_ctrl;			/* 0x010 */
+	u32 video_size;			/* 0x014 */
+	u32 video_bp;			/* 0x018 */
+	u32 video_fp;			/* 0x01c */
+	u32 video_spw;			/* 0x020 */
+	u32 video_polarity;		/* 0x024 */
+	u8 res0[0x1d8];			/* 0x028 */
+	u32 pad_ctrl0;			/* 0x200 */
+	u32 pad_ctrl1;			/* 0x204 */
+	u32 pll_ctrl;			/* 0x208 */
+	u32 pll_dbg0;			/* 0x20c */
+};
+
+/*
+ * DE-BE register constants.
+ */
+#define SUNXI_DE_BE_WIDTH(x)			(((x) - 1) << 0)
+#define SUNXI_DE_BE_HEIGHT(y)			(((y) - 1) << 16)
+#define SUNXI_DE_BE_MODE_ENABLE			(1 << 0)
+#define SUNXI_DE_BE_MODE_START			(1 << 1)
+#define SUNXI_DE_BE_MODE_LAYER0_ENABLE		(1 << 8)
+#define SUNXI_DE_BE_LAYER_STRIDE(x)		((x) << 5)
+#define SUNXI_DE_BE_REG_CTRL_LOAD_REGS		(1 << 0)
+#define SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888	(0x09 << 8)
+
+/*
+ * LCDC register constants.
+ */
+#define SUNXI_LCDC_X(x)				(((x) - 1) << 16)
+#define SUNXI_LCDC_Y(y)				(((y) - 1) << 0)
+#define SUNXI_LCDC_CTRL_IO_MAP_MASK		(1 << 0)
+#define SUNXI_LCDC_CTRL_IO_MAP_TCON0		(0 << 0)
+#define SUNXI_LCDC_CTRL_IO_MAP_TCON1		(1 << 0)
+#define SUNXI_LCDC_CTRL_TCON_ENABLE		(1 << 31)
+#define SUNXI_LCDC_TCON0_DCLK_ENABLE		(0xf << 28)
+#define SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(n)	(((n) & 0x1f) << 4)
+#define SUNXI_LCDC_TCON1_CTRL_ENABLE		(1 << 31)
+#define SUNXI_LCDC_TCON1_TIMING_H_BP(n)		(((n) - 1) << 0)
+#define SUNXI_LCDC_TCON1_TIMING_H_TOTAL(n)	(((n) - 1) << 16)
+#define SUNXI_LCDC_TCON1_TIMING_V_BP(n)		(((n) - 1) << 0)
+#define SUNXI_LCDC_TCON1_TIMING_V_TOTAL(n)	(((n) * 2) << 16)
+
+/*
+ * HDMI register constants.
+ */
+#define SUNXI_HDMI_X(x)				(((x) - 1) << 0)
+#define SUNXI_HDMI_Y(y)				(((y) - 1) << 16)
+#define SUNXI_HDMI_CTRL_ENABLE			(1 << 31)
+#define SUNXI_HDMI_IRQ_STATUS_FIFO_UF		(1 << 0)
+#define SUNXI_HDMI_IRQ_STATUS_FIFO_OF		(1 << 1)
+#define SUNXI_HDMI_IRQ_STATUS_BITS		0x73
+#define SUNXI_HDMI_HPD_DETECT			(1 << 0)
+#define SUNXI_HDMI_VIDEO_CTRL_ENABLE		(1 << 31)
+#define SUNXI_HDMI_VIDEO_POL_HOR		(1 << 0)
+#define SUNXI_HDMI_VIDEO_POL_VER		(1 << 1)
+#define SUNXI_HDMI_VIDEO_POL_TX_CLK		(0x3e0 << 16)
+
+#ifdef CONFIG_MACH_SUN6I
+#define SUNXI_HDMI_PAD_CTRL0_HDP		0x7e80000f
+#define SUNXI_HDMI_PAD_CTRL0_RUN		0x7e8000ff
+#else
+#define SUNXI_HDMI_PAD_CTRL0_HDP		0xfe800000
+#define SUNXI_HDMI_PAD_CTRL0_RUN		0xfe800000
+#endif
+
+#ifdef CONFIG_MACH_SUN4I
+#define SUNXI_HDMI_PAD_CTRL1			0x00d8c820
+#elif defined CONFIG_MACH_SUN6I
+#define SUNXI_HDMI_PAD_CTRL1			0x01ded030
+#else
+#define SUNXI_HDMI_PAD_CTRL1			0x00d8c830
+#endif
+#define SUNXI_HDMI_PAD_CTRL1_HALVE		(1 << 6)
+
+#ifdef CONFIG_MACH_SUN6I
+#define SUNXI_HDMI_PLL_CTRL			0xba48a308
+#define SUNXI_HDMI_PLL_CTRL_DIV(n)		(((n) - 1) << 4)
+#else
+#define SUNXI_HDMI_PLL_CTRL			0xfa4ef708
+#define SUNXI_HDMI_PLL_CTRL_DIV(n)		((n) << 4)
+#endif
+#define SUNXI_HDMI_PLL_CTRL_DIV_MASK		(0xf << 4)
+
+#define SUNXI_HDMI_PLL_DBG0_PLL3		(0 << 21)
+#define SUNXI_HDMI_PLL_DBG0_PLL7		(1 << 21)
+
+int sunxi_simplefb_setup(void *blob);
+
+#endif /* _SUNXI_DISPLAY_H */
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index c734cf0..366c0dc 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -134,6 +134,7 @@
 #define SUNXI_GPIO_OUTPUT	1
 
 #define SUNXI_GPA0_EMAC		2
+#define SUN6I_GPA0_GMAC		2
 #define SUN7I_GPA0_GMAC		5
 
 #define SUNXI_GPB0_TWI0		2
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
index 7555896..246cd9a 100644
--- a/board/sunxi/Kconfig
+++ b/board/sunxi/Kconfig
@@ -24,6 +24,7 @@
 	select CPU_V7_HAS_NONSEC
 	select CPU_V7_HAS_VIRT
 	select SUPPORT_SPL
+	select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
 
 config MACH_SUN8I
 	bool "sun8i (Allwinner A23)"
@@ -215,4 +216,18 @@
 	---help---
 	See USB1_VBUS_PIN help text.
 
+config VIDEO
+	boolean "Enable graphical uboot console on HDMI"
+	default y
+	---help---
+	Say Y here to add support for using a cfb console on the HDMI output
+	found on most sunxi devices.
+
+config USB_KEYBOARD
+	boolean "Enable USB keyboard support"
+	default y
+	---help---
+	Say Y here to add support for using a USB keyboard (typically used
+	in combination with a graphical console on HDMI).
+
 endif
diff --git a/board/sunxi/ahci.c b/board/sunxi/ahci.c
index 5e12328..b7f0dda 100644
--- a/board/sunxi/ahci.c
+++ b/board/sunxi/ahci.c
@@ -76,6 +76,8 @@
 #ifdef CONFIG_SATAPWR
 	gpio_request(CONFIG_SATAPWR, "satapwr");
 	gpio_direction_output(CONFIG_SATAPWR, 1);
+	/* Give attached sata device time to power-up to avoid link timeouts */
+	mdelay(500);
 #endif
 
 	if (sunxi_ahci_phy_init(SUNXI_SATA_BASE) < 0)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index e6ec5b8..4c1c69a 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -24,6 +24,7 @@
 #endif
 #include <asm/arch/clock.h>
 #include <asm/arch/cpu.h>
+#include <asm/arch/display.h>
 #include <asm/arch/dram.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
@@ -237,3 +238,12 @@
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_OF_BOARD_SETUP
+int ft_board_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_VIDEO_DT_SIMPLEFB
+	return sunxi_simplefb_setup(blob);
+#endif
+}
+#endif /* CONFIG_OF_BOARD_SETUP */
diff --git a/board/sunxi/gmac.c b/board/sunxi/gmac.c
index 051aca0..571bc9e 100644
--- a/board/sunxi/gmac.c
+++ b/board/sunxi/gmac.c
@@ -13,7 +13,12 @@
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
 	/* Set up clock gating */
+#ifndef CONFIG_MACH_SUN6I
 	setbits_le32(&ccm->ahb_gate1, 0x1 << AHB_GATE_OFFSET_GMAC);
+#else
+	setbits_le32(&ccm->ahb_reset0_cfg, 0x1 << AHB_RESET_OFFSET_GMAC);
+	setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_GMAC);
+#endif
 
 	/* Set MII clock */
 #ifdef CONFIG_RGMII
@@ -33,6 +38,7 @@
 	setbits_le32(&ccm->gmac_clk_cfg, 0x3 << 10);
 #endif
 
+#ifndef CONFIG_MACH_SUN6I
 	/* Configure pin mux settings for GMAC */
 	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(16); pin++) {
 #ifdef CONFIG_RGMII
@@ -43,9 +49,48 @@
 		sunxi_gpio_set_cfgpin(pin, SUN7I_GPA0_GMAC);
 		sunxi_gpio_set_drv(pin, 3);
 	}
+#elif defined CONFIG_RGMII
+	/* Configure sun6i RGMII mode pin mux settings */
+	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(3); pin++) {
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 3);
+	}
+	for (pin = SUNXI_GPA(9); pin <= SUNXI_GPA(14); pin++) {
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 3);
+	}
+	for (pin = SUNXI_GPA(19); pin <= SUNXI_GPA(20); pin++) {
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 3);
+	}
+	for (pin = SUNXI_GPA(25); pin <= SUNXI_GPA(27); pin++) {
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 3);
+	}
+#elif defined CONFIG_GMII
+	/* Configure sun6i GMII mode pin mux settings */
+	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(27); pin++) {
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+		sunxi_gpio_set_drv(pin, 2);
+	}
+#else
+	/* Configure sun6i MII mode pin mux settings */
+	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(3); pin++)
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+	for (pin = SUNXI_GPA(8); pin <= SUNXI_GPA(9); pin++)
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+	for (pin = SUNXI_GPA(11); pin <= SUNXI_GPA(14); pin++)
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+	for (pin = SUNXI_GPA(19); pin <= SUNXI_GPA(24); pin++)
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+	for (pin = SUNXI_GPA(26); pin <= SUNXI_GPA(27); pin++)
+		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA0_GMAC);
+#endif
 
 #ifdef CONFIG_RGMII
 	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_RGMII);
+#elif defined CONFIG_GMII
+	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_GMII);
 #else
 	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_MII);
 #endif
diff --git a/common/fdt_support.c b/common/fdt_support.c
index ce32fe7..ea42c63 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1499,3 +1499,65 @@
 
 	return 0;
 }
+
+/**
+ * fdt_setup_simplefb_node - Fill and enable a simplefb node
+ *
+ * @fdt: ptr to device tree
+ * @node: offset of the simplefb node
+ * @base_address: framebuffer base address
+ * @width: width in pixels
+ * @height: height in pixels
+ * @stride: bytes per line
+ * @format: pixel format string
+ *
+ * Convenience function to fill and enable a simplefb node.
+ */
+int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
+			    u32 height, u32 stride, const char *format)
+{
+	char name[32];
+	fdt32_t cells[4];
+	int i, addrc, sizec, ret;
+
+	of_bus_default_count_cells(fdt, fdt_parent_offset(fdt, node),
+				   &addrc, &sizec);
+	i = 0;
+	if (addrc == 2)
+		cells[i++] = cpu_to_fdt32(base_address >> 32);
+	cells[i++] = cpu_to_fdt32(base_address);
+	if (sizec == 2)
+		cells[i++] = 0;
+	cells[i++] = cpu_to_fdt32(height * stride);
+
+	ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i);
+	if (ret < 0)
+		return ret;
+
+	snprintf(name, sizeof(name), "framebuffer@%llx", base_address);
+	ret = fdt_set_name(fdt, node, name);
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop_u32(fdt, node, "width", width);
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop_u32(fdt, node, "height", height);
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop_u32(fdt, node, "stride", stride);
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop_string(fdt, node, "format", format);
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop_string(fdt, node, "status", "okay");
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
diff --git a/common/lcd.c b/common/lcd.c
index d8e1371..28b3fe7 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -30,6 +30,7 @@
 #include <splash.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
+#include <fdt_support.h>
 
 #if defined(CONFIG_CPU_PXA25X) || defined(CONFIG_CPU_PXA27X) || \
 	defined(CONFIG_CPU_MONAHANS)
@@ -1172,51 +1173,13 @@
 #if defined(CONFIG_LCD_DT_SIMPLEFB)
 static int lcd_dt_simplefb_configure_node(void *blob, int off)
 {
-	u32 stride;
-	fdt32_t cells[2];
-	int ret;
-	static const char format[] =
 #if LCD_BPP == LCD_COLOR16
-		"r5g6b5";
+	return fdt_setup_simplefb_node(blob, off, gd->fb_base,
+				       panel_info.vl_col, panel_info.vl_row,
+				       panel_info.vl_col * 2, "r5g6b5");
 #else
-		"";
+	return -1;
 #endif
-
-	if (!format[0])
-		return -1;
-
-	stride = panel_info.vl_col * 2;
-
-	cells[0] = cpu_to_fdt32(gd->fb_base);
-	cells[1] = cpu_to_fdt32(stride * panel_info.vl_row);
-	ret = fdt_setprop(blob, off, "reg", cells, sizeof(cells[0]) * 2);
-	if (ret < 0)
-		return -1;
-
-	cells[0] = cpu_to_fdt32(panel_info.vl_col);
-	ret = fdt_setprop(blob, off, "width", cells, sizeof(cells[0]));
-	if (ret < 0)
-		return -1;
-
-	cells[0] = cpu_to_fdt32(panel_info.vl_row);
-	ret = fdt_setprop(blob, off, "height", cells, sizeof(cells[0]));
-	if (ret < 0)
-		return -1;
-
-	cells[0] = cpu_to_fdt32(stride);
-	ret = fdt_setprop(blob, off, "stride", cells, sizeof(cells[0]));
-	if (ret < 0)
-		return -1;
-
-	ret = fdt_setprop(blob, off, "format", format, strlen(format) + 1);
-	if (ret < 0)
-		return -1;
-
-	ret = fdt_delprop(blob, off, "status");
-	if (ret < 0)
-		return -1;
-
-	return 0;
 }
 
 int lcd_dt_simplefb_add_node(void *blob)
diff --git a/configs/A13-OLinuXinoM_defconfig b/configs/A13-OLinuXinoM_defconfig
index 8517203..be8652b 100644
--- a/configs/A13-OLinuXinoM_defconfig
+++ b/configs/A13-OLinuXinoM_defconfig
@@ -2,6 +2,8 @@
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,USB_EHCI"
 CONFIG_FDTFILE="sun5i-a13-olinuxino-micro.dtb"
 CONFIG_USB1_VBUS_PIN="PG11"
+CONFIG_VIDEO=n
+CONFIG_USB_KEYBOARD=n
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
 +S:CONFIG_MACH_SUN5I=y
diff --git a/configs/A13-OLinuXino_defconfig b/configs/A13-OLinuXino_defconfig
index 61f5466..654e12a 100644
--- a/configs/A13-OLinuXino_defconfig
+++ b/configs/A13-OLinuXino_defconfig
@@ -2,6 +2,8 @@
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,AXP209_POWER,USB_EHCI"
 CONFIG_FDTFILE="sun5i-a13-olinuxino.dtb"
 CONFIG_USB1_VBUS_PIN="PG11"
+CONFIG_VIDEO=n
+CONFIG_USB_KEYBOARD=n
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
 +S:CONFIG_MACH_SUN5I=y
diff --git a/configs/Colombus_defconfig b/configs/Colombus_defconfig
index bef568d..de78a01 100644
--- a/configs/Colombus_defconfig
+++ b/configs/Colombus_defconfig
@@ -1,5 +1,6 @@
 CONFIG_SPL=y
 CONFIG_FDTFILE="sun6i-a31-colombus.dtb"
+CONFIG_USB_KEYBOARD=n
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
 +S:CONFIG_MACH_SUN6I=y
diff --git a/configs/Ippo_q8h_v5_defconfig b/configs/Ippo_q8h_v5_defconfig
index fc67bd9..50c2f93 100644
--- a/configs/Ippo_q8h_v5_defconfig
+++ b/configs/Ippo_q8h_v5_defconfig
@@ -4,3 +4,5 @@
 CONFIG_MACH_SUN8I=y
 CONFIG_TARGET_IPPO_Q8H_V5=y
 CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_VIDEO=n
+CONFIG_USB_KEYBOARD=n
diff --git a/configs/Mele_M9_defconfig b/configs/Mele_M9_defconfig
index f46439f..ac3cd36 100644
--- a/configs/Mele_M9_defconfig
+++ b/configs/Mele_M9_defconfig
@@ -1,5 +1,5 @@
 CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="USB_EHCI"
+CONFIG_SYS_EXTRA_OPTIONS="USB_EHCI,SUNXI_GMAC"
 CONFIG_FDTFILE="sun6i-a31-m9.dtb"
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
@@ -14,5 +14,7 @@
 # HDMI power ?
 +S:CONFIG_AXP221_ALDO2_VOLT=1800
 +S:CONFIG_AXP221_ALDO3_VOLT=3000
-# No Vbus gpio for usb1
-+S:CONFIG_USB1_VBUS_PIN=""
+# Vbus gpio for usb1
++S:CONFIG_USB1_VBUS_PIN="PC27"
+# No Vbus gpio for usb2
++S:CONFIG_USB2_VBUS_PIN=""
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 14a6781..7301be3 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -39,6 +39,7 @@
 obj-$(CONFIG_VIDEO_SED13806) += sed13806.o
 obj-$(CONFIG_VIDEO_SM501) += sm501.o
 obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
+obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o
 obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
 obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
 obj-$(CONFIG_FORMIKE) += formike.o
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
new file mode 100644
index 0000000..d241397
--- /dev/null
+++ b/drivers/video/sunxi_display.c
@@ -0,0 +1,451 @@
+/*
+ * Display driver for Allwinner SoCs.
+ *
+ * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/display.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <linux/fb.h>
+#include <video_fb.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sunxi_display {
+	GraphicDevice graphic_device;
+	bool enabled;
+} sunxi_display;
+
+static int sunxi_hdmi_hpd_detect(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct sunxi_hdmi_reg * const hdmi =
+		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+
+	/* Set pll3 to 300MHz */
+	clock_set_pll3(300000000);
+
+	/* Set hdmi parent to pll3 */
+	clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
+			CCM_HDMI_CTRL_PLL3);
+
+	/* Set ahb gating to pass */
+#ifdef CONFIG_MACH_SUN6I
+	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
+#endif
+	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
+
+	/* Clock on */
+	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
+
+	writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
+	writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
+
+	udelay(1000);
+
+	if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
+		return 1;
+
+	/* No need to keep these running */
+	clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
+	clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
+	clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
+#ifdef CONFIG_MACH_SUN6I
+	clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
+#endif
+	clock_set_pll3(0);
+
+	return 0;
+}
+
+/*
+ * This is the entity that mixes and matches the different layers and inputs.
+ * Allwinner calls it the back-end, but i like composer better.
+ */
+static void sunxi_composer_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct sunxi_de_be_reg * const de_be =
+		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+	int i;
+
+#ifdef CONFIG_MACH_SUN6I
+	/* Reset off */
+	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
+#endif
+
+	/* Clocks on */
+	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
+	setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
+	clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
+
+	/* Engine bug, clear registers after reset */
+	for (i = 0x0800; i < 0x1000; i += 4)
+		writel(0, SUNXI_DE_BE0_BASE + i);
+
+	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
+}
+
+static void sunxi_composer_mode_set(struct fb_videomode *mode,
+				    unsigned int address)
+{
+	struct sunxi_de_be_reg * const de_be =
+		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+
+	writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
+	       &de_be->disp_size);
+	writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
+	       &de_be->layer0_size);
+	writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
+	writel(address << 3, &de_be->layer0_addr_low32b);
+	writel(address >> 29, &de_be->layer0_addr_high4b);
+	writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
+
+	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
+}
+
+/*
+ * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
+ */
+static void sunxi_lcdc_pll_set(int dotclock, int *clk_div, int *clk_double)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	int value, n, m, diff;
+	int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
+	int best_double = 0;
+
+	/*
+	 * Find the lowest divider resulting in a matching clock, if there
+	 * is no match, pick the closest lower clock, as monitors tend to
+	 * not sync to higher frequencies.
+	 */
+	for (m = 15; m > 0; m--) {
+		n = (m * dotclock) / 3000;
+
+		if ((n >= 9) && (n <= 127)) {
+			value = (3000 * n) / m;
+			diff = dotclock - value;
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 0;
+			}
+		}
+
+		/* These are just duplicates */
+		if (!(m & 1))
+			continue;
+
+		n = (m * dotclock) / 6000;
+		if ((n >= 9) && (n <= 127)) {
+			value = (6000 * n) / m;
+			diff = dotclock - value;
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 1;
+			}
+		}
+	}
+
+	debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
+	      dotclock, (best_double + 1) * 3000 * best_n / best_m,
+	      best_double + 1, best_n, best_m);
+
+	clock_set_pll3(best_n * 3000000);
+
+	writel(CCM_LCD_CH1_CTRL_GATE |
+	    (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X : CCM_LCD_CH1_CTRL_PLL3) |
+	    CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
+
+	*clk_div = best_m;
+	*clk_double = best_double;
+}
+
+static void sunxi_lcdc_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct sunxi_lcdc_reg * const lcdc =
+		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+
+	/* Reset off */
+#ifdef CONFIG_MACH_SUN6I
+	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
+#else
+	setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
+#endif
+
+	/* Clock on */
+	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
+
+	/* Init lcdc */
+	writel(0, &lcdc->ctrl); /* Disable tcon */
+	writel(0, &lcdc->int0); /* Disable all interrupts */
+
+	/* Disable tcon0 dot clock */
+	clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
+
+	/* Set all io lines to tristate */
+	writel(0xffffffff, &lcdc->tcon0_io_tristate);
+	writel(0xffffffff, &lcdc->tcon1_io_tristate);
+}
+
+static void sunxi_lcdc_mode_set(struct fb_videomode *mode,
+				int *clk_div, int *clk_double)
+{
+	struct sunxi_lcdc_reg * const lcdc =
+		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+	int bp, total;
+
+	/* Use tcon1 */
+	clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
+			SUNXI_LCDC_CTRL_IO_MAP_TCON1);
+
+	/* Enabled, 0x1e start delay */
+	writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
+	       SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(0x1e), &lcdc->tcon1_ctrl);
+
+	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+	       &lcdc->tcon1_timing_source);
+	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+	       &lcdc->tcon1_timing_scale);
+	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+	       &lcdc->tcon1_timing_out);
+
+	bp = mode->hsync_len + mode->left_margin;
+	total = mode->xres + mode->right_margin + bp;
+	writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
+	       SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
+
+	bp = mode->vsync_len + mode->upper_margin;
+	total = mode->yres + mode->lower_margin + bp;
+	writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
+	       SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
+
+	writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
+	       &lcdc->tcon1_timing_sync);
+
+	sunxi_lcdc_pll_set(mode->pixclock, clk_div, clk_double);
+}
+
+#ifdef CONFIG_MACH_SUN6I
+static void sunxi_drc_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* On sun6i the drc must be clocked even when in pass-through mode */
+	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
+	clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
+}
+#endif
+
+static void sunxi_hdmi_mode_set(struct fb_videomode *mode,
+				int clk_div, int clk_double)
+{
+	struct sunxi_hdmi_reg * const hdmi =
+		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+	int x, y;
+
+	/* Write clear interrupt status bits */
+	writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
+
+	/* Init various registers, select pll3 as clock source */
+	writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
+	writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
+	writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
+	writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
+	writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
+
+	/* Setup clk div and doubler */
+	clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
+			SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
+	if (!clk_double)
+		setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
+
+	/* Setup timing registers */
+	writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
+	       &hdmi->video_size);
+
+	x = mode->hsync_len + mode->left_margin;
+	y = mode->vsync_len + mode->upper_margin;
+	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
+
+	x = mode->right_margin;
+	y = mode->lower_margin;
+	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
+
+	x = mode->hsync_len;
+	y = mode->vsync_len;
+	writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
+
+	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
+
+	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
+}
+
+static void sunxi_engines_init(void)
+{
+	sunxi_composer_init();
+	sunxi_lcdc_init();
+#ifdef CONFIG_MACH_SUN6I
+	sunxi_drc_init();
+#endif
+}
+
+static void sunxi_mode_set(struct fb_videomode *mode, unsigned int address)
+{
+	struct sunxi_de_be_reg * const de_be =
+		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+	struct sunxi_lcdc_reg * const lcdc =
+		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+	struct sunxi_hdmi_reg * const hdmi =
+		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+	int clk_div, clk_double;
+	int retries = 3;
+
+retry:
+	clrbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
+	clrbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
+	clrbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
+
+	sunxi_composer_mode_set(mode, address);
+	sunxi_lcdc_mode_set(mode, &clk_div, &clk_double);
+	sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+
+	setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
+	setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
+
+	udelay(1000000 / mode->refresh + 500);
+
+	setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
+
+	udelay(1000000 / mode->refresh + 500);
+
+	setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
+
+	udelay(1000000 / mode->refresh + 500);
+
+	/*
+	 * Sometimes the display pipeline does not sync up properly, if
+	 * this happens the hdmi fifo underrun or overrun bits are set.
+	 */
+	if (readl(&hdmi->irq) &
+	    (SUNXI_HDMI_IRQ_STATUS_FIFO_UF | SUNXI_HDMI_IRQ_STATUS_FIFO_OF)) {
+		if (retries--)
+			goto retry;
+		printf("HDMI fifo under or overrun\n");
+	}
+}
+
+void *video_hw_init(void)
+{
+	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	/*
+	 * Vesa standard 1024x768@60
+	 * 65.0  1024 1048 1184 1344  768 771 777 806  -hsync -vsync
+	 */
+	struct fb_videomode mode = {
+		.name = "1024x768",
+		.refresh = 60,
+		.xres = 1024,
+		.yres = 768,
+		.pixclock = 65000,
+		.left_margin = 160,
+		.right_margin = 24,
+		.upper_margin = 29,
+		.lower_margin = 3,
+		.hsync_len = 136,
+		.vsync_len = 6,
+		.sync = 0,
+		.vmode = 0,
+		.flag = 0,
+	};
+	int ret;
+
+	memset(&sunxi_display, 0, sizeof(struct sunxi_display));
+
+	printf("Reserved %dkB of RAM for Framebuffer.\n",
+	       CONFIG_SUNXI_FB_SIZE >> 10);
+	gd->fb_base = gd->ram_top;
+
+	ret = sunxi_hdmi_hpd_detect();
+	if (!ret)
+		return NULL;
+
+	printf("HDMI connected.\n");
+	sunxi_display.enabled = true;
+
+	printf("Setting up a %s console.\n", mode.name);
+	sunxi_engines_init();
+	sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
+
+	/*
+	 * These are the only members of this structure that are used. All the
+	 * others are driver specific. There is nothing to decribe pitch or
+	 * stride, but we are lucky with our hw.
+	 */
+	graphic_device->frameAdrs = gd->fb_base;
+	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
+	graphic_device->gdfBytesPP = 4;
+	graphic_device->winSizeX = mode.xres;
+	graphic_device->winSizeY = mode.yres;
+
+	return graphic_device;
+}
+
+/*
+ * Simplefb support.
+ */
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
+int sunxi_simplefb_setup(void *blob)
+{
+	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	int offset, ret;
+
+	if (!sunxi_display.enabled)
+		return 0;
+
+	/* Find a framebuffer node, with pipeline == "de_be0-lcd0-hdmi" */
+	offset = fdt_node_offset_by_compatible(blob, -1,
+					       "allwinner,simple-framebuffer");
+	while (offset >= 0) {
+		ret = fdt_find_string(blob, offset, "allwinner,pipeline",
+				      "de_be0-lcd0-hdmi");
+		if (ret == 0)
+			break;
+		offset = fdt_node_offset_by_compatible(blob, offset,
+					       "allwinner,simple-framebuffer");
+	}
+	if (offset < 0) {
+		eprintf("Cannot setup simplefb: node not found\n");
+		return 0; /* Keep older kernels working */
+	}
+
+	ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
+			graphic_device->winSizeX, graphic_device->winSizeY,
+			graphic_device->winSizeX * graphic_device->gdfBytesPP,
+			"x8r8g8b8");
+	if (ret)
+		eprintf("Cannot setup simplefb: Error setting properties\n");
+
+	return ret;
+}
+#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
index 3629587..f6b1b3e 100644
--- a/include/configs/sun7i.h
+++ b/include/configs/sun7i.h
@@ -23,7 +23,6 @@
 #endif
 
 #define CONFIG_ARMV7_PSCI		1
-#define CONFIG_ARMV7_PSCI_NR_CPUS	2
 #define CONFIG_ARMV7_SECURE_BASE	SUNXI_SRAM_B_BASE
 #define CONFIG_SYS_CLK_FREQ		24000000
 
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index ce038ed..3f890b2 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -197,6 +197,36 @@
 #define CONFIG_SPL_GPIO_SUPPORT
 #define CONFIG_CMD_GPIO
 
+#ifdef CONFIG_VIDEO
+/*
+ * The amount of RAM that is reserved for the FB. This will not show up as
+ * RAM to the kernel, but will be reclaimed by a KMS driver in future.
+ */
+#define CONFIG_SUNXI_FB_SIZE (8 << 20)
+
+/* Do we want to initialize a simple FB? */
+#define CONFIG_VIDEO_DT_SIMPLEFB
+
+#define CONFIG_VIDEO_SUNXI
+
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_VIDEO_SW_CURSOR
+#define CONFIG_VIDEO_LOGO
+
+/* allow both serial and cfb console. */
+#define CONFIG_CONSOLE_MUX
+/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+
+#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF)
+
+/* To be able to hook simplefb into dt */
+#ifdef CONFIG_VIDEO_DT_SIMPLEFB
+#define CONFIG_OF_BOARD_SETUP
+#endif
+
+#endif /* CONFIG_VIDEO */
+
 /* Ethernet support */
 #ifdef CONFIG_SUNXI_EMAC
 #define CONFIG_MII			/* MII PHY management		*/
@@ -217,6 +247,13 @@
 #define CONFIG_USB_STORAGE
 #endif
 
+#ifdef CONFIG_USB_KEYBOARD
+#define CONFIG_CONSOLE_MUX
+#define CONFIG_PREBOOT
+#define CONFIG_SYS_STDIO_DEREGISTER
+#define CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
+#endif
+
 #if !defined CONFIG_ENV_IS_IN_MMC && \
     !defined CONFIG_ENV_IS_IN_NAND && \
     !defined CONFIG_ENV_IS_IN_FAT && \
@@ -225,6 +262,7 @@
 #endif
 
 #define CONFIG_MISC_INIT_R
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
 
 #ifndef CONFIG_SPL_BUILD
 #include <config_distro_defaults.h>
@@ -266,7 +304,31 @@
 
 #include <config_distro_bootcmd.h>
 
+#ifdef CONFIG_USB_KEYBOARD
+#define CONSOLE_STDIN_SETTINGS \
+	"preboot=usb start\0" \
+	"stdin=serial,usbkbd\0"
+#else
+#define CONSOLE_STDIN_SETTINGS \
+	"stdin=serial\0"
+#endif
+
+#ifdef CONFIG_VIDEO
+#define CONSOLE_STDOUT_SETTINGS \
+	"stdout=serial,vga\0" \
+	"stderr=serial,vga\0"
+#else
+#define CONSOLE_STDOUT_SETTINGS \
+	"stdout=serial\0" \
+	"stderr=serial\0"
+#endif
+
+#define CONSOLE_ENV_SETTINGS \
+	CONSOLE_STDIN_SETTINGS \
+	CONSOLE_STDOUT_SETTINGS
+
 #define CONFIG_EXTRA_ENV_SETTINGS \
+	CONSOLE_ENV_SETTINGS \
 	MEM_LAYOUT_ENV_SETTINGS \
 	"fdtfile=" CONFIG_FDTFILE "\0" \
 	"console=ttyS0,115200\0" \
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 0fbc9bd..1f19fe4 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -172,6 +172,9 @@
 int ft_verify_fdt(void *fdt);
 int arch_fixup_memory_node(void *blob);
 
+int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
+			    u32 height, u32 stride, const char *format);
+
 #endif /* ifdef CONFIG_OF_LIBFDT */
 
 #ifdef USE_HOSTCC