Merge branch 'master' of http://git.denx.de/u-boot-mmc
diff --git a/Kconfig b/Kconfig
index 1fa791c..3f79f6f 100644
--- a/Kconfig
+++ b/Kconfig
@@ -57,6 +57,7 @@
 	bool "Select defaults suitable for booting general purpose Linux distributions"
 	default y if ARCH_SUNXI || TEGRA
 	default y if ARCH_LS2080A
+	default y if ARCH_ROCKCHIP
 	default n
 	select CMD_BOOTZ if ARM && !ARM64
 	select CMD_BOOTI if ARM64
diff --git a/arch/arm/dts/rk3288-popmetal.dtsi b/arch/arm/dts/rk3288-popmetal.dtsi
index f3bd468..e5be4cb 100644
--- a/arch/arm/dts/rk3288-popmetal.dtsi
+++ b/arch/arm/dts/rk3288-popmetal.dtsi
@@ -145,6 +145,18 @@
 		regulator-always-on;
 		vin-supply = <&vcc_io>;
 	};
+
+	vcc5v0_host: usb-host-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&host_vbus_drv>;
+		regulator-name = "vcc5v0_host";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
 };
 
 &cpu0 {
@@ -471,6 +483,12 @@
 			rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
+
+	usb_host {
+		host_vbus_drv: host-vbus-drv {
+			rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
 };
 
 &tsadc {
@@ -515,6 +533,11 @@
 	status = "okay";
 };
 
+&usb_host1 {
+	vbus-supply = <&vcc5v0_host>;
+	status = "okay";
+};
+
 &usbphy {
 	status = "okay";
 };
diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi
index 179860c..22277ff 100644
--- a/arch/arm/dts/rk3399.dtsi
+++ b/arch/arm/dts/rk3399.dtsi
@@ -188,6 +188,7 @@
 		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
 		assigned-clocks = <&cru SCLK_EMMC>;
 		assigned-clock-rates = <200000000>;
+		max-frequency = <200000000>;
 		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
 		clock-names = "clk_xin", "clk_ahb";
 		phys = <&emmc_phy>;
diff --git a/arch/arm/include/asm/arch-rockchip/qos_rk3288.h b/arch/arm/include/asm/arch-rockchip/qos_rk3288.h
new file mode 100644
index 0000000..b3094fc
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/qos_rk3288.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Rockchip Inc.
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+#ifndef _ASM_ARCH_QOS_RK3288_H
+#define _ASM_ARCH_QOS_RK3288_H
+
+#define PRIORITY_HIGH_SHIFT	2
+#define PRIORITY_LOW_SHIFT	0
+
+#define CPU_AXI_QOS_PRIORITY    0x08
+
+#define VIO0_VOP_QOS            0xffad0400
+#define VIO1_VOP_QOS            0xffad0000
+#define VIO1_ISP_R_QOS          0xffad0900
+#define VIO1_ISP_W0_QOS         0xffad0100
+#define VIO1_ISP_W1_QOS         0xffad0180
+
+#endif
diff --git a/arch/arm/mach-rockchip/rk3288-board.c b/arch/arm/mach-rockchip/rk3288-board.c
index bca6075..8bf45f7 100644
--- a/arch/arm/mach-rockchip/rk3288-board.c
+++ b/arch/arm/mach-rockchip/rk3288-board.c
@@ -13,6 +13,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/periph.h>
 #include <asm/arch/pmu_rk3288.h>
+#include <asm/arch/qos_rk3288.h>
 #include <asm/arch/boot_mode.h>
 #include <asm/gpio.h>
 #include <dm/pinctrl.h>
@@ -51,9 +52,28 @@
 	return 0;
 }
 
+int rk3288_qos_init(void)
+{
+	int val = 2 << PRIORITY_HIGH_SHIFT | 2 << PRIORITY_LOW_SHIFT;
+	/* set vop qos to higher priority */
+	writel(val, CPU_AXI_QOS_PRIORITY + VIO0_VOP_QOS);
+	writel(val, CPU_AXI_QOS_PRIORITY + VIO1_VOP_QOS);
+
+	if (!fdt_node_check_compatible(gd->fdt_blob, 0,
+				       "rockchip,rk3288-miniarm"))
+	{
+		/* set isp qos to higher priority */
+		writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_R_QOS);
+		writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_W0_QOS);
+		writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_W1_QOS);
+	}
+	return 0;
+}
+
 int board_late_init(void)
 {
 	setup_boot_mode();
+	rk3288_qos_init();
 
 	return rk_board_late_init();
 }
diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig
index 223ae41..54545f3 100644
--- a/arch/arm/mach-rockchip/rk3288/Kconfig
+++ b/arch/arm/mach-rockchip/rk3288/Kconfig
@@ -61,7 +61,7 @@
 config TARGET_CHROMEBOOK_MINNIE
 	bool "Google/Rockchip Veyron-Minnie Chromebook"
 	help
-	  Jerry is a RK3288-based convertible clamshell device with 2 USB 3.0
+	  Minnie is a RK3288-based convertible clamshell device with 2 USB 3.0
 	  ports, micro HDMI, a 10.1-inch 1280x800 EDP display, micro-SD card,
 	  HD camera, touchpad, WiFi and Bluetooth. It includes a Chrome OS
 	  EC (Cortex-M3) to provide access to the keyboard and battery
diff --git a/arch/arm/mach-rockchip/rk3399/clk_rk3399.c b/arch/arm/mach-rockchip/rk3399/clk_rk3399.c
index 7663591..ce706a6 100644
--- a/arch/arm/mach-rockchip/rk3399/clk_rk3399.c
+++ b/arch/arm/mach-rockchip/rk3399/clk_rk3399.c
@@ -11,10 +11,10 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/cru_rk3399.h>
 
-int rockchip_get_clk(struct udevice **devp)
+static int rockchip_get_cruclk(struct udevice **devp)
 {
 	return uclass_get_device_by_driver(UCLASS_CLK,
-			DM_GET_DRIVER(rockchip_rk3399_pmuclk), devp);
+			DM_GET_DRIVER(clk_rk3399), devp);
 }
 
 void *rockchip_get_cru(void)
@@ -23,7 +23,7 @@
 	struct udevice *dev;
 	int ret;
 
-	ret = rockchip_get_clk(&dev);
+	ret = rockchip_get_cruclk(&dev);
 	if (ret)
 		return ERR_PTR(ret);
 
diff --git a/board/chipspark/popmetal_rk3288/popmetal-rk3288.c b/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
index aad74ef..ed82b2b 100644
--- a/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
+++ b/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <spl.h>
+#include <asm/gpio.h>
 
 void board_boot_order(u32 *spl_boot_list)
 {
@@ -13,3 +14,19 @@
 	spl_boot_list[0] = BOOT_DEVICE_MMC2;
 	spl_boot_list[1] = BOOT_DEVICE_MMC1;
 }
+
+#define GPIO7A3_HUB_RST	227
+
+int rk_board_late_init(void)
+{
+	int ret;
+
+	ret = gpio_request(GPIO7A3_HUB_RST, "hub_rst");
+	if (ret)
+		return ret;
+	ret = gpio_direction_output(GPIO7A3_HUB_RST, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/cmd/mem.c b/cmd/mem.c
index a690957..ff6a770 100644
--- a/cmd/mem.c
+++ b/cmd/mem.c
@@ -372,10 +372,8 @@
 
 static int do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	ulong	addr, dest, count, bytes;
+	ulong	addr, dest, count;
 	int	size;
-	const void *src;
-	void *buf;
 
 	if (argc != 4)
 		return CMD_RET_USAGE;
@@ -465,29 +463,7 @@
 	}
 #endif
 
-	bytes = size * count;
-	buf = map_sysmem(dest, bytes);
-	src = map_sysmem(addr, bytes);
-	while (count-- > 0) {
-		if (size == 4)
-			*((u32 *)buf) = *((u32  *)src);
-#ifdef CONFIG_SYS_SUPPORT_64BIT_DATA
-		else if (size == 8)
-			*((u64 *)buf) = *((u64 *)src);
-#endif
-		else if (size == 2)
-			*((u16 *)buf) = *((u16 *)src);
-		else
-			*((u8 *)buf) = *((u8 *)src);
-		src += size;
-		buf += size;
-
-		/* reset watchdog from time to time */
-		if ((count % (64 << 10)) == 0)
-			WATCHDOG_RESET();
-	}
-	unmap_sysmem(buf);
-	unmap_sysmem(src);
+	memcpy((void *)dest, (void *)addr, count * size);
 
 	return 0;
 }
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig
index 6988bcb..02d91a7 100644
--- a/configs/evb-rk3399_defconfig
+++ b/configs/evb-rk3399_defconfig
@@ -11,6 +11,9 @@
 CONFIG_CMD_SF=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig
index eb78d54..3ed17b4 100644
--- a/configs/firefly-rk3288_defconfig
+++ b/configs/firefly-rk3288_defconfig
@@ -45,6 +45,10 @@
 CONFIG_LED_GPIO=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_DM_ETH=y
+CONFIG_NETDEVICES=y
+CONFIG_ETH_DESIGNWARE=y
+CONFIG_GMAC_ROCKCHIP=y
 CONFIG_PINCTRL=y
 CONFIG_SPL_PINCTRL=y
 # CONFIG_SPL_PINCTRL_FULL is not set
diff --git a/configs/popmetal-rk3288_defconfig b/configs/popmetal-rk3288_defconfig
index a123b84..c4bf33a 100644
--- a/configs/popmetal-rk3288_defconfig
+++ b/configs/popmetal-rk3288_defconfig
@@ -64,3 +64,6 @@
 CONFIG_USE_TINY_PRINTF=y
 CONFIG_CMD_DHRYSTONE=y
 CONFIG_ERRNO_STR=y
+CONFIG_CMD_USB=y
+CONFIG_USB=y
+CONFIG_USB_STORAGE=y
diff --git a/configs/rock2_defconfig b/configs/rock2_defconfig
index a3b0c87..488c6f4 100644
--- a/configs/rock2_defconfig
+++ b/configs/rock2_defconfig
@@ -32,6 +32,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent"
+CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_REGMAP=y
 CONFIG_SPL_REGMAP=y
 CONFIG_SYSCON=y
@@ -43,6 +44,10 @@
 CONFIG_SYS_I2C_ROCKCHIP=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_DM_ETH=y
+CONFIG_NETDEVICES=y
+CONFIG_ETH_DESIGNWARE=y
+CONFIG_GMAC_ROCKCHIP=y
 CONFIG_PINCTRL=y
 CONFIG_SPL_PINCTRL=y
 # CONFIG_SPL_PINCTRL_FULL is not set
diff --git a/doc/README.rockchip b/doc/README.rockchip
index 06ec80e..43cafc7 100644
--- a/doc/README.rockchip
+++ b/doc/README.rockchip
@@ -219,7 +219,6 @@
 - USB host
 - USB device
 - Run CPU at full speed (code exists but we only see ~60 DMIPS maximum)
-- Ethernet
 - NAND flash
 - Support for other Rockchip parts
 - Boot U-Boot proper over USB OTG (at present only SPL works)
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index c56e1a3..e33e35e 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -12,7 +12,9 @@
 #include <libfdt.h>
 #include <malloc.h>
 #include <sdhci.h>
+#include <clk.h>
 
+DECLARE_GLOBAL_DATA_PTR;
 /* 400KHz is max freq for card ID etc. Use that as min */
 #define EMMC_MIN_FREQ	400000
 
@@ -32,11 +34,24 @@
 	struct rockchip_sdhc_plat *plat = dev_get_platdata(dev);
 	struct rockchip_sdhc *prv = dev_get_priv(dev);
 	struct sdhci_host *host = &prv->host;
-	int ret;
+	int max_frequency, ret;
+	struct clk clk;
+
+
+	max_frequency = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+			"max-frequency", 0);
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (!ret) {
+		ret = clk_set_rate(&clk, max_frequency);
+		if (IS_ERR_VALUE(ret))
+			printf("%s clk set rate fail!\n", __func__);
+	} else {
+		printf("%s fail to get clk\n", __func__);
+	}
 
 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, CONFIG_ROCKCHIP_SDHCI_MAX_FREQ,
+	ret = sdhci_setup_cfg(&plat->cfg, host, max_frequency,
 			EMMC_MIN_FREQ);
 
 	host->mmc = &plat->mmc;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 929b9e2..f52629f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -215,4 +215,11 @@
 	  This driver implements 10/100 Mbps Ethernet and MAC layer for
 	  Microchip PIC32 microcontrollers.
 
+config GMAC_ROCKCHIP
+	bool "Rockchip Synopsys Designware Ethernet MAC"
+	depends on DM_ETH && ETH_DESIGNWARE
+	help
+	  This driver provides Rockchip SoCs network support based on the
+	  Synopsys Designware driver.
+
 endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 9a7bfc6..2493a48 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_FTMAC110) += ftmac110.o
 obj-$(CONFIG_FTMAC100) += ftmac100.o
 obj-$(CONFIG_GRETH) += greth.o
+obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o
 obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
 obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 obj-$(CONFIG_LAN91C96) += lan91c96.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 9e6d726..f242fc6 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -230,14 +230,14 @@
 	return 0;
 }
 
-static void dw_adjust_link(struct eth_mac_regs *mac_p,
-			   struct phy_device *phydev)
+static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p,
+			  struct phy_device *phydev)
 {
 	u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
 
 	if (!phydev->link) {
 		printf("%s: No link.\n", phydev->dev->name);
-		return;
+		return 0;
 	}
 
 	if (phydev->speed != 1000)
@@ -256,6 +256,8 @@
 	printf("Speed: %d, %s duplex%s\n", phydev->speed,
 	       (phydev->duplex) ? "full" : "half",
 	       (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
+
+	return 0;
 }
 
 static void _dw_eth_halt(struct dw_eth_dev *priv)
@@ -269,7 +271,7 @@
 	phy_shutdown(priv->phydev);
 }
 
-static int _dw_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
+int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
 {
 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -321,7 +323,16 @@
 		return ret;
 	}
 
+	ret = dw_adjust_link(priv, mac_p, priv->phydev);
+	if (ret)
+		return ret;
+
-	dw_adjust_link(mac_p, priv->phydev);
+	return 0;
+}
+
+int designware_eth_enable(struct dw_eth_dev *priv)
+{
+	struct eth_mac_regs *mac_p = priv->mac_regs_p;
 
 	if (!priv->phydev->link)
 		return -EIO;
@@ -480,7 +491,13 @@
 #ifndef CONFIG_DM_ETH
 static int dw_eth_init(struct eth_device *dev, bd_t *bis)
 {
-	return _dw_eth_init(dev->priv, dev->enetaddr);
+	int ret;
+
+	ret = designware_eth_init(dev->priv, dev->enetaddr);
+	if (!ret)
+		ret = designware_eth_enable(dev->priv);
+
+	return ret;
 }
 
 static int dw_eth_send(struct eth_device *dev, void *packet, int length)
@@ -571,40 +588,48 @@
 static int designware_eth_start(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct dw_eth_dev *priv = dev_get_priv(dev);
+	int ret;
 
-	return _dw_eth_init(dev->priv, pdata->enetaddr);
+	ret = designware_eth_init(priv, pdata->enetaddr);
+	if (ret)
+		return ret;
+	ret = designware_eth_enable(priv);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
-static int designware_eth_send(struct udevice *dev, void *packet, int length)
+int designware_eth_send(struct udevice *dev, void *packet, int length)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
 	return _dw_eth_send(priv, packet, length);
 }
 
-static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
 	return _dw_eth_recv(priv, packetp);
 }
 
-static int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
-				   int length)
+int designware_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
 	return _dw_free_pkt(priv);
 }
 
-static void designware_eth_stop(struct udevice *dev)
+void designware_eth_stop(struct udevice *dev)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
 	return _dw_eth_halt(priv);
 }
 
-static int designware_eth_write_hwaddr(struct udevice *dev)
+int designware_eth_write_hwaddr(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct dw_eth_dev *priv = dev_get_priv(dev);
@@ -628,7 +653,7 @@
 	return 0;
 }
 
-static int designware_eth_probe(struct udevice *dev)
+int designware_eth_probe(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct dw_eth_dev *priv = dev_get_priv(dev);
@@ -678,7 +703,7 @@
 	return 0;
 }
 
-static const struct eth_ops designware_eth_ops = {
+const struct eth_ops designware_eth_ops = {
 	.start			= designware_eth_start,
 	.send			= designware_eth_send,
 	.recv			= designware_eth_recv,
@@ -687,7 +712,7 @@
 	.write_hwaddr		= designware_eth_write_hwaddr,
 };
 
-static int designware_eth_ofdata_to_platdata(struct udevice *dev)
+int designware_eth_ofdata_to_platdata(struct udevice *dev)
 {
 	struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
 #ifdef CONFIG_DM_GPIO
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index d345c5b..7992d0e 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -245,10 +245,23 @@
 };
 
 #ifdef CONFIG_DM_ETH
+int designware_eth_ofdata_to_platdata(struct udevice *dev);
+int designware_eth_probe(struct udevice *dev);
+extern const struct eth_ops designware_eth_ops;
+
 struct dw_eth_pdata {
 	struct eth_pdata eth_pdata;
 	u32 reset_delays[3];
 };
+
+int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr);
+int designware_eth_enable(struct dw_eth_dev *priv);
+int designware_eth_send(struct udevice *dev, void *packet, int length);
+int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp);
+int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
+				   int length);
+void designware_eth_stop(struct udevice *dev);
+int designware_eth_write_hwaddr(struct udevice *dev);
 #endif
 
 #endif
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
new file mode 100644
index 0000000..5f833fa
--- /dev/null
+++ b/drivers/net/gmac_rockchip.c
@@ -0,0 +1,154 @@
+/*
+ * (C) Copyright 2015 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Rockchip GMAC ethernet IP driver for U-Boot
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <phy.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/periph.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/grf_rk3288.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/clock/rk3288-cru.h>
+#include "designware.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Platform data for the gmac
+ *
+ * dw_eth_pdata: Required platform data for designware driver (must be first)
+ */
+struct gmac_rockchip_platdata {
+	struct dw_eth_pdata dw_eth_pdata;
+	int tx_delay;
+	int rx_delay;
+};
+
+static int gmac_rockchip_ofdata_to_platdata(struct udevice *dev)
+{
+	struct gmac_rockchip_platdata *pdata = dev_get_platdata(dev);
+
+	pdata->tx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					 "tx-delay", 0x30);
+	pdata->rx_delay = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					 "rx-delay", 0x10);
+
+	return designware_eth_ofdata_to_platdata(dev);
+}
+
+static int gmac_rockchip_fix_mac_speed(struct dw_eth_dev *priv)
+{
+	struct rk3288_grf *grf;
+	int clk;
+
+	switch (priv->phydev->speed) {
+	case 10:
+		clk = GMAC_CLK_SEL_2_5M;
+		break;
+	case 100:
+		clk = GMAC_CLK_SEL_25M;
+		break;
+	case 1000:
+		clk = GMAC_CLK_SEL_125M;
+		break;
+	default:
+		debug("Unknown phy speed: %d\n", priv->phydev->speed);
+		return -EINVAL;
+	}
+
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	rk_clrsetreg(&grf->soc_con1,
+		     GMAC_CLK_SEL_MASK << GMAC_CLK_SEL_SHIFT,
+		     clk << GMAC_CLK_SEL_SHIFT);
+
+	return 0;
+}
+
+static int gmac_rockchip_probe(struct udevice *dev)
+{
+	struct gmac_rockchip_platdata *pdata = dev_get_platdata(dev);
+	struct rk3288_grf *grf;
+	struct clk clk;
+	int ret;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	/* Since mac_clk is fed by an external clock we can use 0 here */
+	ret = clk_set_rate(&clk, 0);
+	if (ret)
+		return ret;
+
+	/* Set to RGMII mode */
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	rk_clrsetreg(&grf->soc_con1,
+		     RMII_MODE_MASK << RMII_MODE_SHIFT |
+		     GMAC_PHY_INTF_SEL_MASK << GMAC_PHY_INTF_SEL_SHIFT,
+		     GMAC_PHY_INTF_SEL_RGMII << GMAC_PHY_INTF_SEL_SHIFT);
+
+	rk_clrsetreg(&grf->soc_con3,
+		     RXCLK_DLY_ENA_GMAC_MASK <<  RXCLK_DLY_ENA_GMAC_SHIFT |
+		     TXCLK_DLY_ENA_GMAC_MASK <<  TXCLK_DLY_ENA_GMAC_SHIFT |
+		     CLK_RX_DL_CFG_GMAC_MASK <<  CLK_RX_DL_CFG_GMAC_SHIFT |
+		     CLK_TX_DL_CFG_GMAC_MASK <<  CLK_TX_DL_CFG_GMAC_SHIFT,
+		     RXCLK_DLY_ENA_GMAC_ENABLE << RXCLK_DLY_ENA_GMAC_SHIFT |
+		     TXCLK_DLY_ENA_GMAC_ENABLE << TXCLK_DLY_ENA_GMAC_SHIFT |
+		     pdata->rx_delay << CLK_RX_DL_CFG_GMAC_SHIFT |
+		     pdata->tx_delay << CLK_TX_DL_CFG_GMAC_SHIFT);
+
+	return designware_eth_probe(dev);
+}
+
+static int gmac_rockchip_eth_start(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct dw_eth_dev *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = designware_eth_init(priv, pdata->enetaddr);
+	if (ret)
+		return ret;
+	ret = gmac_rockchip_fix_mac_speed(priv);
+	if (ret)
+		return ret;
+	ret = designware_eth_enable(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+const struct eth_ops gmac_rockchip_eth_ops = {
+	.start			= gmac_rockchip_eth_start,
+	.send			= designware_eth_send,
+	.recv			= designware_eth_recv,
+	.free_pkt		= designware_eth_free_pkt,
+	.stop			= designware_eth_stop,
+	.write_hwaddr		= designware_eth_write_hwaddr,
+};
+
+static const struct udevice_id rockchip_gmac_ids[] = {
+	{ .compatible = "rockchip,rk3288-gmac" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_gmac_rockchip) = {
+	.name	= "gmac_rockchip",
+	.id	= UCLASS_ETH,
+	.of_match = rockchip_gmac_ids,
+	.ofdata_to_platdata = gmac_rockchip_ofdata_to_platdata,
+	.probe	= gmac_rockchip_probe,
+	.ops	= &gmac_rockchip_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct dw_eth_dev),
+	.platdata_auto_alloc_size = sizeof(struct gmac_rockchip_platdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c
index 032b1de..1a4fa36 100644
--- a/drivers/video/rockchip/rk_hdmi.c
+++ b/drivers/video/rockchip/rk_hdmi.c
@@ -85,13 +85,13 @@
 
 static const struct hdmi_phy_config rockchip_phy_config[] = {
 	{
-		.mpixelclock = 74250,
+		.mpixelclock = 74250000,
 		.sym_ctr = 0x8009, .term = 0x0004, .vlev_ctr = 0x0272,
 	}, {
-		.mpixelclock = 148500,
+		.mpixelclock = 148500000,
 		.sym_ctr = 0x802b, .term = 0x0004, .vlev_ctr = 0x028d,
 	}, {
-		.mpixelclock = 297000,
+		.mpixelclock = 297000000,
 		.sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d,
 	}, {
 		.mpixelclock = ~0ul,
@@ -101,22 +101,22 @@
 
 static const struct hdmi_mpll_config rockchip_mpll_cfg[] = {
 	{
-		.mpixelclock = 40000,
+		.mpixelclock = 40000000,
 		.cpce = 0x00b3, .gmp = 0x0000, .curr = 0x0018,
 	}, {
-		.mpixelclock = 65000,
+		.mpixelclock = 65000000,
 		.cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028,
 	}, {
-		.mpixelclock = 66000,
+		.mpixelclock = 66000000,
 		.cpce = 0x013e, .gmp = 0x0003, .curr = 0x0038,
 	}, {
-		.mpixelclock = 83500,
+		.mpixelclock = 835000000,
 		.cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028,
 	}, {
-		.mpixelclock = 146250,
+		.mpixelclock = 146250000,
 		.cpce = 0x0051, .gmp = 0x0002, .curr = 0x0038,
 	}, {
-		.mpixelclock = 148500,
+		.mpixelclock = 148500000,
 		.cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000,
 	}, {
 		.mpixelclock = ~0ul,
@@ -870,7 +870,7 @@
 		clk_free(&clk);
 	}
 	if (ret) {
-		debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
+		debug("%s: Failed to set hdmi clock: ret=%d\n", __func__, ret);
 		return ret;
 	}
 
diff --git a/include/configs/evb_rk3288.h b/include/configs/evb_rk3288.h
index 77b647e..554ca0e 100644
--- a/include/configs/evb_rk3288.h
+++ b/include/configs/evb_rk3288.h
@@ -12,11 +12,20 @@
 
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV 1
+
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* SPL @ 32k for 34k
+ * u-boot directly after @ 68k for 400k or so
+ * ENV @ 992k
+ */
+#define CONFIG_ENV_OFFSET ((1024-32) * 1024)
+#else
 /* SPL @ 32k for ~36k
  * ENV @ 96k
  * u-boot @ 128K
  */
 #define CONFIG_ENV_OFFSET (96 * 1024)
+#endif
 
 #define CONFIG_SYS_WHITE_ON_BLACK
 
diff --git a/include/configs/fennec_rk3288.h b/include/configs/fennec_rk3288.h
index 77b647e..554ca0e 100644
--- a/include/configs/fennec_rk3288.h
+++ b/include/configs/fennec_rk3288.h
@@ -12,11 +12,20 @@
 
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV 1
+
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* SPL @ 32k for 34k
+ * u-boot directly after @ 68k for 400k or so
+ * ENV @ 992k
+ */
+#define CONFIG_ENV_OFFSET ((1024-32) * 1024)
+#else
 /* SPL @ 32k for ~36k
  * ENV @ 96k
  * u-boot @ 128K
  */
 #define CONFIG_ENV_OFFSET (96 * 1024)
+#endif
 
 #define CONFIG_SYS_WHITE_ON_BLACK
 
diff --git a/include/configs/kylin_rk3036.h b/include/configs/kylin_rk3036.h
index 4f0bd84..bc28525 100644
--- a/include/configs/kylin_rk3036.h
+++ b/include/configs/kylin_rk3036.h
@@ -19,9 +19,20 @@
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV		0 /* emmc */
 #define CONFIG_SYS_MMC_ENV_PART		0 /* user area */
-#define CONFIG_ENV_OFFSET		(SZ_4M - SZ_64K) /* reserved area */
-#define CONFIG_ENV_OFFSET_REDUND	(CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
-#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* SPL @ 32k for 34k
+ * u-boot directly after @ 68k for 400k or so
+ * ENV @ 992k
+ */
+#define CONFIG_ENV_OFFSET ((1024-32) * 1024)
+#else
+/* SPL @ 32k for ~36k
+ * ENV @ 96k
+ * u-boot @ 128K
+ */
+#define CONFIG_ENV_OFFSET (96 * 1024)
+#endif
 
 #endif
 
diff --git a/include/configs/miniarm_rk3288.h b/include/configs/miniarm_rk3288.h
index 9451365..5a623ca 100644
--- a/include/configs/miniarm_rk3288.h
+++ b/include/configs/miniarm_rk3288.h
@@ -17,11 +17,20 @@
 
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV 0
+
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* SPL @ 32k for 34k
+ * u-boot directly after @ 68k for 400k or so
+ * ENV @ 992k
+ */
+#define CONFIG_ENV_OFFSET ((1024-32) * 1024)
+#else
 /* SPL @ 32k for ~36k
  * ENV @ 96k
  * u-boot @ 128K
  */
 #define CONFIG_ENV_OFFSET (96 * 1024)
+#endif
 
 #define CONFIG_SYS_WHITE_ON_BLACK
 
diff --git a/include/configs/popmetal_rk3288.h b/include/configs/popmetal_rk3288.h
index 77b647e..554ca0e 100644
--- a/include/configs/popmetal_rk3288.h
+++ b/include/configs/popmetal_rk3288.h
@@ -12,11 +12,20 @@
 
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV 1
+
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* SPL @ 32k for 34k
+ * u-boot directly after @ 68k for 400k or so
+ * ENV @ 992k
+ */
+#define CONFIG_ENV_OFFSET ((1024-32) * 1024)
+#else
 /* SPL @ 32k for ~36k
  * ENV @ 96k
  * u-boot @ 128K
  */
 #define CONFIG_ENV_OFFSET (96 * 1024)
+#endif
 
 #define CONFIG_SYS_WHITE_ON_BLACK
 
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h
index a9995ee..33b1f0e 100644
--- a/include/configs/rk3288_common.h
+++ b/include/configs/rk3288_common.h
@@ -87,6 +87,13 @@
 #define CONFIG_G_DNL_VENDOR_NUM		0x2207
 #define CONFIG_G_DNL_PRODUCT_NUM	0x320a
 
+/* usb host support */
+#ifdef CONFIG_CMD_USB
+#define CONFIG_USB_DWC2
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_USB_ETHER_ASIX
+#endif
 #define ENV_MEM_LAYOUT_SETTINGS \
 	"scriptaddr=0x00000000\0" \
 	"pxefile_addr_r=0x00100000\0" \
diff --git a/include/configs/rockchip-common.h b/include/configs/rockchip-common.h
index 9ec71c4..be53e65 100644
--- a/include/configs/rockchip-common.h
+++ b/include/configs/rockchip-common.h
@@ -14,7 +14,9 @@
 /* First try to boot from SD (index 0), then eMMC (index 1 */
 #define BOOT_TARGET_DEVICES(func) \
 	func(MMC, mmc, 0) \
-	func(MMC, mmc, 1)
+	func(MMC, mmc, 1) \
+	func(PXE, pxe, na) \
+	func(DHCP, dchp, na)
 
  /* Enable gpt partition table */
 #define CONFIG_CMD_GPT