Merge branch 'master' of http://git.denx.de/u-boot-sunxi
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index c948df8..f5217fb 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -9,6 +9,7 @@
 	aliases {
 		console = &uart0;
 		eth0 = "/eth@10002000";
+		eth3 = &eth_3;
 		eth5 = &eth_5;
 		i2c0 = "/i2c@0";
 		pci0 = &pci;
@@ -121,6 +122,12 @@
 		fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;
 	};
 
+	eth_3: sbe5 {
+		compatible = "sandbox,eth";
+		reg = <0x10005000 0x1000>;
+		fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x33>;
+	};
+
 	eth@10004000 {
 		compatible = "sandbox,eth";
 		reg = <0x10004000 0x1000>;
diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c
index 0e9f15f..845f86a 100644
--- a/arch/x86/cpu/coreboot/coreboot.c
+++ b/arch/x86/cpu/coreboot/coreboot.c
@@ -8,7 +8,6 @@
 
 #include <common.h>
 #include <fdtdec.h>
-#include <netdev.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/mtrr.h>
@@ -48,11 +47,6 @@
 	return 0;
 }
 
-int board_eth_init(bd_t *bis)
-{
-	return pci_eth_init(bis);
-}
-
 void board_final_cleanup(void)
 {
 	/*
diff --git a/arch/x86/cpu/quark/Makefile b/arch/x86/cpu/quark/Makefile
index e87b424..8f1d018 100644
--- a/arch/x86/cpu/quark/Makefile
+++ b/arch/x86/cpu/quark/Makefile
@@ -6,4 +6,3 @@
 
 obj-y += car.o dram.o msg_port.o quark.o
 obj-y += mrc.o mrc_util.o hte.o smc.o
-obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/x86/cpu/quark/msg_port.c b/arch/x86/cpu/quark/msg_port.c
index 31713e3..cf828f2 100644
--- a/arch/x86/cpu/quark/msg_port.c
+++ b/arch/x86/cpu/quark/msg_port.c
@@ -5,34 +5,34 @@
  */
 
 #include <common.h>
-#include <pci.h>
 #include <asm/arch/device.h>
 #include <asm/arch/msg_port.h>
+#include <asm/arch/quark.h>
 
 void msg_port_setup(int op, int port, int reg)
 {
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_REG,
-			       (((op) << 24) | ((port) << 16) |
-			       (((reg) << 8) & 0xff00) | MSG_BYTE_ENABLE));
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_REG,
+				   (((op) << 24) | ((port) << 16) |
+				   (((reg) << 8) & 0xff00) | MSG_BYTE_ENABLE));
 }
 
 u32 msg_port_read(u8 port, u32 reg)
 {
 	u32 value;
 
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_READ, port, reg);
-	pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
+	qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
 
 	return value;
 }
 
 void msg_port_write(u8 port, u32 reg, u32 value)
 {
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_WRITE, port, reg);
 }
 
@@ -40,19 +40,19 @@
 {
 	u32 value;
 
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_ALT_READ, port, reg);
-	pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
+	qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
 
 	return value;
 }
 
 void msg_port_alt_write(u8 port, u32 reg, u32 value)
 {
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_ALT_WRITE, port, reg);
 }
 
@@ -60,18 +60,18 @@
 {
 	u32 value;
 
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_IO_READ, port, reg);
-	pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
+	qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
 
 	return value;
 }
 
 void msg_port_io_write(u8 port, u32 reg, u32 value)
 {
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
-	pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
-			       reg & 0xffffff00);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
+	qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
+				   reg & 0xffffff00);
 	msg_port_setup(MSG_OP_IO_WRITE, port, reg);
 }
diff --git a/arch/x86/cpu/quark/pci.c b/arch/x86/cpu/quark/pci.c
deleted file mode 100644
index 354e15a..0000000
--- a/arch/x86/cpu/quark/pci.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-#include <pci.h>
-#include <asm/pci.h>
-#include <asm/arch/device.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-void board_pci_setup_hose(struct pci_controller *hose)
-{
-	hose->first_busno = 0;
-	hose->last_busno = 0;
-
-	/* PCI memory space */
-	pci_set_region(hose->regions + 0,
-		       CONFIG_PCI_MEM_BUS,
-		       CONFIG_PCI_MEM_PHYS,
-		       CONFIG_PCI_MEM_SIZE,
-		       PCI_REGION_MEM);
-
-	/* PCI IO space */
-	pci_set_region(hose->regions + 1,
-		       CONFIG_PCI_IO_BUS,
-		       CONFIG_PCI_IO_PHYS,
-		       CONFIG_PCI_IO_SIZE,
-		       PCI_REGION_IO);
-
-	pci_set_region(hose->regions + 2,
-		       CONFIG_PCI_PREF_BUS,
-		       CONFIG_PCI_PREF_PHYS,
-		       CONFIG_PCI_PREF_SIZE,
-		       PCI_REGION_PREFETCH);
-
-	pci_set_region(hose->regions + 3,
-		       0,
-		       0,
-		       gd->ram_size,
-		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
-	hose->region_count = 4;
-}
-
-int board_pci_post_scan(struct pci_controller *hose)
-{
-	return 0;
-}
-
-int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
-{
-	/*
-	 * TODO:
-	 *
-	 * For some unknown reason, the PCI enumeration process hangs
-	 * when it scans to the PCIe root port 0 (D23:F0) & 1 (D23:F1).
-	 *
-	 * For now we just skip these two devices, and this needs to
-	 * be revisited later.
-	 */
-	if (dev == QUARK_HOST_BRIDGE ||
-	    dev == QUARK_PCIE0 || dev == QUARK_PCIE1) {
-		return 1;
-	}
-
-	return 0;
-}
diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c
index 12ac376..637c370 100644
--- a/arch/x86/cpu/quark/quark.c
+++ b/arch/x86/cpu/quark/quark.c
@@ -31,32 +31,32 @@
 {
 	u32 bc;
 
-	bc = x86_pci_read_config32(QUARK_LEGACY_BRIDGE, 0xd8);
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, 0xd8, &bc);
 	bc |= 0x1;	/* unprotect the flash */
-	x86_pci_write_config32(QUARK_LEGACY_BRIDGE, 0xd8, bc);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, 0xd8, bc);
 }
 
 static void quark_setup_bars(void)
 {
 	/* GPIO - D31:F0:R44h */
-	pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GBA,
-			       CONFIG_GPIO_BASE | IO_BAR_EN);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GBA,
+				   CONFIG_GPIO_BASE | IO_BAR_EN);
 
 	/* ACPI PM1 Block - D31:F0:R48h */
-	pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_PM1BLK,
-			       CONFIG_ACPI_PM1_BASE | IO_BAR_EN);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_PM1BLK,
+				   CONFIG_ACPI_PM1_BASE | IO_BAR_EN);
 
 	/* GPE0 - D31:F0:R4Ch */
-	pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GPE0BLK,
-			       CONFIG_ACPI_GPE0_BASE | IO_BAR_EN);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GPE0BLK,
+				   CONFIG_ACPI_GPE0_BASE | IO_BAR_EN);
 
 	/* WDT - D31:F0:R84h */
-	pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_WDTBA,
-			       CONFIG_WDT_BASE | IO_BAR_EN);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_WDTBA,
+				   CONFIG_WDT_BASE | IO_BAR_EN);
 
 	/* RCBA - D31:F0:RF0h */
-	pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA,
-			       CONFIG_RCBA_BASE | MEM_BAR_EN);
+	qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA,
+				   CONFIG_RCBA_BASE | MEM_BAR_EN);
 
 	/* ACPI P Block - Msg Port 04:R70h */
 	msg_port_write(MSG_PORT_RMU, PBLK_BA,
@@ -73,6 +73,96 @@
 		       CONFIG_PCIE_ECAM_BASE | MEM_BAR_EN);
 }
 
+static void quark_pcie_early_init(void)
+{
+	u32 pcie_cfg;
+
+	/*
+	 * Step1: Assert PCIe signal PERST#
+	 *
+	 * The CPU interface to the PERST# signal is platform dependent.
+	 * Call the board-specific codes to perform this task.
+	 */
+	board_assert_perst();
+
+	/* Step2: PHY common lane reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_PHY_LANE_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 1 ms for PHY common lane reset */
+	mdelay(1);
+
+	/* Step3: PHY sideband interface reset and controller main reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= (PCIE_PHY_SB_RST | PCIE_CTLR_MAIN_RST);
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 80ms for PLL to lock */
+	mdelay(80);
+
+	/* Step4: Controller sideband interface reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_CTLR_SB_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 20ms for controller sideband interface reset */
+	mdelay(20);
+
+	/* Step5: De-assert PERST# */
+	board_deassert_perst();
+
+	/* Step6: Controller primary interface reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_CTLR_PRI_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+
+	/* Mixer Load Lane 0 */
+	pcie_cfg = msg_port_io_read(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L0);
+	pcie_cfg &= ~((1 << 6) | (1 << 7));
+	msg_port_io_write(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L0, pcie_cfg);
+
+	/* Mixer Load Lane 1 */
+	pcie_cfg = msg_port_io_read(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L1);
+	pcie_cfg &= ~((1 << 6) | (1 << 7));
+	msg_port_io_write(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L1, pcie_cfg);
+}
+
+static void quark_usb_early_init(void)
+{
+	u32 usb;
+
+	/* The sequence below comes from Quark firmware writer guide */
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_GLOBAL_PORT);
+	usb &= ~(1 << 1);
+	usb |= ((1 << 6) | (1 << 7));
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_GLOBAL_PORT, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_COMPBG);
+	usb &= ~((1 << 8) | (1 << 9));
+	usb |= ((1 << 7) | (1 << 10));
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_COMPBG, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_PLL2);
+	usb |= (1 << 29);
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_PLL2, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_PLL1);
+	usb |= (1 << 1);
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_PLL1, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_PLL1);
+	usb &= ~((1 << 3) | (1 << 4) | (1 << 5));
+	usb |= (1 << 6);
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_PLL1, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_PLL2);
+	usb &= ~(1 << 29);
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_PLL2, usb);
+
+	usb = msg_port_alt_read(MSG_PORT_USB_AFE, USB2_PLL2);
+	usb |= (1 << 24);
+	msg_port_alt_write(MSG_PORT_USB_AFE, USB2_PLL2, usb);
+}
+
 static void quark_enable_legacy_seg(void)
 {
 	u32 hmisc2;
@@ -84,7 +174,6 @@
 
 int arch_cpu_init(void)
 {
-	struct pci_controller *hose;
 	int ret;
 
 	post_code(POST_CPU_INIT);
@@ -96,16 +185,26 @@
 	if (ret)
 		return ret;
 
-	ret = pci_early_init_hose(&hose);
-	if (ret)
-		return ret;
-
 	/*
 	 * Quark SoC has some non-standard BARs (excluding PCI standard BARs)
 	 * which need be initialized with suggested values
 	 */
 	quark_setup_bars();
 
+	/*
+	 * Initialize PCIe controller
+	 *
+	 * Quark SoC holds the PCIe controller in reset following a power on.
+	 * U-Boot needs to release the PCIe controller from reset. The PCIe
+	 * controller (D23:F0/F1) will not be visible in PCI configuration
+	 * space and any access to its PCI configuration registers will cause
+	 * system hang while it is held in reset.
+	 */
+	quark_pcie_early_init();
+
+	/* Initialize USB2 PHY */
+	quark_usb_early_init();
+
 	/* Turn on legacy segments (A/B/E/F) decode to system RAM */
 	quark_enable_legacy_seg();
 
@@ -137,10 +236,10 @@
 	u32 base;
 	int ret0, ret1;
 
-	pci_read_config_dword(QUARK_EMAC0, PCI_BASE_ADDRESS_0, &base);
+	qrk_pci_read_config_dword(QUARK_EMAC0, PCI_BASE_ADDRESS_0, &base);
 	ret0 = designware_initialize(base, PHY_INTERFACE_MODE_RMII);
 
-	pci_read_config_dword(QUARK_EMAC1, PCI_BASE_ADDRESS_0, &base);
+	qrk_pci_read_config_dword(QUARK_EMAC1, PCI_BASE_ADDRESS_0, &base);
 	ret1 = designware_initialize(base, PHY_INTERFACE_MODE_RMII);
 
 	if (ret0 < 0 && ret1 < 0)
@@ -154,7 +253,7 @@
 	struct quark_rcba *rcba;
 	u32 base;
 
-	base = x86_pci_read_config32(QUARK_LEGACY_BRIDGE, LB_RCBA);
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA, &base);
 	base &= ~MEM_BAR_EN;
 	rcba = (struct quark_rcba *)base;
 
diff --git a/arch/x86/dts/chromebox_panther.dts b/arch/x86/dts/chromebox_panther.dts
index 36feb96..c60ab71 100644
--- a/arch/x86/dts/chromebox_panther.dts
+++ b/arch/x86/dts/chromebox_panther.dts
@@ -42,6 +42,16 @@
 		stdout-path = "/serial";
 	};
 
+	pci {
+		compatible = "pci-x86";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		u-boot,dm-pre-reloc;
+		ranges = <0x02000000 0x0 0xe0000000 0xe0000000 0 0x10000000
+			0x42000000 0x0 0xd0000000 0xd0000000 0 0x10000000
+			0x01000000 0x0 0x1000 0x1000 0 0xf000>;
+	};
+
 	spi {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/x86/dts/galileo.dts b/arch/x86/dts/galileo.dts
index d77ff8a..f119bf7 100644
--- a/arch/x86/dts/galileo.dts
+++ b/arch/x86/dts/galileo.dts
@@ -54,8 +54,11 @@
 	pci {
 		#address-cells = <3>;
 		#size-cells = <2>;
-		compatible = "intel,pci";
-		device_type = "pci";
+		compatible = "pci-x86";
+		u-boot,dm-pre-reloc;
+		ranges = <0x02000000 0x0 0x90000000 0x90000000 0 0x20000000
+			  0x42000000 0x0 0xb0000000 0xb0000000 0 0x20000000
+			  0x01000000 0x0 0x2000 0x2000 0 0xe000>;
 
 		pciuart0: uart@14,5 {
 			compatible = "pci8086,0936.00",
@@ -63,6 +66,7 @@
 					"pciclass,070002",
 					"pciclass,0700",
 					"x86-uart";
+			u-boot,dm-pre-reloc;
 			reg = <0x0000a500 0x0 0x0 0x0 0x0
 			       0x0200a510 0x0 0x0 0x0 0x0>;
 			reg-shift = <2>;
diff --git a/arch/x86/include/asm/arch-quark/quark.h b/arch/x86/include/asm/arch-quark/quark.h
index c997928..5d81976 100644
--- a/arch/x86/include/asm/arch-quark/quark.h
+++ b/arch/x86/include/asm/arch-quark/quark.h
@@ -12,6 +12,8 @@
 #define MSG_PORT_HOST_BRIDGE	0x03
 #define MSG_PORT_RMU		0x04
 #define MSG_PORT_MEM_MGR	0x05
+#define MSG_PORT_USB_AFE	0x14
+#define MSG_PORT_PCIE_AFE	0x16
 #define MSG_PORT_SOC_UNIT	0x31
 
 /* Port 0x00: Memory Arbiter Message Port Registers */
@@ -48,6 +50,28 @@
 #define ESRAM_BLK_CTRL		0x82
 #define ESRAM_BLOCK_MODE	0x10000000
 
+/* Port 0x14: USB2 AFE Unit Port Registers */
+
+#define USB2_GLOBAL_PORT	0x4001
+#define USB2_PLL1		0x7f02
+#define USB2_PLL2		0x7f03
+#define USB2_COMPBG		0x7f04
+
+/* Port 0x16: PCIe AFE Unit Port Registers */
+
+#define PCIE_RXPICTRL0_L0	0x2080
+#define PCIE_RXPICTRL0_L1	0x2180
+
+/* Port 0x31: SoC Unit Port Registers */
+
+/* PCIe Controller Config */
+#define PCIE_CFG		0x36
+#define PCIE_CTLR_PRI_RST	0x00010000
+#define PCIE_PHY_SB_RST		0x00020000
+#define PCIE_CTLR_SB_RST	0x00040000
+#define PCIE_PHY_LANE_RST	0x00090000
+#define PCIE_CTLR_MAIN_RST	0x00100000
+
 /* DRAM */
 #define DRAM_BASE		0x00000000
 #define DRAM_MAX_SIZE		0x80000000
@@ -89,6 +113,67 @@
 	u16	d20d21_ir;
 };
 
+#include <asm/io.h>
+#include <asm/pci.h>
+
+/**
+ * qrk_pci_read_config_dword() - Read a configuration value
+ *
+ * @dev:	PCI device address: bus, device and function
+ * @offset:	Dword offset within the device's configuration space
+ * @valuep:	Place to put the returned value
+ *
+ * Note: This routine is inlined to provide better performance on Quark
+ */
+static inline void qrk_pci_read_config_dword(pci_dev_t dev, int offset,
+					     u32 *valuep)
+{
+	outl(dev | offset | PCI_CFG_EN, PCI_REG_ADDR);
+	*valuep = inl(PCI_REG_DATA);
+}
+
+/**
+ * qrk_pci_write_config_dword() - Write a PCI configuration value
+ *
+ * @dev:	PCI device address: bus, device and function
+ * @offset:	Dword offset within the device's configuration space
+ * @value:	Value to write
+ *
+ * Note: This routine is inlined to provide better performance on Quark
+ */
+static inline void qrk_pci_write_config_dword(pci_dev_t dev, int offset,
+					      u32 value)
+{
+	outl(dev | offset | PCI_CFG_EN, PCI_REG_ADDR);
+	outl(value, PCI_REG_DATA);
+}
+
+/**
+ * board_assert_perst() - Assert the PERST# pin
+ *
+ * The CPU interface to the PERST# signal on Quark is platform dependent.
+ * Board-specific codes need supply this routine to assert PCIe slot reset.
+ *
+ * The tricky part in this routine is that any APIs that may trigger PCI
+ * enumeration process are strictly forbidden, as any access to PCIe root
+ * port's configuration registers will cause system hang while it is held
+ * in reset.
+ */
+void board_assert_perst(void);
+
+/**
+ * board_deassert_perst() - De-assert the PERST# pin
+ *
+ * The CPU interface to the PERST# signal on Quark is platform dependent.
+ * Board-specific codes need supply this routine to de-assert PCIe slot reset.
+ *
+ * The tricky part in this routine is that any APIs that may trigger PCI
+ * enumeration process are strictly forbidden, as any access to PCIe root
+ * port's configuration registers will cause system hang while it is held
+ * in reset.
+ */
+void board_deassert_perst(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _QUARK_H_ */
diff --git a/board/intel/bayleybay/bayleybay.c b/board/intel/bayleybay/bayleybay.c
index 7844796..ccbe860 100644
--- a/board/intel/bayleybay/bayleybay.c
+++ b/board/intel/bayleybay/bayleybay.c
@@ -6,14 +6,8 @@
 
 #include <common.h>
 #include <asm/gpio.h>
-#include <netdev.h>
 
 void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio)
 {
 	return;
 }
-
-int board_eth_init(bd_t *bis)
-{
-	return pci_eth_init(bis);
-}
diff --git a/board/intel/crownbay/crownbay.c b/board/intel/crownbay/crownbay.c
index d6de9fa..3a79e69 100644
--- a/board/intel/crownbay/crownbay.c
+++ b/board/intel/crownbay/crownbay.c
@@ -7,7 +7,6 @@
 #include <common.h>
 #include <asm/ibmpc.h>
 #include <asm/pnp_def.h>
-#include <netdev.h>
 #include <smsc_lpc47m.h>
 
 int board_early_init_f(void)
@@ -24,8 +23,3 @@
 {
 	return;
 }
-
-int board_eth_init(bd_t *bis)
-{
-	return pci_eth_init(bis);
-}
diff --git a/board/intel/galileo/galileo.c b/board/intel/galileo/galileo.c
index 746ab27..c1087ac 100644
--- a/board/intel/galileo/galileo.c
+++ b/board/intel/galileo/galileo.c
@@ -5,12 +5,68 @@
  */
 
 #include <common.h>
+#include <asm/io.h>
+#include <asm/arch/device.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/quark.h>
 
 int board_early_init_f(void)
 {
 	return 0;
 }
 
+/*
+ * Intel Galileo gen2 board uses GPIO Resume Well bank pin0 as the PERST# pin.
+ *
+ * We cannot use any public GPIO APIs in <asm-generic/gpio.h> to control this
+ * pin, as these APIs will eventually call into gpio_ich6_ofdata_to_platdata()
+ * in the Intel ICH6 GPIO driver where it calls PCI configuration space access
+ * APIs which will trigger PCI enumeration process.
+ *
+ * Check <asm/arch-quark/quark.h> for more details.
+ */
+void board_assert_perst(void)
+{
+	u32 base, port, val;
+
+	/* retrieve the GPIO IO base */
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, PCI_CFG_GPIOBASE, &base);
+	base = (base & 0xffff) & ~0x7f;
+
+	/* enable the pin */
+	port = base + 0x20;
+	val = inl(port);
+	val |= (1 << 0);
+	outl(val, port);
+
+	/* configure the pin as output */
+	port = base + 0x24;
+	val = inl(port);
+	val &= ~(1 << 0);
+	outl(val, port);
+
+	/* pull it down (assert) */
+	port = base + 0x28;
+	val = inl(port);
+	val &= ~(1 << 0);
+	outl(val, port);
+}
+
+void board_deassert_perst(void)
+{
+	u32 base, port, val;
+
+	/* retrieve the GPIO IO base */
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, PCI_CFG_GPIOBASE, &base);
+	base = (base & 0xffff) & ~0x7f;
+
+	/* pull it up (de-assert) */
+	port = base + 0x28;
+	val = inl(port);
+	val |= (1 << 0);
+	outl(val, port);
+}
+
 void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio)
 {
 	return;
diff --git a/board/siemens/corvus/board.c b/board/siemens/corvus/board.c
index 3294203..28985b8 100644
--- a/board/siemens/corvus/board.c
+++ b/board/siemens/corvus/board.c
@@ -29,6 +29,10 @@
 #include <netdev.h>
 #include <spi.h>
 
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#include <asm/arch/atmel_usba_udc.h>
+#endif
+
 DECLARE_GLOBAL_DATA_PTR;
 
 static void corvus_nand_hw_init(void)
@@ -73,7 +77,7 @@
 #include <spl.h>
 #include <nand.h>
 
-void at91_spl_board_init(void)
+void spl_board_init(void)
 {
 	/*
 	 * For on the sam9m10g45ek board, the chip wm9711 stay in the test
@@ -202,6 +206,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+/* from ./arch/arm/mach-at91/armv7/sama5d3_devices.c */
+void at91_udp_hw_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	/* Enable UPLL clock */
+	writel(AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr);
+	/* Enable UDPHS clock */
+	at91_periph_clk_enable(ATMEL_ID_UDPHS);
+}
+#endif
+
 int board_init(void)
 {
 	/* address of boot parameters */
@@ -222,6 +239,10 @@
 #ifdef CONFIG_CMD_USB
 	taurus_usb_hw_init();
 #endif
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+	at91_udp_hw_init();
+	usba_udc_probe(&pdata);
+#endif
 	return 0;
 }
 
diff --git a/board/siemens/smartweb/smartweb.c b/board/siemens/smartweb/smartweb.c
index cf8a7f5..2d42488 100644
--- a/board/siemens/smartweb/smartweb.c
+++ b/board/siemens/smartweb/smartweb.c
@@ -25,6 +25,7 @@
 #include <asm/arch/at91_pmc.h>
 #include <asm/arch/at91_spi.h>
 #include <spi.h>
+#include <asm/arch/clk.h>
 #include <asm/arch/gpio.h>
 #include <watchdog.h>
 #ifdef CONFIG_MACB
@@ -108,6 +109,29 @@
 }
 #endif /* CONFIG_MACB */
 
+#ifdef CONFIG_USB_GADGET_AT91
+#include <linux/usb/at91_udc.h>
+
+void at91_udp_hw_init(void)
+{
+	at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
+
+	/* Enable PLLB */
+	writel(get_pllb_init(), &pmc->pllbr);
+	while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
+		;
+
+	/* Enable UDPCK clock, MCK is enabled in at91_clock_init() */
+	at91_periph_clk_enable(ATMEL_ID_UDP);
+
+	writel(AT91SAM926x_PMC_UDP, &pmc->scer);
+}
+
+struct at91_udc_data board_udc_data  = {
+	.baseaddr = ATMEL_BASE_UDP0,
+};
+#endif
+
 int board_early_init_f(void)
 {
 	/* enable this here, as we have SPL without serial support */
@@ -134,6 +158,11 @@
 	at91_set_gpio_output(AT91_PIN_PC10, 0);
 	at91_set_gpio_output(AT91_PIN_PC11, 1);
 
+#ifdef CONFIG_USB_GADGET_AT91
+	at91_udp_hw_init();
+	at91_udc_probe(&board_udc_data);
+#endif
+
 	return 0;
 }
 
diff --git a/board/siemens/taurus/taurus.c b/board/siemens/taurus/taurus.c
index 013dac2..72c5e60 100644
--- a/board/siemens/taurus/taurus.c
+++ b/board/siemens/taurus/taurus.c
@@ -12,6 +12,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#include <command.h>
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/at91sam9260_matrix.h>
@@ -79,25 +80,57 @@
 			&mat->scfg[3]);
 }
 
-void at91_spl_board_init(void)
+#if defined(CONFIG_BOARD_AXM)
+static int at91_is_recovery(void)
+{
+	if ((at91_get_gpio_value(AT91_PIN_PA26) == 0) &&
+	    (at91_get_gpio_value(AT91_PIN_PA27) == 0))
+		return 1;
+
+	return 0;
+}
+#elif defined(CONFIG_BOARD_TAURUS)
+static int at91_is_recovery(void)
+{
+	if (at91_get_gpio_value(AT91_PIN_PA31) == 0)
+		return 1;
+
+	return 0;
+}
+#endif
+
+void spl_board_init(void)
 {
 	taurus_nand_hw_init();
 	at91_spi0_hw_init(TAURUS_SPI_MASK);
 
-	/* Configure recovery button PINs */
-	at91_set_gpio_input(AT91_PIN_PA31, 1);
+#if defined(CONFIG_BOARD_AXM)
+	/* Configure LED PINs */
+	at91_set_gpio_output(AT91_PIN_PA6, 0);
+	at91_set_gpio_output(AT91_PIN_PA8, 0);
+	at91_set_gpio_output(AT91_PIN_PA9, 0);
+	at91_set_gpio_output(AT91_PIN_PA10, 0);
+	at91_set_gpio_output(AT91_PIN_PA11, 0);
+	at91_set_gpio_output(AT91_PIN_PA12, 0);
 
-	/* check if button is pressed */
-	if (at91_get_gpio_value(AT91_PIN_PA31) == 0) {
+	/* Configure recovery button PINs */
+	at91_set_gpio_input(AT91_PIN_PA26, 1);
+	at91_set_gpio_input(AT91_PIN_PA27, 1);
+#elif defined(CONFIG_BOARD_TAURUS)
+	at91_set_gpio_input(AT91_PIN_PA31, 1);
+#endif
+
+	/* check for recovery mode */
+	if (at91_is_recovery() == 1) {
 		struct spi_flash *flash;
 
-		debug("Recovery button pressed\n");
+		puts("Recovery button pressed\n");
 		nand_init();
 		spl_nand_erase_one(0, 0);
 		flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
 					0,
 					CONFIG_SF_DEFAULT_SPEED,
-					SPI_MODE_3);
+					CONFIG_SF_DEFAULT_MODE);
 		if (!flash) {
 			puts("no flash\n");
 		} else {
@@ -108,35 +141,72 @@
 	}
 }
 
-void mem_init(void)
+#define SDRAM_BASE_CONF	(AT91_SDRAMC_NR_13 | AT91_SDRAMC_CAS_3 \
+			 |AT91_SDRAMC_NB_4 | AT91_SDRAMC_DBW_32 \
+			 | AT91_SDRAMC_TWR_VAL(3) | AT91_SDRAMC_TRC_VAL(9) \
+			 | AT91_SDRAMC_TRP_VAL(3) | AT91_SDRAMC_TRCD_VAL(3) \
+			 | AT91_SDRAMC_TRAS_VAL(6) | AT91_SDRAMC_TXSR_VAL(10))
+
+void sdramc_configure(unsigned int mask)
 {
 	struct at91_matrix *ma = (struct at91_matrix *)ATMEL_BASE_MATRIX;
 	struct sdramc_reg setting;
 
 	at91_sdram_hw_init();
-	setting.cr = (AT91_SDRAMC_NC_9 |
-		      AT91_SDRAMC_NR_13 |
-		      AT91_SDRAMC_CAS_3 |
-		      AT91_SDRAMC_NB_4 |
-		      AT91_SDRAMC_DBW_32 |
-		      AT91_SDRAMC_TWR_VAL(3) |
-		      AT91_SDRAMC_TRC_VAL(9) |
-		      AT91_SDRAMC_TRP_VAL(3) |
-		      AT91_SDRAMC_TRCD_VAL(3) |
-		      AT91_SDRAMC_TRAS_VAL(6) |
-		      AT91_SDRAMC_TXSR_VAL(10));
+	setting.cr = SDRAM_BASE_CONF | mask;
 	setting.mdr = AT91_SDRAMC_MD_SDRAM;
 	setting.tr = (CONFIG_SYS_MASTER_CLOCK * 7) / 1000000;
 
-
 	writel(readl(&ma->ebicsa) | AT91_MATRIX_CS1A_SDRAMC |
 		AT91_MATRIX_VDDIOMSEL_3_3V | AT91_MATRIX_EBI_IOSR_SEL,
 		&ma->ebicsa);
+
 	sdramc_initialize(ATMEL_BASE_CS1, &setting);
 }
+
+void mem_init(void)
+{
+	unsigned int ram_size = 0;
+
+	/* Configure SDRAM for 128MB */
+	sdramc_configure(AT91_SDRAMC_NC_10);
+
+	/* Do memtest for 128MB */
+	ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
+				CONFIG_SYS_SDRAM_SIZE);
+
+	/*
+	 * If 32MB or 16MB should be supported check also for
+	 * expected mirroring at A16 and A17
+	 * To find mirror addresses depends how the collumns are connected
+	 * at RAM (internaly or externaly)
+	 * If the collumns are not in inverted order the mirror size effect
+	 * behaves like normal SRAM with A0,A1,A2,etc. connected incremantal
+	 */
+
+	/* Mirrors at A15 on ATMEL G20 SDRAM Controller with 64MB*/
+	if (ram_size == 0x800) {
+		printf("\n\r 64MB");
+		sdramc_configure(AT91_SDRAMC_NC_9);
+	} else {
+		/* Size already initialized */
+		printf("\n\r 128MB");
+	}
+}
 #endif
 
 #ifdef CONFIG_MACB
+static void siemens_phy_reset(void)
+{
+	/*
+	 * we need to reset PHY for 200us
+	 * because of bug in ATMEL G20 CPU (undefined initial state of GPIO)
+	 */
+	if ((readl(AT91_ASM_RSTC_SR) & AT91_RSTC_RSTTYP) ==
+	    AT91_RSTC_RSTTYP_GENERAL)
+		at91_set_gpio_value(AT91_PIN_PA25, 0); /* reset eth switch */
+}
+
 static void taurus_macb_hw_init(void)
 {
 	/* Enable EMAC clock */
@@ -160,6 +230,8 @@
 	at91_set_pio_pullup(AT91_PIO_PORTA, 26, 0);
 	at91_set_pio_pullup(AT91_PIO_PORTA, 28, 0);
 
+	siemens_phy_reset();
+
 	at91_phy_reset();
 
 	at91_set_gpio_input(AT91_PIN_PA25, 1);   /* ERST tri-state */
@@ -213,6 +285,29 @@
 	at91_set_gpio_value(TAURUS_SPI_CS_PIN, 1);
 }
 
+#ifdef CONFIG_USB_GADGET_AT91
+#include <linux/usb/at91_udc.h>
+
+void at91_udp_hw_init(void)
+{
+	at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
+
+	/* Enable PLLB */
+	writel(get_pllb_init(), &pmc->pllbr);
+	while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
+		;
+
+	/* Enable UDPCK clock, MCK is enabled in at91_clock_init() */
+	at91_periph_clk_enable(ATMEL_ID_UDP);
+
+	writel(AT91SAM926x_PMC_UDP, &pmc->scer);
+}
+
+struct at91_udc_data board_udc_data  = {
+	.baseaddr = ATMEL_BASE_UDP0,
+};
+#endif
+
 int board_init(void)
 {
 	/* adress of boot parameters */
@@ -225,6 +320,10 @@
 	taurus_macb_hw_init();
 #endif
 	at91_spi0_hw_init(TAURUS_SPI_MASK);
+#ifdef CONFIG_USB_GADGET_AT91
+	at91_udp_hw_init();
+	at91_udc_probe(&board_udc_data);
+#endif
 
 	return 0;
 }
@@ -244,3 +343,97 @@
 #endif
 	return rc;
 }
+
+#if !defined(CONFIG_SPL_BUILD)
+#if defined(CONFIG_BOARD_AXM)
+/*
+ * Booting the Fallback Image.
+ *
+ *  The function is used to provide and
+ *  boot the image with the fallback
+ *  parameters, incase if the faulty image
+ *  in upgraded over the base firmware.
+ *
+ */
+static int upgrade_failure_fallback(void)
+{
+	char *partitionset_active = NULL;
+	char *rootfs = NULL;
+	char *rootfs_fallback = NULL;
+	char *kern_off;
+	char *kern_off_fb;
+	char *kern_size;
+	char *kern_size_fb;
+
+	partitionset_active = getenv("partitionset_active");
+	if (partitionset_active) {
+		if (partitionset_active[0] == 'A')
+			setenv("partitionset_active", "B");
+		else
+			setenv("partitionset_active", "A");
+	} else {
+		printf("partitionset_active missing.\n");
+		return -ENOENT;
+	}
+
+	rootfs = getenv("rootfs");
+	rootfs_fallback = getenv("rootfs_fallback");
+	setenv("rootfs", rootfs_fallback);
+	setenv("rootfs_fallback", rootfs);
+
+	kern_size = getenv("kernel_size");
+	kern_size_fb = getenv("kernel_size_fallback");
+	setenv("kernel_size", kern_size_fb);
+	setenv("kernel_size_fallback", kern_size);
+
+	kern_off = getenv("kernel_Off");
+	kern_off_fb = getenv("kernel_Off_fallback");
+	setenv("kernel_Off", kern_off_fb);
+	setenv("kernel_Off_fallback", kern_off);
+
+	setenv("bootargs", '\0');
+	setenv("upgrade_available", '\0');
+	setenv("boot_retries", '\0');
+	saveenv();
+
+	return 0;
+}
+
+static int do_upgrade_available(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	unsigned long upgrade_available = 0;
+	unsigned long boot_retry = 0;
+	char boot_buf[10];
+
+	upgrade_available = simple_strtoul(getenv("upgrade_available"), NULL,
+					   10);
+	if (upgrade_available) {
+		boot_retry = simple_strtoul(getenv("boot_retries"), NULL, 10);
+		boot_retry++;
+		sprintf(boot_buf, "%lx", boot_retry);
+		setenv("boot_retries", boot_buf);
+		saveenv();
+
+		/*
+		 * Here the boot_retries count is checked, and if the
+		 * count becomes greater than 2 switch back to the
+		 * fallback, and reset the board.
+		 */
+
+		if (boot_retry > 2) {
+			if (upgrade_failure_fallback() == 0)
+				do_reset(NULL, 0, 0, NULL);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+U_BOOT_CMD(
+	upgrade_available,	1,	1,	do_upgrade_available,
+	"check Siemens update",
+	"no parameters"
+);
+#endif
+#endif
diff --git a/configs/bayleybay_defconfig b/configs/bayleybay_defconfig
index 13bd282..2ea30c8 100644
--- a/configs/bayleybay_defconfig
+++ b/configs/bayleybay_defconfig
@@ -5,6 +5,7 @@
 CONFIG_HAVE_INTEL_ME=y
 CONFIG_SMP=y
 CONFIG_HAVE_VGA_BIOS=y
+CONFIG_VGA_BIOS_ADDR=0xfffa0000
 CONFIG_GENERATE_PIRQ_TABLE=y
 CONFIG_GENERATE_MP_TABLE=y
 CONFIG_CMD_CPU=y
@@ -19,11 +20,13 @@
 CONFIG_CPU=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
-CONFIG_NETDEVICES=y
+CONFIG_DM_ETH=y
 CONFIG_E1000=y
 CONFIG_VIDEO_VESA=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_DM_RTC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
diff --git a/configs/coreboot-x86_defconfig b/configs/coreboot-x86_defconfig
index ebaf86b..e95f96d 100644
--- a/configs/coreboot-x86_defconfig
+++ b/configs/coreboot-x86_defconfig
@@ -14,10 +14,13 @@
 CONFIG_OF_CONTROL=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
-CONFIG_NETDEVICES=y
+CONFIG_DM_ETH=y
 CONFIG_E1000=y
 CONFIG_DM_TPM=y
 CONFIG_TPM_TIS_LPC=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_RTC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
 CONFIG_TPM=y
diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig
index 4fc1827..f328159 100644
--- a/configs/crownbay_defconfig
+++ b/configs/crownbay_defconfig
@@ -19,10 +19,13 @@
 CONFIG_CPU=y
 CONFIG_DM_PCI=y
 CONFIG_SPI_FLASH=y
-CONFIG_NETDEVICES=y
+CONFIG_DM_ETH=y
 CONFIG_E1000=y
+CONFIG_PCH_GBE=y
 CONFIG_VIDEO_VESA=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_DM_RTC=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
diff --git a/configs/galileo_defconfig b/configs/galileo_defconfig
index 6ef1090..d05154e 100644
--- a/configs/galileo_defconfig
+++ b/configs/galileo_defconfig
@@ -14,6 +14,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
+CONFIG_DM_PCI=y
 CONFIG_DM_RTC=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USE_PRIVATE_LIBGCC=y
 CONFIG_SYS_VSNPRINTF=y
diff --git a/doc/README.x86 b/doc/README.x86
index 3bab5cf..5f9c46f 100644
--- a/doc/README.x86
+++ b/doc/README.x86
@@ -189,7 +189,7 @@
 001000   me.bin              Set by the descriptor
 500000   <spare>
 700000   u-boot-dtb.bin      CONFIG_SYS_TEXT_BASE
-790000   vga.bin             CONFIG_X86_OPTION_ROM_ADDR
+790000   vga.bin             CONFIG_VGA_BIOS_ADDR
 7c0000   fsp.bin             CONFIG_FSP_ADDR
 7f8000   <spare>             (depends on size of fsp.bin)
 7fe000   Environment         CONFIG_ENV_OFFSET
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 7367d9e..bbec6a6 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -8,6 +8,11 @@
 	  This is currently implemented in net/eth.c
 	  Look in include/net.h for details.
 
+config PHYLIB
+	bool "Ethernet PHY (physical media interface) support"
+	help
+	  Enable Ethernet PHY (physical media interface) support.
+
 menuconfig NETDEVICES
 	bool "Network device support"
 	depends on NET
@@ -79,4 +84,12 @@
 	  100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
 	  provide the PHY (physical media interface).
 
+config PCH_GBE
+	bool "Intel Platform Controller Hub EG20T GMAC driver"
+	depends on DM_ETH && DM_PCI
+	select PHYLIB
+	help
+	  This MAC is present in Intel Platform Controller Hub EG20T. It
+	  supports 10/100/1000 Mbps operation.
+
 endif # NETDEVICES
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index d9cb507..ae78d21 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -562,12 +562,12 @@
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct dw_eth_dev *priv = dev_get_priv(dev);
+	u32 iobase = pdata->iobase;
 	int ret;
 
-	debug("%s, iobase=%lx, priv=%p\n", __func__, pdata->iobase, priv);
-	priv->mac_regs_p = (struct eth_mac_regs *)pdata->iobase;
-	priv->dma_regs_p = (struct eth_dma_regs *)(pdata->iobase +
-			DW_DMA_BASE_OFFSET);
+	debug("%s, iobase=%x, priv=%p\n", __func__, iobase, priv);
+	priv->mac_regs_p = (struct eth_mac_regs *)iobase;
+	priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
 	priv->interface = pdata->phy_interface;
 
 	dw_mdio_init(dev->name, priv->mac_regs_p);
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
index a03bdc0..004fcf8 100644
--- a/drivers/net/pch_gbe.c
+++ b/drivers/net/pch_gbe.c
@@ -7,10 +7,10 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <asm/io.h>
 #include <pci.h>
-#include <malloc.h>
 #include <miiphy.h>
 #include "pch_gbe.h"
 
@@ -19,7 +19,7 @@
 #endif
 
 static struct pci_device_id supported[] = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_GBE },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_GBE) },
 	{ }
 };
 
@@ -62,9 +62,10 @@
 	return -ETIME;
 }
 
-static int pch_gbe_reset(struct eth_device *dev)
+static int pch_gbe_reset(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *plat = dev_get_platdata(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
 	ulong start;
 
@@ -97,7 +98,7 @@
 			 * so we have to reload MAC address here in order to
 			 * make linux pch_gbe driver happy.
 			 */
-			return pch_gbe_mac_write(mac_regs, dev->enetaddr);
+			return pch_gbe_mac_write(mac_regs, plat->enetaddr);
 		}
 
 		udelay(10);
@@ -107,9 +108,9 @@
 	return -ETIME;
 }
 
-static void pch_gbe_rx_descs_init(struct eth_device *dev)
+static void pch_gbe_rx_descs_init(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
 	struct pch_gbe_rx_desc *rx_desc = &priv->rx_desc[0];
 	int i;
@@ -128,9 +129,9 @@
 	       &mac_regs->rx_dsc_sw_p);
 }
 
-static void pch_gbe_tx_descs_init(struct eth_device *dev)
+static void pch_gbe_tx_descs_init(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
 	struct pch_gbe_tx_desc *tx_desc = &priv->tx_desc[0];
 
@@ -183,9 +184,9 @@
 	return;
 }
 
-static int pch_gbe_init(struct eth_device *dev, bd_t *bis)
+static int pch_gbe_start(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
 
 	if (pch_gbe_reset(dev))
@@ -226,18 +227,18 @@
 	return 0;
 }
 
-static void pch_gbe_halt(struct eth_device *dev)
+static void pch_gbe_stop(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 
 	pch_gbe_reset(dev);
 
 	phy_shutdown(priv->phydev);
 }
 
-static int pch_gbe_send(struct eth_device *dev, void *packet, int length)
+static int pch_gbe_send(struct udevice *dev, void *packet, int length)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
 	struct pch_gbe_tx_desc *tx_head, *tx_desc;
 	u16 frame_ctrl = 0;
@@ -277,15 +278,13 @@
 	return -ETIME;
 }
 
-static int pch_gbe_recv(struct eth_device *dev)
+static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
 	struct pch_gbe_regs *mac_regs = priv->mac_regs;
-	struct pch_gbe_rx_desc *rx_head, *rx_desc;
+	struct pch_gbe_rx_desc *rx_desc;
 	u32 hw_desc, buffer_addr, length;
-	int rx_swp;
 
-	rx_head = &priv->rx_desc[0];
 	rx_desc = &priv->rx_desc[priv->rx_idx];
 
 	readl(&mac_regs->int_st);
@@ -293,11 +292,21 @@
 
 	/* Just return if not receiving any packet */
 	if ((u32)rx_desc == hw_desc)
-		return 0;
+		return -EAGAIN;
 
 	buffer_addr = pci_mem_to_phys(priv->bdf, rx_desc->buffer_addr);
+	*packetp = (uchar *)buffer_addr;
 	length = rx_desc->rx_words_eob - 3 - ETH_FCS_LEN;
-	net_process_received_packet((uchar *)buffer_addr, length);
+
+	return length;
+}
+
+static int pch_gbe_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
+	struct pch_gbe_regs *mac_regs = priv->mac_regs;
+	struct pch_gbe_rx_desc *rx_head = &priv->rx_desc[0];
+	int rx_swp;
 
 	/* Test the wrap-around condition */
 	if (++priv->rx_idx >= PCH_GBE_DESC_NUM)
@@ -309,7 +318,7 @@
 	writel(pci_phys_to_mem(priv->bdf, (u32)(rx_head + rx_swp)),
 	       &mac_regs->rx_dsc_sw_p);
 
-	return length;
+	return 0;
 }
 
 static int pch_gbe_mdio_ready(struct pch_gbe_regs *mac_regs)
@@ -365,7 +374,7 @@
 		return 0;
 }
 
-static int pch_gbe_mdio_init(char *name, struct pch_gbe_regs *mac_regs)
+static int pch_gbe_mdio_init(const char *name, struct pch_gbe_regs *mac_regs)
 {
 	struct mii_dev *bus;
 
@@ -384,13 +393,14 @@
 	return mdio_register(bus);
 }
 
-static int pch_gbe_phy_init(struct eth_device *dev)
+static int pch_gbe_phy_init(struct udevice *dev)
 {
-	struct pch_gbe_priv *priv = dev->priv;
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *plat = dev_get_platdata(dev);
 	struct phy_device *phydev;
 	int mask = 0xffffffff;
 
-	phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+	phydev = phy_find_by_mask(priv->bus, mask, plat->phy_interface);
 	if (!phydev) {
 		printf("pch_gbe: cannot find the phy\n");
 		return -1;
@@ -404,63 +414,66 @@
 	priv->phydev = phydev;
 	phy_config(phydev);
 
-	return 1;
+	return 0;
 }
 
-int pch_gbe_register(bd_t *bis)
+int pch_gbe_probe(struct udevice *dev)
 {
-	struct eth_device *dev;
 	struct pch_gbe_priv *priv;
+	struct eth_pdata *plat = dev_get_platdata(dev);
 	pci_dev_t devno;
 	u32 iobase;
 
-	devno = pci_find_devices(supported, 0);
-	if (devno == -1)
-		return -ENODEV;
-
-	dev = (struct eth_device *)malloc(sizeof(*dev));
-	if (!dev)
-		return -ENOMEM;
-	memset(dev, 0, sizeof(*dev));
+	devno = pci_get_bdf(dev);
 
 	/*
 	 * The priv structure contains the descriptors and frame buffers which
-	 * need a strict buswidth alignment (64 bytes)
+	 * need a strict buswidth alignment (64 bytes). This is guaranteed by
+	 * DM_FLAG_ALLOC_PRIV_DMA flag in the U_BOOT_DRIVER.
 	 */
-	priv = (struct pch_gbe_priv *)memalign(PCH_GBE_ALIGN_SIZE,
-					       sizeof(*priv));
-	if (!priv) {
-		free(dev);
-		return -ENOMEM;
-	}
-	memset(priv, 0, sizeof(*priv));
+	priv = dev_get_priv(dev);
 
-	dev->priv = priv;
-	priv->dev = dev;
 	priv->bdf = devno;
 
 	pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
 	iobase &= PCI_BASE_ADDRESS_MEM_MASK;
 	iobase = pci_mem_to_phys(devno, iobase);
 
-	dev->iobase = iobase;
+	plat->iobase = iobase;
 	priv->mac_regs = (struct pch_gbe_regs *)iobase;
 
-	sprintf(dev->name, "pch_gbe");
-
 	/* Read MAC address from SROM and initialize dev->enetaddr with it */
-	pch_gbe_mac_read(priv->mac_regs, dev->enetaddr);
+	pch_gbe_mac_read(priv->mac_regs, plat->enetaddr);
 
-	dev->init = pch_gbe_init;
-	dev->halt = pch_gbe_halt;
-	dev->send = pch_gbe_send;
-	dev->recv = pch_gbe_recv;
-
-	eth_register(dev);
-
-	priv->interface = PHY_INTERFACE_MODE_RGMII;
+	plat->phy_interface = PHY_INTERFACE_MODE_RGMII;
 	pch_gbe_mdio_init(dev->name, priv->mac_regs);
 	priv->bus = miiphy_get_dev_by_name(dev->name);
 
 	return pch_gbe_phy_init(dev);
 }
+
+static const struct eth_ops pch_gbe_ops = {
+	.start = pch_gbe_start,
+	.send = pch_gbe_send,
+	.recv = pch_gbe_recv,
+	.free_pkt = pch_gbe_free_pkt,
+	.stop = pch_gbe_stop,
+};
+
+static const struct udevice_id pch_gbe_ids[] = {
+	{ .compatible = "intel,pch-gbe" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_pch_gbe) = {
+	.name = "pch_gbe",
+	.id = UCLASS_ETH,
+	.of_match = pch_gbe_ids,
+	.probe = pch_gbe_probe,
+	.ops = &pch_gbe_ops,
+	.priv_auto_alloc_size = sizeof(struct pch_gbe_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+U_BOOT_PCI_DEVICE(eth_pch_gbe, supported);
diff --git a/drivers/net/pch_gbe.h b/drivers/net/pch_gbe.h
index 11329d4..afcb03d 100644
--- a/drivers/net/pch_gbe.h
+++ b/drivers/net/pch_gbe.h
@@ -287,12 +287,10 @@
 	struct pch_gbe_rx_desc rx_desc[PCH_GBE_DESC_NUM];
 	struct pch_gbe_tx_desc tx_desc[PCH_GBE_DESC_NUM];
 	char rx_buff[PCH_GBE_DESC_NUM][PCH_GBE_RX_FRAME_LEN];
-	struct eth_device *dev;
 	struct phy_device *phydev;
 	struct mii_dev *bus;
 	struct pch_gbe_regs *mac_regs;
 	pci_dev_t bdf;
-	u32 interface;
 	int rx_idx;
 	int tx_idx;
 };
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index b25298f..ea70853 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -20,16 +20,36 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static int pci_get_bus(int busnum, struct udevice **busp)
+{
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
+
+	/* Since buses may not be numbered yet try a little harder with bus 0 */
+	if (ret == -ENODEV) {
+		ret = uclass_first_device(UCLASS_PCI, busp);
+		if (ret)
+			return ret;
+		else if (!*busp)
+			return -ENODEV;
+		ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
+	}
+
+	return ret;
+}
+
 struct pci_controller *pci_bus_to_hose(int busnum)
 {
 	struct udevice *bus;
 	int ret;
 
-	ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
+	ret = pci_get_bus(busnum, &bus);
 	if (ret) {
 		debug("%s: Cannot get bus %d: ret=%d\n", __func__, busnum, ret);
 		return NULL;
 	}
+
 	return dev_get_uclass_priv(bus);
 }
 
@@ -128,7 +148,7 @@
 	struct udevice *bus;
 	int ret;
 
-	ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+	ret = pci_get_bus(PCI_BUS(bdf), &bus);
 	if (ret)
 		return ret;
 	return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp);
@@ -206,7 +226,7 @@
 	struct udevice *bus;
 	int ret;
 
-	ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+	ret = pci_get_bus(PCI_BUS(bdf), &bus);
 	if (ret)
 		return ret;
 
@@ -271,7 +291,7 @@
 	struct udevice *bus;
 	int ret;
 
-	ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+	ret = pci_get_bus(PCI_BUS(bdf), &bus);
 	if (ret)
 		return ret;
 
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 4c11a7e..6288ecf 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -10,6 +10,7 @@
 
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
+obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o
 obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
 obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o
 obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
new file mode 100644
index 0000000..4070803
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.c
@@ -0,0 +1,1625 @@
+/*
+ * from linux:
+ * c94e289f195e: usb: gadget: remove incorrect __init/__exit annotations
+ *
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by David Brownell
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#undef	VERBOSE_DEBUG
+#undef	PACKET_TRACE
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <mach/at91_matrix.h>
+#include <linux/list.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/at91_udc.h>
+#include <malloc.h>
+#include <usb/lin_gadget_compat.h>
+
+#include "at91_udc.h"
+
+/*
+ * This controller is simple and PIO-only.  It's used in many AT91-series
+ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs supporting
+ * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the
+ * testing hasn't covered such cases.)
+ *
+ * The pullup is most important (so it's integrated on sam926x parts).  It
+ * provides software control over whether the host enumerates the device.
+ *
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power.  During USB suspend, the 48 MHz clock is gated off in hardware;
+ * it may also be gated off by software during some Linux sleep states.
+ */
+
+#define	DRIVER_VERSION	"3 May 2006"
+
+static const char driver_name [] = "at91_udc";
+static const char * const ep_names[] = {
+	"ep0",
+	"ep1",
+	"ep2",
+	"ep3-int",
+	"ep4",
+	"ep5",
+};
+#define ep0name		ep_names[0]
+
+#define at91_udp_read(udc, reg) \
+	__raw_readl((udc)->udp_baseaddr + (reg))
+#define at91_udp_write(udc, reg, val) \
+	__raw_writel((val), (udc)->udp_baseaddr + (reg))
+
+static struct at91_udc *controller;
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+	unsigned	stopped = ep->stopped;
+	struct at91_udc	*udc = ep->udc;
+
+	list_del_init(&req->queue);
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+	if (status && status != -ESHUTDOWN)
+		VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
+
+	ep->stopped = 1;
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+	ep->stopped = stopped;
+
+	/* ep0 is always ready; other endpoints need a non-empty queue */
+	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+		at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define	RX_DATA_READY	(AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ *  - clear SET_FX bits (setting them could change something)
+ *  - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ *
+ * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains,
+ * implying a need to wait for one write to complete (test relevant bits)
+ * before starting the next write.  This shouldn't be an issue given how
+ * infrequently we write, except maybe for write-then-read idioms.
+ */
+#define	SET_FX	(AT91_UDP_TXPKTRDY)
+#define	CLR_FX	(RX_DATA_READY | AT91_UDP_RXSETUP \
+		| AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	u32		csr;
+	u8		*buf;
+	unsigned int	count, bufferspace, is_done;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+
+	/*
+	 * there might be nothing to read if ep_queue() calls us,
+	 * or if we already emptied both pingpong buffers
+	 */
+rescan:
+	csr = __raw_readl(creg);
+	if ((csr & RX_DATA_READY) == 0)
+		return 0;
+
+	count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (count > ep->ep.maxpacket)
+		count = ep->ep.maxpacket;
+	if (count > bufferspace) {
+		DBG("%s buffer overflow\n", ep->ep.name);
+		req->req.status = -EOVERFLOW;
+		count = bufferspace;
+	}
+	__raw_readsb((unsigned long)dreg, buf, count);
+
+	/* release and swap pingpong mem bank */
+	csr |= CLR_FX;
+	if (ep->is_pingpong) {
+		if (ep->fifo_bank == 0) {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+			ep->fifo_bank = 1;
+		} else {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+			ep->fifo_bank = 0;
+		}
+	} else
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+	__raw_writel(csr, creg);
+
+	req->req.actual += count;
+	is_done = (count < ep->ep.maxpacket);
+	if (count == bufferspace)
+		is_done = 1;
+
+	PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+			is_done ? " (done)" : "");
+
+	/*
+	 * avoid extra trips through IRQ logic for packets already in
+	 * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+	 */
+	if (is_done)
+		done(ep, req, 0);
+	else if (ep->is_pingpong) {
+		/*
+		 * One dummy read to delay the code because of a HW glitch:
+		 * CSR returns bad RXCOUNT when read too soon after updating
+		 * RX_DATA_BK flags.
+		 */
+		csr = __raw_readl(creg);
+
+		bufferspace -= count;
+		buf += count;
+		goto rescan;
+	}
+
+	return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u32		csr = __raw_readl(creg);
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	total, count, is_last;
+	u8		*buf;
+
+	/*
+	 * TODO: allow for writing two packets to the fifo ... that'll
+	 * reduce the amount of IN-NAKing, but probably won't affect
+	 * throughput much.  (Unlike preventing OUT-NAKing!)
+	 */
+
+	/*
+	 * If ep_queue() calls us, the queue is empty and possibly in
+	 * odd states like TXCOMP not yet cleared (we do it, saving at
+	 * least one IRQ) or the fifo not yet being free.  Those aren't
+	 * issues normally (IRQ handler fast path).
+	 */
+	if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+		if (csr & AT91_UDP_TXCOMP) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (csr & AT91_UDP_TXPKTRDY)
+			return 0;
+	}
+
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+	total = req->req.length - req->req.actual;
+	if (ep->ep.maxpacket < total) {
+		count = ep->ep.maxpacket;
+		is_last = 0;
+	} else {
+		count = total;
+		is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+	}
+
+	/*
+	 * Write the packet, maybe it's a ZLP.
+	 *
+	 * NOTE:  incrementing req->actual before we receive the ACK means
+	 * gadget driver IN bytecounts can be wrong in fault cases.  That's
+	 * fixable with PIO drivers like this one (save "count" here, and
+	 * do the increment later on TX irq), but not for most DMA hardware.
+	 *
+	 * So all gadget drivers must accept that potential error.  Some
+	 * hardware supports precise fifo status reporting, letting them
+	 * recover when the actual bytecount matters (e.g. for USB Test
+	 * and Measurement Class devices).
+	 */
+	__raw_writesb((unsigned long)dreg, buf, count);
+	csr &= ~SET_FX;
+	csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	req->req.actual += count;
+
+	PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+			is_last ? " (done)" : "");
+	if (is_last)
+		done(ep, req, 0);
+	return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+	struct at91_request *req;
+
+	/* terminate any request in the queue */
+	ep->stopped = 1;
+	if (list_empty(&ep->queue))
+		return;
+
+	VDBG("%s %s\n", __func__, ep->ep.name);
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct at91_request, queue);
+		done(ep, req, status);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep,
+				const struct usb_endpoint_descriptor *desc)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc *udc;
+	u16		maxpacket;
+	u32		tmp;
+	unsigned long	flags;
+
+	if (!_ep || !ep
+			|| !desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| (maxpacket = usb_endpoint_maxp(desc)) == 0
+			|| maxpacket > ep->maxpacket) {
+		DBG("bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	udc = ep->udc;
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	tmp = usb_endpoint_type(desc);
+	switch (tmp) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		DBG("only one control endpoint\n");
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_INT:
+		if (maxpacket > 64)
+			goto bogus_max;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		switch (maxpacket) {
+		case 8:
+		case 16:
+		case 32:
+		case 64:
+			goto ok;
+		}
+bogus_max:
+		DBG("bogus maxpacket %d\n", maxpacket);
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->is_pingpong) {
+			DBG("iso requires double buffering\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+ok:
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* initialize endpoint to match this descriptor */
+	ep->is_in = usb_endpoint_dir_in(desc);
+	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+	ep->stopped = 0;
+	if (ep->is_in)
+		tmp |= 0x04;
+	tmp <<= 8;
+	tmp |= AT91_UDP_EPEDS;
+	__raw_writel(tmp, ep->creg);
+
+	ep->ep.maxpacket = maxpacket;
+
+	/*
+	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
+	 * since endpoint resets don't reset hw pingpong state.
+	 */
+	at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
+	unsigned long	flags;
+
+	if (ep == &ep->udc->ep[0])
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* restore the endpoint's pristine config */
+	ep->ep.desc = NULL;
+	ep->ep.maxpacket = ep->maxpacket;
+
+	/* reset fifos and endpoint */
+	if (ep->udc->clocked) {
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+		__raw_writel(0, ep->creg);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *
+at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct at91_request *req;
+
+	req = kzalloc(sizeof (struct at91_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_request *req;
+
+	req = container_of(_req, struct at91_request, req);
+	BUG_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+			struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct at91_request	*req;
+	struct at91_ep		*ep;
+	struct at91_udc		*udc;
+	int			status;
+	unsigned long		flags;
+
+	req = container_of(_req, struct at91_request, req);
+	ep = container_of(_ep, struct at91_ep, ep);
+
+	if (!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)) {
+		DBG("invalid request\n");
+		return -EINVAL;
+	}
+
+	if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) {
+		DBG("invalid ep\n");
+		return -EINVAL;
+	}
+
+	udc = ep->udc;
+
+	if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("invalid device\n");
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* try to kickstart any empty and idle queue */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		int	is_ep0;
+
+		/*
+		 * If this control request has a non-empty DATA stage, this
+		 * will start that stage.  It works just like a non-control
+		 * request (until the status stage starts, maybe early).
+		 *
+		 * If the data stage is empty, then this starts a successful
+		 * IN/STATUS stage.  (Unsuccessful ones use set_halt.)
+		 */
+		is_ep0 = (ep->ep.name == ep0name);
+		if (is_ep0) {
+			u32	tmp;
+
+			if (!udc->req_pending) {
+				status = -EINVAL;
+				goto done;
+			}
+
+			/*
+			 * defer changing CONFG until after the gadget driver
+			 * reconfigures the endpoints.
+			 */
+			if (udc->wait_for_config_ack) {
+				tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+				tmp ^= AT91_UDP_CONFG;
+				VDBG("toggle config\n");
+				at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+			}
+			if (req->req.length == 0) {
+ep0_in_status:
+				PACKET("ep0 in/status\n");
+				status = 0;
+				tmp = __raw_readl(ep->creg);
+				tmp &= ~SET_FX;
+				tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+				__raw_writel(tmp, ep->creg);
+				udc->req_pending = 0;
+				goto done;
+			}
+		}
+
+		if (ep->is_in)
+			status = write_fifo(ep, req);
+		else {
+			status = read_fifo(ep, req);
+
+			/* IN/STATUS stage is otherwise triggered by irq */
+			if (status && is_ep0)
+				goto ep0_in_status;
+		}
+	} else
+		status = 0;
+
+	if (req && !status) {
+		list_add_tail (&req->queue, &ep->queue);
+		at91_udp_write(udc, AT91_UDP_IER, ep->int_mask);
+	}
+done:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_ep		*ep;
+	struct at91_request	*req;
+	unsigned long		flags;
+
+	ep = container_of(_ep, struct at91_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
+	u32 __iomem	*creg;
+	u32		csr;
+	unsigned long	flags;
+	int		status = 0;
+
+	if (!_ep || ep->is_iso || !ep->udc->clocked)
+		return -EINVAL;
+
+	creg = ep->creg;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	csr = __raw_readl(creg);
+
+	/*
+	 * fail with still-busy IN endpoints, ensuring correct sequencing
+	 * of data tx then stall.  note that the fifo rx bytecount isn't
+	 * completely accurate as a tx bytecount.
+	 */
+	if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+		status = -EAGAIN;
+	else {
+		csr |= CLR_FX;
+		csr &= ~SET_FX;
+		if (value) {
+			csr |= AT91_UDP_FORCESTALL;
+			VDBG("halt %s\n", ep->ep.name);
+		} else {
+			at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+			csr &= ~AT91_UDP_FORCESTALL;
+		}
+		__raw_writel(csr, creg);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+static const struct usb_ep_ops at91_ep_ops = {
+	.enable		= at91_ep_enable,
+	.disable	= at91_ep_disable,
+	.alloc_request	= at91_ep_alloc_request,
+	.free_request	= at91_ep_free_request,
+	.queue		= at91_ep_queue,
+	.dequeue	= at91_ep_dequeue,
+	.set_halt	= at91_ep_set_halt,
+	/* there's only imprecise fifo status reporting */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+	struct at91_udc *udc = to_udc(gadget);
+
+	if (!to_udc(gadget)->clocked)
+		return -EINVAL;
+	return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	u32		glbstate;
+	int		status = -EINVAL;
+	unsigned long	flags;
+
+	DBG("%s\n", __func__ );
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!udc->clocked || !udc->suspended)
+		goto done;
+
+	/* NOTE:  some "early versions" handle ESR differently ... */
+
+	glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+	if (!(glbstate & AT91_UDP_ESR))
+		goto done;
+	glbstate |= AT91_UDP_ESR;
+	at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
+
+done:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->ep.desc = NULL;
+		ep->stopped = 0;
+		ep->fifo_bank = 0;
+		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
+		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
+		/* initialize one queue per endpoint */
+		INIT_LIST_HEAD(&ep->queue);
+	}
+}
+
+static void reset_gadget(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->suspended = 0;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver) {
+		spin_unlock(&udc->lock);
+		udc->driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+	}
+
+	udc_reinit(udc);
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->suspended = 0;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver) {
+		spin_unlock(&udc->lock);
+		driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+	}
+
+	udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+	if (udc->clocked)
+		return;
+	udc->clocked = 1;
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+	if (!udc->clocked)
+		return;
+	udc->clocked = 0;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+	if (!udc->enabled || !udc->vbus)
+		is_on = 0;
+	DBG("%sactive\n", is_on ? "" : "in");
+
+	if (is_on) {
+		clk_on(udc);
+		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+		at91_udp_write(udc, AT91_UDP_TXVC, 0);
+	} else {
+		stop_activity(udc);
+		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+		clk_off(udc);
+	}
+
+	if (udc->caps && udc->caps->pullup)
+		udc->caps->pullup(udc, is_on);
+}
+
+/* vbus is here!  turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	/* VDBG("vbus %s\n", is_active ? "on" : "off"); */
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->vbus = (is_active != 0);
+	if (udc->driver)
+		pullup(udc, is_active);
+	else
+		pullup(udc, 0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->enabled = is_on = !!is_on;
+	pullup(udc, is_on);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->selfpowered = (is_on != 0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget);
+
+static const struct usb_gadget_ops at91_udc_ops = {
+	.get_frame		= at91_get_frame,
+	.wakeup			= at91_wakeup,
+	.set_selfpowered	= at91_set_selfpowered,
+	.vbus_session		= at91_vbus_session,
+	.pullup			= at91_pullup,
+	.udc_start		= at91_start,
+	.udc_stop		= at91_stop,
+
+	/*
+	 * VBUS-powered devices may also also want to support bigger
+	 * power budgets after an appropriate SET_CONFIGURATION.
+	 */
+	/* .vbus_power		= at91_vbus_power, */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+	struct at91_request	*req;
+	u32 __iomem		*creg = ep->creg;
+	u32			csr = __raw_readl(creg);
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+			struct at91_request, queue);
+	else
+		req = NULL;
+
+	if (ep->is_in) {
+		if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+		}
+		if (req)
+			return write_fifo(ep, req);
+
+	} else {
+		if (csr & AT91_UDP_STALLSENT) {
+			/* STALLSENT bit == ISOERR */
+			if (ep->is_iso && req)
+				req->req.status = -EILSEQ;
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (req && (csr & RX_DATA_READY))
+			return read_fifo(ep, req);
+	}
+	return 0;
+}
+
+union setup {
+	u8			raw[8];
+	struct usb_ctrlrequest	r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	rxcount, i = 0;
+	u32		tmp;
+	union setup	pkt;
+	int		status = 0;
+
+	/* read and ack SETUP; hard-fail for bogus packets */
+	rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (likely(rxcount == 8)) {
+		while (rxcount--)
+			pkt.raw[i++] = __raw_readb(dreg);
+		if (pkt.r.bRequestType & USB_DIR_IN) {
+			csr |= AT91_UDP_DIR;
+			ep->is_in = 1;
+		} else {
+			csr &= ~AT91_UDP_DIR;
+			ep->is_in = 0;
+		}
+	} else {
+		/* REVISIT this happens sometimes under load; why?? */
+		ERR("SETUP len %d, csr %08x\n", rxcount, csr);
+		status = -EINVAL;
+	}
+	csr |= CLR_FX;
+	csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+	__raw_writel(csr, creg);
+	udc->wait_for_addr_ack = 0;
+	udc->wait_for_config_ack = 0;
+	ep->stopped = 0;
+	if (unlikely(status != 0))
+		goto stall;
+
+#define w_index		le16_to_cpu(pkt.r.wIndex)
+#define w_value		le16_to_cpu(pkt.r.wValue)
+#define w_length	le16_to_cpu(pkt.r.wLength)
+
+	VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+			pkt.r.bRequestType, pkt.r.bRequest,
+			w_value, w_index, w_length);
+
+	/*
+	 * A few standard requests get handled here, ones that touch
+	 * hardware ... notably for device and endpoint features.
+	 */
+	udc->req_pending = 1;
+	csr = __raw_readl(creg);
+	csr |= CLR_FX;
+	csr &= ~SET_FX;
+	switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_ADDRESS:
+		__raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+		udc->addr = w_value;
+		udc->wait_for_addr_ack = 1;
+		udc->req_pending = 0;
+		/* FADDR is set later, when we ack host STATUS */
+		return;
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_CONFIGURATION:
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+		if (pkt.r.wValue)
+			udc->wait_for_config_ack = (tmp == 0);
+		else
+			udc->wait_for_config_ack = (tmp != 0);
+		if (udc->wait_for_config_ack)
+			VDBG("wait for config\n");
+		/* CONFG is toggled later, if gadget driver succeeds */
+		break;
+
+	/*
+	 * Hosts may set or clear remote wakeup status, and
+	 * devices may report they're VBUS powered.
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+		PACKET("get device status\n");
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+		tmp |= AT91_UDP_ESR;
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+		tmp &= ~AT91_UDP_ESR;
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+
+	/*
+	 * Interfaces have no feature settings; this is pretty useless.
+	 * we won't even insist the interface exists...
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_GET_STATUS:
+		PACKET("get interface status\n");
+		__raw_writeb(0, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_SET_FEATURE:
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		goto stall;
+
+	/*
+	 * Hosts may clear bulk/intr endpoint halt after the gadget
+	 * driver sets it (not widely used); or set it (for testing)
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
+			goto stall;
+
+		if (tmp) {
+			if ((w_index & USB_DIR_IN)) {
+				if (!ep->is_in)
+					goto stall;
+			} else if (ep->is_in)
+				goto stall;
+		}
+		PACKET("get %s status\n", ep->ep.name);
+		if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+			tmp = (1 << USB_ENDPOINT_HALT);
+		else
+			tmp = 0;
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_SET_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+			goto stall;
+		if (!ep->ep.desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		tmp = __raw_readl(ep->creg);
+		tmp &= ~SET_FX;
+		tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+		__raw_writel(tmp, ep->creg);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+			goto stall;
+		if (tmp == 0)
+			goto succeed;
+		if (!ep->ep.desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+		tmp = __raw_readl(ep->creg);
+		tmp |= CLR_FX;
+		tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+		__raw_writel(tmp, ep->creg);
+		if (!list_empty(&ep->queue))
+			handle_ep(ep);
+		goto succeed;
+	}
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+	/* pass request up to the gadget driver */
+	if (udc->driver) {
+		spin_unlock(&udc->lock);
+		status = udc->driver->setup(&udc->gadget, &pkt.r);
+		spin_lock(&udc->lock);
+	}
+	else
+		status = -ENODEV;
+	if (status < 0) {
+stall:
+		VDBG("req %02x.%02x protocol STALL; stat %d\n",
+				pkt.r.bRequestType, pkt.r.bRequest, status);
+		csr |= AT91_UDP_FORCESTALL;
+		__raw_writel(csr, creg);
+		udc->req_pending = 0;
+	}
+	return;
+
+succeed:
+	/* immediate successful (IN) STATUS after zero length DATA */
+	PACKET("ep0 in/status\n");
+write_in:
+	csr |= AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	udc->req_pending = 0;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+	struct at91_ep		*ep0 = &udc->ep[0];
+	u32 __iomem		*creg = ep0->creg;
+	u32			csr = __raw_readl(creg);
+	struct at91_request	*req;
+
+	if (unlikely(csr & AT91_UDP_STALLSENT)) {
+		nuke(ep0, -EPROTO);
+		udc->req_pending = 0;
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+		__raw_writel(csr, creg);
+		VDBG("ep0 stalled\n");
+		csr = __raw_readl(creg);
+	}
+	if (csr & AT91_UDP_RXSETUP) {
+		nuke(ep0, 0);
+		udc->req_pending = 0;
+		handle_setup(udc, ep0, csr);
+		return;
+	}
+
+	if (list_empty(&ep0->queue))
+		req = NULL;
+	else
+		req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+	/* host ACKed an IN packet that we sent */
+	if (csr & AT91_UDP_TXCOMP) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+		/* write more IN DATA? */
+		if (req && ep0->is_in) {
+			if (handle_ep(ep0))
+				udc->req_pending = 0;
+
+		/*
+		 * Ack after:
+		 *  - last IN DATA packet (including GET_STATUS)
+		 *  - IN/STATUS for OUT DATA
+		 *  - IN/STATUS for any zero-length DATA stage
+		 * except for the IN DATA case, the host should send
+		 * an OUT status later, which we'll ack.
+		 */
+		} else {
+			udc->req_pending = 0;
+			__raw_writel(csr, creg);
+
+			/*
+			 * SET_ADDRESS takes effect only after the STATUS
+			 * (to the original address) gets acked.
+			 */
+			if (udc->wait_for_addr_ack) {
+				u32	tmp;
+
+				at91_udp_write(udc, AT91_UDP_FADDR,
+						AT91_UDP_FEN | udc->addr);
+				tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+				tmp &= ~AT91_UDP_FADDEN;
+				if (udc->addr)
+					tmp |= AT91_UDP_FADDEN;
+				at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+
+				udc->wait_for_addr_ack = 0;
+				VDBG("address %d\n", udc->addr);
+			}
+		}
+	}
+
+	/* OUT packet arrived ... */
+	else if (csr & AT91_UDP_RX_DATA_BK0) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+		/* OUT DATA stage */
+		if (!ep0->is_in) {
+			if (req) {
+				if (handle_ep(ep0)) {
+					/* send IN/STATUS */
+					PACKET("ep0 in/status\n");
+					csr = __raw_readl(creg);
+					csr &= ~SET_FX;
+					csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+					__raw_writel(csr, creg);
+					udc->req_pending = 0;
+				}
+			} else if (udc->req_pending) {
+				/*
+				 * AT91 hardware has a hard time with this
+				 * "deferred response" mode for control-OUT
+				 * transfers.  (For control-IN it's fine.)
+				 *
+				 * The normal solution leaves OUT data in the
+				 * fifo until the gadget driver is ready.
+				 * We couldn't do that here without disabling
+				 * the IRQ that tells about SETUP packets,
+				 * e.g. when the host gets impatient...
+				 *
+				 * Working around it by copying into a buffer
+				 * would almost be a non-deferred response,
+				 * except that it wouldn't permit reliable
+				 * stalling of the request.  Instead, demand
+				 * that gadget drivers not use this mode.
+				 */
+				DBG("no control-OUT deferred responses!\n");
+				__raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+				udc->req_pending = 0;
+			}
+
+		/* STATUS stage for control-IN; ack.  */
+		} else {
+			PACKET("ep0 out/status ACK\n");
+			__raw_writel(csr, creg);
+
+			/* "early" status stage */
+			if (req)
+				done(ep0, req, 0);
+		}
+	}
+}
+
+static irqreturn_t at91_udc_irq(struct at91_udc *udc)
+{
+	u32			rescans = 5;
+	int			disable_clock = 0;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!udc->clocked) {
+		clk_on(udc);
+		disable_clock = 1;
+	}
+
+	while (rescans--) {
+		u32 status;
+
+		status = at91_udp_read(udc, AT91_UDP_ISR)
+			& at91_udp_read(udc, AT91_UDP_IMR);
+		if (!status)
+			break;
+
+		/* USB reset irq:  not maskable */
+		if (status & AT91_UDP_ENDBUSRES) {
+			at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+			at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+			/* Atmel code clears this irq twice */
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			VDBG("end bus reset\n");
+			udc->addr = 0;
+			reset_gadget(udc);
+
+			/* enable ep0 */
+			at91_udp_write(udc, AT91_UDP_CSR(0),
+					AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+			udc->gadget.speed = USB_SPEED_FULL;
+			udc->suspended = 0;
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
+
+			/*
+			 * NOTE:  this driver keeps clocks off unless the
+			 * USB host is present.  That saves power, but for
+			 * boards that don't support VBUS detection, both
+			 * clocks need to be active most of the time.
+			 */
+
+		/* host initiated suspend (3+ms bus idle) */
+		} else if (status & AT91_UDP_RXSUSP) {
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
+			/* VDBG("bus suspend\n"); */
+			if (udc->suspended)
+				continue;
+			udc->suspended = 1;
+
+			/*
+			 * NOTE:  when suspending a VBUS-powered device, the
+			 * gadget driver should switch into slow clock mode
+			 * and then into standby to avoid drawing more than
+			 * 500uA power (2500uA for some high-power configs).
+			 */
+			if (udc->driver && udc->driver->suspend) {
+				spin_unlock(&udc->lock);
+				udc->driver->suspend(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
+
+		/* host initiated resume */
+		} else if (status & AT91_UDP_RXRSM) {
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+			/* VDBG("bus resume\n"); */
+			if (!udc->suspended)
+				continue;
+			udc->suspended = 0;
+
+			/*
+			 * NOTE:  for a VBUS-powered device, the gadget driver
+			 * would normally want to switch out of slow clock
+			 * mode into normal mode.
+			 */
+			if (udc->driver && udc->driver->resume) {
+				spin_unlock(&udc->lock);
+				udc->driver->resume(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
+
+		/* endpoint IRQs are cleared by handling them */
+		} else {
+			int		i;
+			unsigned	mask = 1;
+			struct at91_ep	*ep = &udc->ep[1];
+
+			if (status & mask)
+				handle_ep0(udc);
+			for (i = 1; i < NUM_ENDPOINTS; i++) {
+				mask <<= 1;
+				if (status & mask)
+					handle_ep(ep);
+				ep++;
+			}
+		}
+	}
+
+	if (disable_clock)
+		clk_off(udc);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+
+	udc->driver = driver;
+	udc->enabled = 1;
+	udc->selfpowered = 1;
+
+	return 0;
+}
+
+static int at91_stop(struct usb_gadget *gadget)
+{
+	struct at91_udc *udc = controller;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->enabled = 0;
+	at91_udp_write(udc, AT91_UDP_IDR, ~0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	udc->driver = NULL;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91rm9200_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int ret;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+		case 3:
+			ep->maxpacket = 8;
+			break;
+		case 1 ... 2:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	ret = gpio_request(udc->board.pullup_pin, "udc_pullup");
+	if (ret) {
+		DBG("D+ pullup is busy\n");
+		return ret;
+	}
+
+	gpio_direction_output(udc->board.pullup_pin,
+			      udc->board.pullup_active_low);
+
+	return 0;
+}
+
+static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	int active = !udc->board.pullup_active_low;
+
+	if (is_on)
+		gpio_set_value(udc->board.pullup_pin, active);
+	else
+		gpio_set_value(udc->board.pullup_pin, !active);
+}
+
+static const struct at91_udc_caps at91rm9200_udc_caps = {
+	.init = at91rm9200_udc_init,
+	.pullup = at91rm9200_udc_pullup,
+};
+
+static int at91sam9260_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 512;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
+static void at91sam9260_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+	if (is_on)
+		txvc |= AT91_UDP_TXVC_PUON;
+	else
+		txvc &= ~AT91_UDP_TXVC_PUON;
+
+	at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+}
+
+static const struct at91_udc_caps at91sam9260_udc_caps = {
+	.init = at91sam9260_udc_init,
+	.pullup = at91sam9260_udc_pullup,
+};
+#endif
+
+#if defined(CONFIG_AT91SAM9261)
+static int at91sam9261_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+			ep->maxpacket = 8;
+			break;
+		case 1 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	udc->matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX;
+
+	if (IS_ERR(udc->matrix))
+		return PTR_ERR(udc->matrix);
+
+	return 0;
+}
+
+static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 usbpucr = 0;
+
+	usbpucr = readl(&udc->matrix->pucr);
+	if (is_on)
+		usbpucr |= AT91_MATRIX_USBPUCR_PUON;
+
+	writel(usbpucr, &udc->matrix->pucr);
+}
+
+static const struct at91_udc_caps at91sam9261_udc_caps = {
+	.init = at91sam9261_udc_init,
+	.pullup = at91sam9261_udc_pullup,
+};
+#endif
+
+static int at91sam9263_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+			ep->maxpacket = 64;
+			break;
+		case 4:
+		case 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct at91_udc_caps at91sam9263_udc_caps = {
+	.init = at91sam9263_udc_init,
+	.pullup = at91sam9260_udc_pullup,
+};
+
+int usb_gadget_handle_interrupts(int index)
+{
+	struct at91_udc *udc = controller;
+
+	return at91_udc_irq(udc);
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+	int ret;
+
+	if (!driver || !driver->bind || !driver->setup) {
+		printf("bad paramter\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		printf("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	at91_start(&udc->gadget, driver);
+
+	udc->driver = driver;
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		error("driver->bind() returned %d\n", ret);
+		udc->driver = NULL;
+	}
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+
+	if (!driver || !driver->unbind || !driver->disconnect) {
+		error("bad paramter\n");
+		return -EINVAL;
+	}
+
+	driver->disconnect(&udc->gadget);
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	at91_stop(&udc->gadget);
+
+	return 0;
+}
+
+int at91_udc_probe(struct at91_udc_data *pdata)
+{
+	struct at91_udc	*udc;
+	int		retval;
+	struct at91_ep	*ep;
+	int		i;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	controller = udc;
+	memcpy(&udc->board, pdata, sizeof(struct at91_udc_data));
+	if (udc->board.vbus_pin) {
+		printf("%s: gpio vbus pin not supported yet.\n", __func__);
+		return -ENXIO;
+	} else {
+		DBG("no VBUS detection, assuming always-on\n");
+		udc->vbus = 1;
+	}
+
+#if defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
+	udc->caps = &at91sam9260_udc_caps;
+#endif
+
+	udc->enabled = 0;
+	spin_lock_init(&udc->lock);
+
+	udc->gadget.ops = &at91_udc_ops;
+	udc->gadget.ep0 = &udc->ep[0].ep;
+	udc->gadget.name = driver_name;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+		ep->ep.name = ep_names[i];
+		ep->ep.ops = &at91_ep_ops;
+		ep->udc = udc;
+		ep->int_mask = (1 << i);
+		if (i != 0 && i != 3)
+			ep->is_pingpong = 1;
+	}
+
+	udc->udp_baseaddr = (void *)udc->board.baseaddr;
+	if (IS_ERR(udc->udp_baseaddr))
+		return PTR_ERR(udc->udp_baseaddr);
+
+	if (udc->caps && udc->caps->init) {
+		retval = udc->caps->init(udc);
+		if (retval)
+			return retval;
+	}
+
+	udc_reinit(udc);
+
+	at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+	at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
+	/* Clear all pending interrupts - UDP may be used by bootloader. */
+	at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
+
+	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+	return 0;
+}
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
new file mode 100644
index 0000000..3d8752e
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM	0x00		/* Frame Number Register */
+#define     AT91_UDP_NUM	(0x7ff <<  0)	/* Frame Number */
+#define     AT91_UDP_FRM_ERR	(1     << 16)	/* Frame Error */
+#define     AT91_UDP_FRM_OK	(1     << 17)	/* Frame OK */
+
+#define AT91_UDP_GLB_STAT	0x04		/* Global State Register */
+#define     AT91_UDP_FADDEN	(1 <<  0)	/* Function Address Enable */
+#define     AT91_UDP_CONFG	(1 <<  1)	/* Configured */
+#define     AT91_UDP_ESR	(1 <<  2)	/* Enable Send Resume */
+#define     AT91_UDP_RSMINPR	(1 <<  3)	/* Resume has been sent */
+#define     AT91_UDP_RMWUPE	(1 <<  4)	/* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR		0x08		/* Function Address Register */
+#define     AT91_UDP_FADD	(0x7f << 0)	/* Function Address Value */
+#define     AT91_UDP_FEN	(1    << 8)	/* Function Enable */
+
+#define AT91_UDP_IER		0x10		/* Interrupt Enable Register */
+#define AT91_UDP_IDR		0x14		/* Interrupt Disable Register */
+#define AT91_UDP_IMR		0x18		/* Interrupt Mask Register */
+
+#define AT91_UDP_ISR		0x1c		/* Interrupt Status Register */
+#define     AT91_UDP_EP(n)	(1 << (n))	/* Endpoint Interrupt Status */
+#define     AT91_UDP_RXSUSP	(1 <<  8) 	/* USB Suspend Interrupt Status */
+#define     AT91_UDP_RXRSM	(1 <<  9)	/* USB Resume Interrupt Status */
+#define     AT91_UDP_EXTRSM	(1 << 10)	/* External Resume Interrupt Status [AT91RM9200 only] */
+#define     AT91_UDP_SOFINT	(1 << 11)	/* Start of Frame Interrupt Status */
+#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrupt Status */
+#define     AT91_UDP_WAKEUP	(1 << 13)	/* USB Wakeup Interrupt Status [AT91RM9200 only] */
+
+#define AT91_UDP_ICR		0x20		/* Interrupt Clear Register */
+#define AT91_UDP_RST_EP		0x28		/* Reset Endpoint Register */
+
+#define AT91_UDP_CSR(n)		(0x30+((n)*4))	/* Endpoint Control/Status Registers 0-7 */
+#define     AT91_UDP_TXCOMP	(1 <<  0)	/* Generates IN packet with data previously written in DPR */
+#define     AT91_UDP_RX_DATA_BK0 (1 <<  1)	/* Receive Data Bank 0 */
+#define     AT91_UDP_RXSETUP	(1 <<  2)	/* Send STALL to the host */
+#define     AT91_UDP_STALLSENT	(1 <<  3)	/* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define     AT91_UDP_TXPKTRDY	(1 <<  4)	/* Transmit Packet Ready */
+#define     AT91_UDP_FORCESTALL	(1 <<  5)	/* Force Stall */
+#define     AT91_UDP_RX_DATA_BK1 (1 <<  6)	/* Receive Data Bank 1 */
+#define     AT91_UDP_DIR	(1 <<  7)	/* Transfer Direction */
+#define     AT91_UDP_EPTYPE	(7 <<  8)	/* Endpoint Type */
+#define		AT91_UDP_EPTYPE_CTRL		(0 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_OUT		(1 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_OUT	(2 <<  8)
+#define		AT91_UDP_EPTYPE_INT_OUT		(3 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_IN		(5 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_IN		(6 <<  8)
+#define		AT91_UDP_EPTYPE_INT_IN		(7 <<  8)
+#define     AT91_UDP_DTGLE	(1 << 11)	/* Data Toggle */
+#define     AT91_UDP_EPEDS	(1 << 15)	/* Endpoint Enable/Disable */
+#define     AT91_UDP_RXBYTECNT	(0x7ff << 16)	/* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n)		(0x50+((n)*4))	/* Endpoint FIFO Data Registers 0-7 */
+
+#define AT91_UDP_TXVC		0x74		/* Transceiver Control Register */
+#define     AT91_UDP_TXVC_TXVDIS (1 << 8)	/* Transceiver Disable */
+#define     AT91_UDP_TXVC_PUON   (1 << 9)	/* PullUp On [AT91SAM9260 only] */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define	NUM_ENDPOINTS	6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define	MINIMUS_INTERRUPTUS \
+	(AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+	struct usb_ep			ep;
+	struct list_head		queue;
+	struct at91_udc			*udc;
+	void __iomem			*creg;
+
+	unsigned			maxpacket:16;
+	u8				int_mask;
+	unsigned			is_pingpong:1;
+
+	unsigned			stopped:1;
+	unsigned			is_in:1;
+	unsigned			is_iso:1;
+	unsigned			fifo_bank:1;
+};
+
+struct at91_udc_caps {
+	int (*init)(struct at91_udc *udc);
+	void (*pullup)(struct at91_udc *udc, int is_on);
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+	struct usb_gadget		gadget;
+	struct at91_ep			ep[NUM_ENDPOINTS];
+	struct usb_gadget_driver	*driver;
+	const struct at91_udc_caps	*caps;
+	unsigned			vbus:1;
+	unsigned			enabled:1;
+	unsigned			clocked:1;
+	unsigned			suspended:1;
+	unsigned			req_pending:1;
+	unsigned			wait_for_addr_ack:1;
+	unsigned			wait_for_config_ack:1;
+	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
+	u8				addr;
+	struct at91_udc_data		board;
+	void __iomem			*udp_baseaddr;
+	int				udp_irq;
+	spinlock_t			lock;
+	struct at91_matrix		*matrix;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+	struct usb_request		req;
+	struct list_head		queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef VERBOSE_DEBUG
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		debug("udc: " stuff)
+#define WARNING(stuff...)	debug("udc: " stuff)
+#define INFO(stuff...)		debug("udc: " stuff)
+#define DBG(stuff...)		debug("udc: " stuff)
+
+#endif
+
diff --git a/include/configs/at91-sama5_common.h b/include/configs/at91-sama5_common.h
index de5f12e..3d6b0ae 100644
--- a/include/configs/at91-sama5_common.h
+++ b/include/configs/at91-sama5_common.h
@@ -105,8 +105,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + \
-					sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9260ek.h b/include/configs/at91sam9260ek.h
index 459b8f9..619f5da 100644
--- a/include/configs/at91sam9260ek.h
+++ b/include/configs/at91sam9260ek.h
@@ -256,7 +256,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP		1
 #define CONFIG_CMDLINE_EDITING	1
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9261ek.h b/include/configs/at91sam9261ek.h
index 9c595f2..4d260e9 100644
--- a/include/configs/at91sam9261ek.h
+++ b/include/configs/at91sam9261ek.h
@@ -203,7 +203,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9263ek.h b/include/configs/at91sam9263ek.h
index 3eb0154..2f251db 100644
--- a/include/configs/at91sam9263ek.h
+++ b/include/configs/at91sam9263ek.h
@@ -332,7 +332,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP		1
 #define CONFIG_CMDLINE_EDITING		1
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9m10g45ek.h b/include/configs/at91sam9m10g45ek.h
index 2f6a3a5..70eaf1d 100644
--- a/include/configs/at91sam9m10g45ek.h
+++ b/include/configs/at91sam9m10g45ek.h
@@ -183,7 +183,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h
index acdd63e..44f821b 100644
--- a/include/configs/at91sam9n12ek.h
+++ b/include/configs/at91sam9n12ek.h
@@ -223,8 +223,6 @@
 
 #define CONFIG_SYS_CBSIZE	256
 #define CONFIG_SYS_MAXARGS	16
-#define CONFIG_SYS_PBSIZE	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) \
-					+ 16)
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9rlek.h b/include/configs/at91sam9rlek.h
index f7a174e..cba927a 100644
--- a/include/configs/at91sam9rlek.h
+++ b/include/configs/at91sam9rlek.h
@@ -186,7 +186,6 @@
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
-#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_LONGHELP		1
 #define CONFIG_CMDLINE_EDITING		1
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/at91sam9x5ek.h b/include/configs/at91sam9x5ek.h
index fbb584d..2068e0d 100644
--- a/include/configs/at91sam9x5ek.h
+++ b/include/configs/at91sam9x5ek.h
@@ -225,8 +225,6 @@
 
 #define CONFIG_SYS_CBSIZE	256
 #define CONFIG_SYS_MAXARGS	16
-#define CONFIG_SYS_PBSIZE	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) \
-					+ 16)
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
diff --git a/include/configs/chromebox_panther.h b/include/configs/chromebox_panther.h
index 00fe26d..dc732b8 100644
--- a/include/configs/chromebox_panther.h
+++ b/include/configs/chromebox_panther.h
@@ -14,4 +14,6 @@
 /* Avoid a warning in the Realtek Ethernet driver */
 #define CONFIG_SYS_CACHELINE_SIZE 16
 
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+
 #endif	/* __CONFIG_H */
diff --git a/include/configs/corvus.h b/include/configs/corvus.h
index c91e289..6805612 100644
--- a/include/configs/corvus.h
+++ b/include/configs/corvus.h
@@ -15,6 +15,7 @@
 #define __CONFIG_H
 
 #include <asm/hardware.h>
+#include <linux/sizes.h>
 
 #define CONFIG_SYS_GENERIC_BOARD
 /*
@@ -81,7 +82,7 @@
 #define CONFIG_SYS_SDRAM_SIZE		0x08000000
 
 #define CONFIG_SYS_INIT_SP_ADDR \
-	(CONFIG_SYS_SDRAM_BASE + 4 * 1024 - GENERATED_GBL_DATA_SIZE)
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
 
 /* No NOR flash */
 #define CONFIG_SYS_NO_FLASH
@@ -113,13 +114,37 @@
 #define CONFIG_DOS_PARTITION
 #define CONFIG_USB_STORAGE
 
-#define CONFIG_SYS_LOAD_ADDR		0x72000000	/* load address */
+/* USB DFU support */
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_DUALSPEED
+#define CONFIG_USB_GADGET_ATMEL_USBA
+
+/* DFU class support */
+#define CONFIG_CMD_DFU
+#define CONFIG_USB_FUNCTION_DFU
+#define CONFIG_DFU_NAND
+#define CONFIG_USB_GADGET_DOWNLOAD
+#define CONFIG_USB_GADGET_VBUS_DRAW	2
+#define CONFIG_SYS_DFU_DATA_BUF_SIZE	(SZ_1M)
+#define DFU_MANIFEST_POLL_TIMEOUT	25000
+
+/* USB DFU IDs */
+#define CONFIG_G_DNL_VENDOR_NUM 0x0908
+#define CONFIG_G_DNL_PRODUCT_NUM 0x02d2
+#define CONFIG_G_DNL_MANUFACTURER "Siemens AG"
+
+#define CONFIG_SYS_CACHELINE_SIZE	SZ_8K
+#define CONFIG_SYS_LOAD_ADDR	ATMEL_BASE_CS6
 
 /* bootstrap + u-boot + env in nandflash */
 #define CONFIG_ENV_IS_IN_NAND
 #define CONFIG_ENV_OFFSET		0x100000
 #define CONFIG_ENV_OFFSET_REDUND	0x180000
-#define CONFIG_ENV_SIZE			0x20000
+#define CONFIG_ENV_SIZE			SZ_128K
 
 #define CONFIG_BOOTCOMMAND						\
 	"nand read 0x70000000 0x200000 0x300000;"			\
@@ -146,15 +171,16 @@
  * Size of malloc() pool
  */
 #define CONFIG_SYS_MALLOC_LEN	ROUND(3 * CONFIG_ENV_SIZE + \
-				128*1024, 0x1000)
+				SZ_4M, 0x1000)
+
 /* Defines for SPL */
 #define CONFIG_SPL_FRAMEWORK
 #define CONFIG_SPL_TEXT_BASE		0x300000
-#define CONFIG_SPL_MAX_SIZE		(12 * 1024)
-#define CONFIG_SPL_STACK		(16 * 1024)
+#define CONFIG_SPL_MAX_SIZE		(12 * SZ_1K)
+#define CONFIG_SPL_STACK		(SZ_16K)
 
 #define CONFIG_SPL_BSS_START_ADDR	CONFIG_SPL_MAX_SIZE
-#define CONFIG_SPL_BSS_MAX_SIZE		(2 * 1024)
+#define CONFIG_SPL_BSS_MAX_SIZE		(SZ_2K)
 
 #define CONFIG_SPL_LIBCOMMON_SUPPORT
 #define CONFIG_SPL_LIBGENERIC_SUPPORT
@@ -174,8 +200,8 @@
 #define CONFIG_SYS_NAND_U_BOOT_DST	CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_5_ADDR_CYCLE
 
-#define CONFIG_SYS_NAND_PAGE_SIZE	2048
-#define CONFIG_SYS_NAND_BLOCK_SIZE	(128*1024)
+#define CONFIG_SYS_NAND_PAGE_SIZE	SZ_2K
+#define CONFIG_SYS_NAND_BLOCK_SIZE	(SZ_128K)
 #define CONFIG_SYS_NAND_PAGE_COUNT	(CONFIG_SYS_NAND_BLOCK_SIZE / \
 					 CONFIG_SYS_NAND_PAGE_SIZE)
 #define CONFIG_SYS_NAND_BAD_BLOCK_POS	NAND_LARGE_BADBLOCK_POS
diff --git a/include/configs/crownbay.h b/include/configs/crownbay.h
index 998da78..3153a74 100644
--- a/include/configs/crownbay.h
+++ b/include/configs/crownbay.h
@@ -49,10 +49,6 @@
 #define CONFIG_MMC_SDMA
 #define CONFIG_CMD_MMC
 
-/* Topcliff Gigabit Ethernet */
-#define CONFIG_PCH_GBE
-#define CONFIG_PHYLIB
-
 /* Environment configuration */
 #define CONFIG_ENV_SECT_SIZE		0x1000
 #define CONFIG_ENV_OFFSET		0
diff --git a/include/configs/galileo.h b/include/configs/galileo.h
index 3c3c6e9..b7ec279 100644
--- a/include/configs/galileo.h
+++ b/include/configs/galileo.h
@@ -20,18 +20,6 @@
 /* ns16550 UART is memory-mapped in Quark SoC */
 #undef  CONFIG_SYS_NS16550_PORT_MAPPED
 
-#define CONFIG_PCI_MEM_BUS		0x90000000
-#define CONFIG_PCI_MEM_PHYS		CONFIG_PCI_MEM_BUS
-#define CONFIG_PCI_MEM_SIZE		0x20000000
-
-#define CONFIG_PCI_PREF_BUS		0xb0000000
-#define CONFIG_PCI_PREF_PHYS		CONFIG_PCI_PREF_BUS
-#define CONFIG_PCI_PREF_SIZE		0x20000000
-
-#define CONFIG_PCI_IO_BUS		0x2000
-#define CONFIG_PCI_IO_PHYS		CONFIG_PCI_IO_BUS
-#define CONFIG_PCI_IO_SIZE		0xe000
-
 #define CONFIG_SYS_EARLY_PCI_INIT
 #define CONFIG_PCI_PNP
 
diff --git a/include/configs/meesc.h b/include/configs/meesc.h
index e5bb873..ab6c910 100644
--- a/include/configs/meesc.h
+++ b/include/configs/meesc.h
@@ -56,6 +56,8 @@
 #define CONFIG_DISPLAY_CPUINFO			/* display cpu info and speed */
 #define CONFIG_PREBOOT				/* enable preboot variable */
 
+#define CONFIG_SYS_GENERIC_BOARD
+
 /*
  * Hardware drivers
  */
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 6965d92..32e3a9b 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -187,7 +187,8 @@
 
 #define SANDBOX_ETH_SETTINGS		"ethaddr=00:00:11:22:33:44\0" \
 					"eth1addr=00:00:11:22:33:45\0" \
-					"eth5addr=00:00:11:22:33:46\0" \
+					"eth3addr=00:00:11:22:33:46\0" \
+					"eth5addr=00:00:11:22:33:47\0" \
 					"ipaddr=1.2.3.4\0"
 
 #define MEM_LAYOUT_ENV_SETTINGS \
diff --git a/include/configs/smartweb.h b/include/configs/smartweb.h
index d696d4b..d189c3f 100644
--- a/include/configs/smartweb.h
+++ b/include/configs/smartweb.h
@@ -28,6 +28,7 @@
  * In this case SoC is defined in boards.cfg.
  */
 #include <asm/hardware.h>
+#include <linux/sizes.h>
 
 /*
  * Warning: changing CONFIG_SYS_TEXT_BASE requires adapting the initial boot
@@ -64,7 +65,7 @@
  */
 #define CONFIG_NR_DRAM_BANKS		1
 #define CONFIG_SYS_SDRAM_BASE		ATMEL_BASE_CS1
-#define CONFIG_SYS_SDRAM_SIZE		(64 << 20)
+#define CONFIG_SYS_SDRAM_SIZE		(64 * SZ_1M)
 
 /*
  * Perform a SDRAM Memtest from the start of SDRAM
@@ -75,7 +76,7 @@
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN \
-	ROUND(3 * CONFIG_ENV_SIZE + (128 << 10), 0x1000)
+	ROUND(3 * CONFIG_ENV_SIZE + (4 * SZ_1M), 0x1000)
 
 /* NAND flash settings */
 #define CONFIG_NAND_ATMEL
@@ -140,15 +141,42 @@
 
 #if !defined(CONFIG_SPL_BUILD)
 /* USB configuration */
+#define CONFIG_CMD_USB
 #define CONFIG_USB_ATMEL
 #define CONFIG_USB_ATMEL_CLK_SEL_PLLB
 #define CONFIG_USB_OHCI_NEW
-#define CONFIG_USB_STORAGE
-#define CONFIG_DOS_PARTITION
 #define CONFIG_SYS_USB_OHCI_CPU_INIT
 #define CONFIG_SYS_USB_OHCI_REGS_BASE	ATMEL_UHP_BASE
 #define CONFIG_SYS_USB_OHCI_SLOT_NAME	"at91sam9260"
 #define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS	2
+
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_MCS7830
+
+/* USB DFU support */
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_AT91
+
+/* DFU class support */
+#define CONFIG_CMD_DFU
+#define CONFIG_USB_FUNCTION_DFU
+#define CONFIG_DFU_NAND
+#define CONFIG_USB_GADGET_DOWNLOAD
+#define CONFIG_USB_GADGET_VBUS_DRAW	2
+#define CONFIG_SYS_DFU_DATA_BUF_SIZE	SZ_1M
+#define DFU_MANIFEST_POLL_TIMEOUT	25000
+
+/* USB DFU IDs */
+#define CONFIG_G_DNL_VENDOR_NUM 0x0908
+#define CONFIG_G_DNL_PRODUCT_NUM 0x02d2
+#define CONFIG_G_DNL_MANUFACTURER "Siemens AG"
+
+#define CONFIG_SYS_CACHELINE_SIZE	0x2000
 #endif
 
 /* General Boot Parameter */
@@ -173,8 +201,8 @@
 #define CONFIG_ENV_IS_IN_NAND
 #define CONFIG_ENV_OFFSET		(0x100000)
 #define CONFIG_ENV_OFFSET_REDUND	(0x180000)
-#define CONFIG_ENV_RANGE		(0x80000)
-#define CONFIG_ENV_SIZE			(0x20000)
+#define CONFIG_ENV_RANGE		(SZ_512K)
+#define CONFIG_ENV_SIZE			(SZ_128K)
 
 /*
  * Predefined environment variables.
@@ -193,7 +221,6 @@
 #undef CONFIG_CMD_LOADS
 
 #define CONFIG_CMD_NAND
-#define CONFIG_CMD_USB
 #define CONFIG_CMD_FAT
 
 #ifdef CONFIG_MACB
@@ -230,10 +257,10 @@
 /* Defines for SPL */
 #define CONFIG_SPL_FRAMEWORK
 #define CONFIG_SPL_TEXT_BASE		0x0
-#define CONFIG_SPL_MAX_SIZE		(4 * 1024)
+#define CONFIG_SPL_MAX_SIZE		(SZ_4K)
 
 #define CONFIG_SPL_BSS_START_ADDR	CONFIG_SYS_SDRAM_BASE
-#define CONFIG_SPL_BSS_MAX_SIZE		(16 * 1024)
+#define CONFIG_SPL_BSS_MAX_SIZE		(SZ_16K)
 #define CONFIG_SYS_SPL_MALLOC_START     (CONFIG_SPL_BSS_START_ADDR + \
 					CONFIG_SPL_BSS_MAX_SIZE)
 #define CONFIG_SYS_SPL_MALLOC_SIZE      CONFIG_SYS_MALLOC_LEN
@@ -253,14 +280,14 @@
 #define CONFIG_SPL_NAND_RAW_ONLY
 #define CONFIG_SPL_NAND_SOFTECC
 #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x20000
-#define CONFIG_SYS_NAND_U_BOOT_SIZE	0x80000
+#define CONFIG_SYS_NAND_U_BOOT_SIZE	SZ_512K
 #define	CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_DST	CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_5_ADDR_CYCLE
 
-#define CONFIG_SYS_NAND_SIZE		(256*1024*1024)
-#define CONFIG_SYS_NAND_PAGE_SIZE	2048
-#define CONFIG_SYS_NAND_BLOCK_SIZE	(128*1024)
+#define CONFIG_SYS_NAND_SIZE		(SZ_256M)
+#define CONFIG_SYS_NAND_PAGE_SIZE	SZ_2K
+#define CONFIG_SYS_NAND_BLOCK_SIZE	(SZ_128K)
 #define CONFIG_SYS_NAND_PAGE_COUNT	(CONFIG_SYS_NAND_BLOCK_SIZE / \
 					 CONFIG_SYS_NAND_PAGE_SIZE)
 #define CONFIG_SYS_NAND_BAD_BLOCK_POS	NAND_LARGE_BADBLOCK_POS
diff --git a/include/configs/taurus.h b/include/configs/taurus.h
index 2c9f5da..12994c8 100644
--- a/include/configs/taurus.h
+++ b/include/configs/taurus.h
@@ -20,6 +20,7 @@
  * In this case SoC is defined in boards.cfg.
  */
 #include <asm/hardware.h>
+#include <linux/sizes.h>
 
 #define CONFIG_SYS_GENERIC_BOARD
 
@@ -80,14 +81,14 @@
  */
 #define CONFIG_NR_DRAM_BANKS		1
 #define CONFIG_SYS_SDRAM_BASE		ATMEL_BASE_CS1
-#define CONFIG_SYS_SDRAM_SIZE		(128 * 1024 * 1024)
+#define CONFIG_SYS_SDRAM_SIZE		(128 * SZ_1M)
 
 /*
  * Initial stack pointer: 4k - GENERATED_GBL_DATA_SIZE in internal SRAM,
  * leaving the correct space for initial global data structure above
  * that address while providing maximum stack area below.
  */
-# define CONFIG_SYS_INIT_SP_ADDR \
+#define CONFIG_SYS_INIT_SP_ADDR \
 	(ATMEL_BASE_SRAM1 + 0x1000 - GENERATED_GBL_DATA_SIZE)
 
 /* NAND flash */
@@ -111,6 +112,7 @@
 #define CONFIG_AT91_WANTS_COMMON_PHY
 
 #define CONFIG_AT91SAM9_WATCHDOG
+#define CONFIG_AT91_HW_WDT_TIMEOUT	15
 #if !defined(CONFIG_SPL_BUILD)
 /* Enable the watchdog */
 #define CONFIG_HW_WATCHDOG
@@ -119,12 +121,38 @@
 /* USB */
 #if defined(CONFIG_BOARD_TAURUS)
 #define CONFIG_USB_ATMEL
+#define CONFIG_USB_ATMEL_CLK_SEL_PLLB
 #define CONFIG_USB_OHCI_NEW
 #define CONFIG_SYS_USB_OHCI_CPU_INIT
 #define CONFIG_SYS_USB_OHCI_REGS_BASE		0x00500000
 #define CONFIG_SYS_USB_OHCI_SLOT_NAME		"at91sam9260"
 #define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS	2
 #define CONFIG_USB_STORAGE
+
+/* USB DFU support */
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_AT91
+
+/* DFU class support */
+#define CONFIG_CMD_USB
+#define CONFIG_CMD_DFU
+#define CONFIG_USB_FUNCTION_DFU
+#define CONFIG_DFU_NAND
+#define CONFIG_USB_GADGET_DOWNLOAD
+#define CONFIG_USB_GADGET_VBUS_DRAW	2
+#define CONFIG_SYS_DFU_DATA_BUF_SIZE	(SZ_1M)
+#define DFU_MANIFEST_POLL_TIMEOUT	25000
+
+/* USB DFU IDs */
+#define CONFIG_G_DNL_VENDOR_NUM 0x0908
+#define CONFIG_G_DNL_PRODUCT_NUM 0x02d2
+#define CONFIG_G_DNL_MANUFACTURER "Siemens AG"
+
+#define CONFIG_SYS_CACHELINE_SIZE	SZ_8K
 #endif
 
 /* SPI EEPROM */
@@ -145,8 +173,8 @@
 #define CONFIG_SYS_SPI_U_BOOT_OFFS	0x20000
 
 #define CONFIG_SF_DEFAULT_BUS 0
-#define CONFIG_SF_DEFAULT_SPEED 10000000
-#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0
+#define CONFIG_SF_DEFAULT_SPEED 1000000
+#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
 #endif
 
 /* load address */
@@ -156,14 +184,77 @@
 #define CONFIG_ENV_IS_IN_NAND
 #define CONFIG_ENV_OFFSET		0x100000
 #define CONFIG_ENV_OFFSET_REDUND	0x180000
-#define CONFIG_ENV_SIZE		0x20000		/* 1 sector = 128 kB */
+#define CONFIG_ENV_SIZE		(SZ_128K)	/* 1 sector = 128 kB */
 #define CONFIG_BOOTCOMMAND	"nand read 0x22000000 0x200000 0x300000; bootm"
-#define CONFIG_BOOTARGS							\
+
+#if defined(CONFIG_BOARD_TAURUS)
+#define	CONFIG_BOOTARGS_TAURUS						\
 	"console=ttyS0,115200 earlyprintk "				\
 	"mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,"		\
 	"256k(env),256k(env_redundant),256k(spare),"			\
 	"512k(dtb),6M(kernel)ro,-(rootfs) "				\
 	"root=/dev/mtdblock7 rw rootfstype=jffs2"
+#endif
+
+#if defined(CONFIG_BOARD_AXM)
+#define CONFIG_BOOTARGS_AXM						\
+	"\0"	\
+	"addip=setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:"	\
+	"${gatewayip}:${netmask}:${hostname}:${netdev}::off\0"		\
+	"addtest=setenv bootargs ${bootargs} loglevel=4 test\0"		\
+	"baudrate=115200\0"						\
+	"boot_file=setenv bootfile /${project_dir}/kernel/uImage\0"	\
+	"boot_retries=0\0"						\
+	"bootcmd=run flash_self\0"					\
+	"bootdelay=3\0"							\
+	"ethact=macb0\0"						\
+	"flash_nfs=run nand_kernel;run nfsargs;run addip;upgrade_available;"\
+	"bootm ${kernel_ram};reset\0"					\
+	"flash_self=run nand_kernel;run setbootargs;upgrade_available;" \
+	"bootm ${kernel_ram};reset\0"					\
+	"flash_self_test=run nand_kernel;run setbootargs addtest; "	\
+	"upgrade_available;bootm ${kernel_ram};reset\0"			\
+	"hostname=systemone\0"						\
+	"kernel_Off=0x00200000\0"					\
+	"kernel_Off_fallback=0x03800000\0"				\
+	"kernel_ram=0x21500000\0"					\
+	"kernel_size=0x00400000\0"					\
+	"kernel_size_fallback=0x00400000\0"				\
+	"loads_echo=1\0"						\
+	"nand_kernel=nand read.e ${kernel_ram} ${kernel_Off} "		\
+		"${kernel_size}\0"					\
+	"net_nfs=run boot_file;tftp ${kernel_ram} ${bootfile};"		\
+	"run nfsargs;run addip;upgrade_available;bootm "		\
+		"${kernel_ram};reset\0"					\
+	"netdev=eth0\0"							\
+	"nfsargs=run root_path;setenv bootargs ${bootargs} "		\
+	"root=/dev/nfs rw nfsroot=${serverip}:${rootpath} "		\
+	"at91sam9_wdt.wdt_timeout=16\0"					\
+	"partitionset_active=A\0"					\
+	"preboot=echo;echo Type 'run flash_self' to use kernel and root "\
+	"filesystem on memory;echo Type 'run flash_nfs' to use kernel "	\
+	"from memory and root filesystem over NFS;echo Type 'run net_nfs' "\
+	"to get Kernel over TFTP and mount root filesystem over NFS;echo\0"\
+	"project_dir=systemone\0"					\
+	"root_path=setenv rootpath /home/projects/${project_dir}/rootfs\0"\
+	"rootfs=/dev/mtdblock5\0"					\
+	"rootfs_fallback=/dev/mtdblock7\0"				\
+	"setbootargs=setenv bootargs ${bootargs} console=ttyMTD,mtdoops "\
+		"root=${rootfs} rootfstype=jffs2 panic=7 "		\
+		"at91sam9_wdt.wdt_timeout=16\0"				\
+	"stderr=serial\0"						\
+	"stdin=serial\0"						\
+	"stdout=serial\0"						\
+	"upgrade_available=0\0"
+#endif
+
+#if defined(CONFIG_BOARD_TAURUS)
+#define CONFIG_BOOTARGS		CONFIG_BOOTARGS_TAURUS
+#endif
+
+#if defined(CONFIG_BOARD_AXM)
+#define CONFIG_BOOTARGS		CONFIG_BOOTARGS_AXM
+#endif
 
 #define CONFIG_SYS_CBSIZE		256
 #define CONFIG_SYS_MAXARGS		16
@@ -177,19 +268,19 @@
  * Size of malloc() pool
  */
 #define CONFIG_SYS_MALLOC_LEN \
-	ROUND(3 * CONFIG_ENV_SIZE + 128*1024, 0x1000)
+	ROUND(3 * CONFIG_ENV_SIZE + SZ_4M, 0x1000)
 
 /* Defines for SPL */
 #define CONFIG_SPL_FRAMEWORK
 #define CONFIG_SPL_TEXT_BASE		0x0
-#define CONFIG_SPL_MAX_SIZE		(14 * 1024)
-#define CONFIG_SPL_STACK		(16 * 1024)
+#define CONFIG_SPL_MAX_SIZE		(31 * SZ_512)
+#define	CONFIG_SPL_STACK		(ATMEL_BASE_SRAM1 + SZ_16K)
 #define CONFIG_SYS_SPL_MALLOC_START     (CONFIG_SYS_TEXT_BASE - \
 					CONFIG_SYS_MALLOC_LEN)
 #define CONFIG_SYS_SPL_MALLOC_SIZE      CONFIG_SYS_MALLOC_LEN
 
 #define CONFIG_SPL_BSS_START_ADDR	CONFIG_SPL_MAX_SIZE
-#define CONFIG_SPL_BSS_MAX_SIZE		(3 * 1024)
+#define CONFIG_SPL_BSS_MAX_SIZE		(3 * SZ_512)
 
 #define CONFIG_SPL_LIBCOMMON_SUPPORT
 #define CONFIG_SPL_LIBGENERIC_SUPPORT
@@ -206,14 +297,14 @@
 #define CONFIG_SPL_NAND_RAW_ONLY
 #define CONFIG_SPL_NAND_SOFTECC
 #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x20000
-#define CONFIG_SYS_NAND_U_BOOT_SIZE	0x80000
+#define CONFIG_SYS_NAND_U_BOOT_SIZE	SZ_512K
 #define	CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_DST	CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_5_ADDR_CYCLE
 
-#define CONFIG_SYS_NAND_SIZE		(256*1024*1024)
-#define CONFIG_SYS_NAND_PAGE_SIZE	2048
-#define CONFIG_SYS_NAND_BLOCK_SIZE	(128*1024)
+#define CONFIG_SYS_NAND_SIZE		(256 * SZ_1M)
+#define CONFIG_SYS_NAND_PAGE_SIZE	SZ_2K
+#define CONFIG_SYS_NAND_BLOCK_SIZE	(SZ_128K)
 #define CONFIG_SYS_NAND_PAGE_COUNT	(CONFIG_SYS_NAND_BLOCK_SIZE / \
 					 CONFIG_SYS_NAND_PAGE_SIZE)
 #define CONFIG_SYS_NAND_BAD_BLOCK_POS	NAND_LARGE_BADBLOCK_POS
@@ -232,4 +323,5 @@
 #define CONFIG_SYS_MCKR			0x1300
 #define CONFIG_SYS_MCKR_CSS		(0x02 | CONFIG_SYS_MCKR)
 #define CONFIG_SYS_AT91_PLLB		0x10193F05
+
 #endif
diff --git a/include/linux/usb/at91_udc.h b/include/linux/usb/at91_udc.h
new file mode 100644
index 0000000..cd0d00f
--- /dev/null
+++ b/include/linux/usb/at91_udc.h
@@ -0,0 +1,20 @@
+/*
+ * Platform data definitions for Atmel USBA gadget driver
+ * pieces copied from linux:include/linux/platform_data/atmel.h
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+#ifndef __LINUX_USB_AT91_UDC_H__
+#define __LINUX_USB_AT91_UDC_H__
+
+struct at91_udc_data {
+	int	vbus_pin;		/* high == host powering us */
+	u8	vbus_active_low;	/* vbus polarity */
+	u8	vbus_polled;		/* Use polling, not interrupt */
+	int	pullup_pin;		/* active == D+ pulled up */
+	u8	pullup_active_low;	/* true == pullup_pin is active low */
+	unsigned long	baseaddr;
+};
+
+int at91_udc_probe(struct at91_udc_data *pdata);
+#endif /* __LINUX_USB_AT91_UDC_H__ */
diff --git a/include/netdev.h b/include/netdev.h
index 662d173..3d5a54f 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -70,7 +70,6 @@
 int ne2k_register(void);
 int npe_initialize(bd_t *bis);
 int ns8382x_initialize(bd_t *bis);
-int pch_gbe_register(bd_t *bis);
 int pcnet_initialize(bd_t *bis);
 int ppc_4xx_eth_initialize (bd_t *bis);
 int rtl8139_initialize(bd_t *bis);
@@ -123,9 +122,6 @@
 #ifdef CONFIG_E1000
 	num += e1000_initialize(bis);
 #endif
-#ifdef CONFIG_PCH_GBE
-	num += pch_gbe_register(bis);
-#endif
 #ifdef CONFIG_PCNET
 	num += pcnet_initialize(bis);
 #endif
diff --git a/net/eth.c b/net/eth.c
index d3ec8d6..26520d3 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -107,7 +107,9 @@
 		if (cpu_eth_init(gd->bd) < 0)
 			printf("CPU Net Initialization Failed\n");
 	} else {
+#ifndef CONFIG_DM_ETH
 		printf("Net Initialization Skipped\n");
+#endif
 	}
 }
 
@@ -193,10 +195,11 @@
 	const char *startp = NULL;
 	struct udevice *it;
 	struct uclass *uc;
+	int len = strlen("eth");
 
 	/* Must be longer than 3 to be an alias */
-	if (strlen(devname) > strlen("eth")) {
-		startp = devname + strlen("eth");
+	if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
+		startp = devname + len;
 		seq = simple_strtoul(startp, &endp, 10);
 	}
 
diff --git a/net/tftp.c b/net/tftp.c
index 181f0f3..1a51131 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -19,10 +19,10 @@
 /* Well known TFTP port # */
 #define WELL_KNOWN_PORT	69
 /* Millisecs to timeout for lost pkt */
-#define TIMEOUT		100UL
+#define TIMEOUT		5000UL
 #ifndef	CONFIG_NET_RETRY_COUNT
 /* # of timeouts before giving up */
-# define TIMEOUT_COUNT	1000
+# define TIMEOUT_COUNT	10
 #else
 # define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT * 2)
 #endif
@@ -711,10 +711,10 @@
 	if (ep != NULL)
 		timeout_ms = simple_strtol(ep, NULL, 10);
 
-	if (timeout_ms < 10) {
-		printf("TFTP timeout (%ld ms) too low, set min = 10 ms\n",
+	if (timeout_ms < 1000) {
+		printf("TFTP timeout (%ld ms) too low, set min = 1000 ms\n",
 		       timeout_ms);
-		timeout_ms = 10;
+		timeout_ms = 1000;
 	}
 
 	debug("TFTP blocksize = %i, timeout = %ld ms\n",
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 700abdd..fcfb3e1 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -106,6 +106,11 @@
 	ut_assertok(net_loop(PING));
 	ut_asserteq_str("eth@10004000", getenv("ethact"));
 
+	/* Make sure we can handle device name which is not eth# */
+	setenv("ethact", "sbe5");
+	ut_assertok(net_loop(PING));
+	ut_asserteq_str("sbe5", getenv("ethact"));
+
 	return 0;
 }
 
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index c7d3c86..141bf64 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -103,6 +103,24 @@
     'u-boot.cfg', 'u-boot-spl.cfg', 'u-boot-tpl.cfg'
 ]
 
+class Config:
+    """Holds information about configuration settings for a board."""
+    def __init__(self, target):
+        self.target = target
+        self.config = {}
+        for fname in CONFIG_FILENAMES:
+            self.config[fname] = {}
+
+    def Add(self, fname, key, value):
+        self.config[fname][key] = value
+
+    def __hash__(self):
+        val = 0
+        for fname in self.config:
+            for key, value in self.config[fname].iteritems():
+                print key, value
+                val = val ^ hash(key) & hash(value)
+        return val
 
 class Builder:
     """Class for building U-Boot for a particular commit.
@@ -659,7 +677,8 @@
                 List containing a summary of warning lines
                 Dict keyed by error line, containing a list of the Board
                     objects with that warning
-                Dictionary keyed by filename - e.g. '.config'. Each
+                Dictionary keyed by board.target. Each value is a dictionary:
+                    key: filename - e.g. '.config'
                     value is itself a dictionary:
                         key: config name
                         value: config value
@@ -678,8 +697,6 @@
         warn_lines_summary = []
         warn_lines_boards = {}
         config = {}
-        for fname in CONFIG_FILENAMES:
-            config[fname] = {}
 
         for board in boards_selected.itervalues():
             outcome = self.GetBuildOutcome(commit_upto, board.target,
@@ -709,11 +726,12 @@
                                     line, board)
                         last_was_warning = is_warning
                         last_func = None
+            tconfig = Config(board.target)
             for fname in CONFIG_FILENAMES:
-                config[fname] = {}
                 if outcome.config:
                     for key, value in outcome.config[fname].iteritems():
-                        config[fname][key] = value
+                        tconfig.Add(fname, key, value)
+            config[board.target] = tconfig
 
         return (board_dict, err_lines_summary, err_lines_boards,
                 warn_lines_summary, warn_lines_boards, config)
@@ -774,9 +792,7 @@
         self._base_warn_lines = []
         self._base_err_line_boards = {}
         self._base_warn_line_boards = {}
-        self._base_config = {}
-        for fname in CONFIG_FILENAMES:
-            self._base_config[fname] = {}
+        self._base_config = None
 
     def PrintFuncSizeDetail(self, fname, old, new):
         grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
@@ -1051,12 +1067,14 @@
             out = ''
             for key in sorted(config.keys()):
                 out += '%s=%s ' % (key, config[key])
-            return '%5s %s: %s' % (delta, name, out)
+            return '%s %s: %s' % (delta, name, out)
 
-        def _ShowConfig(name, config_plus, config_minus, config_change):
-            """Show changes in configuration
+        def _AddConfig(lines, name, config_plus, config_minus, config_change):
+            """Add changes in configuration to a list
 
             Args:
+                lines: list to add to
+                name: config file name
                 config_plus: configurations added, dictionary
                     key: config name
                     value: config value
@@ -1068,14 +1086,24 @@
                     value: config value
             """
             if config_plus:
-                Print(_CalcConfig('+', name, config_plus),
-                      colour=self.col.GREEN)
+                lines.append(_CalcConfig('+', name, config_plus))
             if config_minus:
-                Print(_CalcConfig('-', name, config_minus),
-                      colour=self.col.RED)
+                lines.append(_CalcConfig('-', name, config_minus))
             if config_change:
-                Print(_CalcConfig('+/-', name, config_change),
-                      colour=self.col.YELLOW)
+                lines.append(_CalcConfig('c', name, config_change))
+
+        def _OutputConfigInfo(lines):
+            for line in lines:
+                if not line:
+                    continue
+                if line[0] == '+':
+                    col = self.col.GREEN
+                elif line[0] == '-':
+                    col = self.col.RED
+                elif line[0] == 'c':
+                    col = self.col.YELLOW
+                Print('   ' + line, newline=True, colour=col)
+
 
         better = []     # List of boards fixed since last commit
         worse = []      # List of new broken boards since last commit
@@ -1137,34 +1165,104 @@
             self.PrintSizeSummary(board_selected, board_dict, show_detail,
                                   show_bloat)
 
-        if show_config:
-            all_config_plus = {}
-            all_config_minus = {}
-            all_config_change = {}
-            for name in CONFIG_FILENAMES:
-                if not config[name]:
+        if show_config and self._base_config:
+            summary = {}
+            arch_config_plus = {}
+            arch_config_minus = {}
+            arch_config_change = {}
+            arch_list = []
+
+            for target in board_dict:
+                if target not in board_selected:
                     continue
-                config_plus = {}
-                config_minus = {}
-                config_change = {}
-                base = self._base_config[name]
-                for key, value in config[name].iteritems():
-                    if key not in base:
-                        config_plus[key] = value
-                        all_config_plus[key] = value
-                for key, value in base.iteritems():
-                    if key not in config[name]:
-                        config_minus[key] = value
-                        all_config_minus[key] = value
-                for key, value in base.iteritems():
-                    new_value = base[key]
-                    if key in config[name] and value != new_value:
-                        desc = '%s -> %s' % (value, new_value)
-                        config_change[key] = desc
-                        all_config_change[key] = desc
-                _ShowConfig(name, config_plus, config_minus, config_change)
-            _ShowConfig('all', all_config_plus, all_config_minus,
-                        all_config_change)
+                arch = board_selected[target].arch
+                if arch not in arch_list:
+                    arch_list.append(arch)
+
+            for arch in arch_list:
+                arch_config_plus[arch] = {}
+                arch_config_minus[arch] = {}
+                arch_config_change[arch] = {}
+                for name in CONFIG_FILENAMES:
+                    arch_config_plus[arch][name] = {}
+                    arch_config_minus[arch][name] = {}
+                    arch_config_change[arch][name] = {}
+
+            for target in board_dict:
+                if target not in board_selected:
+                    continue
+
+                arch = board_selected[target].arch
+
+                all_config_plus = {}
+                all_config_minus = {}
+                all_config_change = {}
+                tbase = self._base_config[target]
+                tconfig = config[target]
+                lines = []
+                for name in CONFIG_FILENAMES:
+                    if not tconfig.config[name]:
+                        continue
+                    config_plus = {}
+                    config_minus = {}
+                    config_change = {}
+                    base = tbase.config[name]
+                    for key, value in tconfig.config[name].iteritems():
+                        if key not in base:
+                            config_plus[key] = value
+                            all_config_plus[key] = value
+                    for key, value in base.iteritems():
+                        if key not in tconfig.config[name]:
+                            config_minus[key] = value
+                            all_config_minus[key] = value
+                    for key, value in base.iteritems():
+                        new_value = tconfig.config.get(key)
+                        if new_value and value != new_value:
+                            desc = '%s -> %s' % (value, new_value)
+                            config_change[key] = desc
+                            all_config_change[key] = desc
+
+                    arch_config_plus[arch][name].update(config_plus)
+                    arch_config_minus[arch][name].update(config_minus)
+                    arch_config_change[arch][name].update(config_change)
+
+                    _AddConfig(lines, name, config_plus, config_minus,
+                               config_change)
+                _AddConfig(lines, 'all', all_config_plus, all_config_minus,
+                           all_config_change)
+                summary[target] = '\n'.join(lines)
+
+            lines_by_target = {}
+            for target, lines in summary.iteritems():
+                if lines in lines_by_target:
+                    lines_by_target[lines].append(target)
+                else:
+                    lines_by_target[lines] = [target]
+
+            for arch in arch_list:
+                lines = []
+                all_plus = {}
+                all_minus = {}
+                all_change = {}
+                for name in CONFIG_FILENAMES:
+                    all_plus.update(arch_config_plus[arch][name])
+                    all_minus.update(arch_config_minus[arch][name])
+                    all_change.update(arch_config_change[arch][name])
+                    _AddConfig(lines, name, arch_config_plus[arch][name],
+                               arch_config_minus[arch][name],
+                               arch_config_change[arch][name])
+                _AddConfig(lines, 'all', all_plus, all_minus, all_change)
+                #arch_summary[target] = '\n'.join(lines)
+                if lines:
+                    Print('%s:' % arch)
+                    _OutputConfigInfo(lines)
+
+            for lines, targets in lines_by_target.iteritems():
+                if not lines:
+                    continue
+                Print('%s :' % ' '.join(sorted(targets)))
+                _OutputConfigInfo(lines.split('\n'))
+
 
         # Save our updated information for the next call to this function
         self._base_board_dict = board_dict
diff --git a/tools/ifdtool.c b/tools/ifdtool.c
index 1f95203..48059c0 100644
--- a/tools/ifdtool.c
+++ b/tools/ifdtool.c
@@ -707,10 +707,12 @@
  *			8MB ROM the start address is 0xfff80000.
  * @write_fname:	Filename to add to the image
  * @offset_uboot_top:	Offset of the top of U-Boot
+ * @offset_uboot_start:	Offset of the start of U-Boot
  * @return number of bytes written if OK, -ve on error
  */
 static int write_data(char *image, int size, unsigned int addr,
-		      const char *write_fname, int offset_uboot_top)
+		      const char *write_fname, int offset_uboot_top,
+		      int offset_uboot_start)
 {
 	int write_fd, write_size;
 	int offset;
@@ -720,13 +722,25 @@
 		return write_fd;
 
 	offset = (uint32_t)(addr + size);
-	if (offset_uboot_top && offset_uboot_top >= offset) {
-		fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
-			write_fname);
-		fprintf(stderr,
-			"U-Boot finishes at offset %x, file starts at %x\n",
-			offset_uboot_top, offset);
-		return -EXDEV;
+	if (offset_uboot_top) {
+		if (offset_uboot_start < offset &&
+		    offset_uboot_top >= offset) {
+			fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+				write_fname);
+			fprintf(stderr,
+				"U-Boot finishes at offset %x, file starts at %x\n",
+				offset_uboot_top, offset);
+			return -EXDEV;
+		}
+		if (offset_uboot_start > offset &&
+		    offset_uboot_start <= offset + write_size) {
+			fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+				write_fname);
+			fprintf(stderr,
+				"U-Boot starts at offset %x, file finishes at %x\n",
+				offset_uboot_start, offset + write_size);
+			return -EXDEV;
+		}
 	}
 	debug("Writing %s to offset %#x\n", write_fname, offset);
 
@@ -927,27 +941,36 @@
  */
 static int write_uboot(char *image, int size, struct input_file *uboot,
 		       struct input_file *fdt, unsigned int ucode_ptr,
-		       int collate_ucode)
+		       int collate_ucode, int *offset_uboot_top,
+		       int *offset_uboot_start)
 {
-	const void *blob;
 	int uboot_size, fdt_size;
+	int uboot_top;
 
-	uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0);
+	uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0, 0);
 	if (uboot_size < 0)
 		return uboot_size;
 	fdt->addr = uboot->addr + uboot_size;
 	debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr);
-	fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0);
+	fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0, 0);
 	if (fdt_size < 0)
 		return fdt_size;
-	blob = (void *)image + (uint32_t)(fdt->addr + size);
+
+	uboot_top = (uint32_t)(fdt->addr + size) + fdt_size;
 
 	if (ucode_ptr) {
-		return write_ucode(image, size, fdt, fdt_size, ucode_ptr,
-				   collate_ucode);
+		uboot_top = write_ucode(image, size, fdt, fdt_size, ucode_ptr,
+					collate_ucode);
+		if (uboot_top < 0)
+			return uboot_top;
 	}
 
-	return ((char *)blob + fdt_size) - image;
+	if (offset_uboot_top && offset_uboot_start) {
+		*offset_uboot_top = uboot_top;
+		*offset_uboot_start = (uint32_t)(uboot->addr + size);
+	}
+
+	return 0;
 }
 
 static void print_version(void)
@@ -1268,13 +1291,14 @@
 	}
 
 	if (mode_write_descriptor)
-		ret = write_data(image, size, -size, desc_fname, 0);
+		ret = write_data(image, size, -size, desc_fname, 0, 0);
 
 	if (mode_inject)
 		ret = inject_region(image, size, region_type, inject_fname);
 
 	if (mode_write) {
 		int offset_uboot_top = 0;
+		int offset_uboot_start = 0;
 
 		for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
 			ifile = &input_file[wr_idx];
@@ -1282,11 +1306,13 @@
 				continue;
 			} else if (ifile->type == IF_uboot) {
 				ret = write_uboot(image, size, ifile, fdt,
-						  ucode_ptr, collate_ucode);
-				offset_uboot_top = ret;
+						  ucode_ptr, collate_ucode,
+						  &offset_uboot_top,
+						  &offset_uboot_start);
 			} else {
 				ret = write_data(image, size, ifile->addr,
-					 ifile->fname, offset_uboot_top);
+						 ifile->fname, offset_uboot_top,
+						 offset_uboot_start);
 			}
 			if (ret < 0)
 				break;
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
index 67b086b..9e739d8 100644
--- a/tools/patman/gitutil.py
+++ b/tools/patman/gitutil.py
@@ -264,7 +264,7 @@
     """
     if series.get('version'):
         version = '%s ' % series['version']
-    cmd = ['git', 'format-patch', '-D', '-M', '--signoff']
+    cmd = ['git', 'format-patch', '-M', '--signoff']
     if series.get('cover'):
         cmd.append('--cover-letter')
     prefix = series.GetPatchPrefix()