Merge branch 'zynq' of git://www.denx.de/git/u-boot-microblaze
diff --git a/Makefile b/Makefile
index 5d824ae..9447aa7 100644
--- a/Makefile
+++ b/Makefile
@@ -1335,6 +1335,9 @@
 spl/u-boot-spl-dtb.sfp: spl/u-boot-spl
 	@:
 
+spl/boot.bin: spl/u-boot-spl
+	@:
+
 tpl/u-boot-tpl.bin: tools prepare
 	$(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all
 
diff --git a/arch/arm/cpu/armv8/zynqmp/mp.c b/arch/arm/cpu/armv8/zynqmp/mp.c
index dcb80b5..58312a7 100644
--- a/arch/arm/cpu/armv8/zynqmp/mp.c
+++ b/arch/arm/cpu/armv8/zynqmp/mp.c
@@ -183,6 +183,29 @@
 	writel(tmp, &rpu_base->rpu1_cfg);
 }
 
+static void write_tcm_boot_trampoline(u32 boot_addr)
+{
+	if (boot_addr) {
+		/*
+		 * Boot trampoline is simple ASM code below.
+		 *
+		 *		b over;
+		 *	label:
+		 *	.word	0
+		 *	over:	ldr	r0, =label
+		 *		ldr	r1, [r0]
+		 *		bx	r1
+		 */
+		debug("Write boot trampoline for %x\n", boot_addr);
+		writel(0xea000000, ZYNQMP_TCM_START_ADDRESS);
+		writel(boot_addr, ZYNQMP_TCM_START_ADDRESS + 0x4);
+		writel(0xe59f0004, ZYNQMP_TCM_START_ADDRESS + 0x8);
+		writel(0xe5901000, ZYNQMP_TCM_START_ADDRESS + 0xc);
+		writel(0xe12fff11, ZYNQMP_TCM_START_ADDRESS + 0x10);
+		writel(0x00000004, ZYNQMP_TCM_START_ADDRESS + 0x14); // address for
+	}
+}
+
 int cpu_release(int nr, int argc, char * const argv[])
 {
 	if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
@@ -205,11 +228,18 @@
 		}
 
 		u32 boot_addr = simple_strtoul(argv[0], NULL, 16);
+		u32 boot_addr_uniq = 0;
 		if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
 		      boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
-			printf("Invalid starting address 0x%x\n", boot_addr);
-			printf("0 or 0xffff0000 are permitted\n");
-			return 1;
+			printf("Using TCM jump trampoline for address 0x%x\n",
+			       boot_addr);
+			/* Save boot address for later usage */
+			boot_addr_uniq = boot_addr;
+			/*
+			 * R5 needs to start from LOVEC at TCM
+			 * OCM will be probably occupied by ATF
+			 */
+			boot_addr = ZYNQMP_R5_LOVEC_ADDR;
 		}
 
 		if (!strncmp(argv[1], "lockstep", 8)) {
@@ -219,6 +249,7 @@
 			set_r5_start(boot_addr);
 			enable_clock_r5();
 			release_r5_reset(LOCK);
+			write_tcm_boot_trampoline(boot_addr_uniq);
 			set_r5_halt_mode(RELEASE, LOCK);
 		} else if (!strncmp(argv[1], "split", 5)) {
 			printf("R5 split mode\n");
@@ -226,6 +257,7 @@
 			set_r5_halt_mode(HALT, SPLIT);
 			enable_clock_r5();
 			release_r5_reset(SPLIT);
+			write_tcm_boot_trampoline(boot_addr_uniq);
 			set_r5_halt_mode(RELEASE, SPLIT);
 		} else {
 			printf("Unsupported mode\n");
diff --git a/common/cmd_mii.c b/common/cmd_mii.c
index 5e9079d..7ef7532 100644
--- a/common/cmd_mii.c
+++ b/common/cmd_mii.c
@@ -314,6 +314,11 @@
 			mask = simple_strtoul(argv[5], NULL, 16);
 	}
 
+	if (addrhi > 31) {
+		printf("Incorrect PHY address. Range should be 0-31\n");
+		return CMD_RET_USAGE;
+	}
+
 	/* use current device */
 	devname = miiphy_get_current_dev();
 
diff --git a/common/image.c b/common/image.c
index 85c4f39..c36927f 100644
--- a/common/image.c
+++ b/common/image.c
@@ -158,6 +158,7 @@
 	{	IH_TYPE_RKIMAGE,    "rkimage",    "Rockchip Boot Image" },
 	{	IH_TYPE_RKSD,       "rksd",       "Rockchip SD Boot Image" },
 	{	IH_TYPE_RKSPI,      "rkspi",      "Rockchip SPI Boot Image" },
+	{	IH_TYPE_ZYNQIMAGE,  "zynqimage",  "Xilinx Zynq Boot Image" },
 	{	-1,		    "",		  "",			},
 };
 
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index c69f5d4..e169b77 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -29,7 +29,7 @@
 		       SDHCI_QUIRK_BROKEN_R1B;
 	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
 
-	add_sdhci(host, 52000000, 52000000 >> 9);
+	add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 52000000 >> 9);
 	return 0;
 }
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index d096db8..9e4d492 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -24,4 +24,5 @@
 obj-$(CONFIG_PHY_REALTEK) += realtek.o
 obj-$(CONFIG_PHY_SMSC) += smsc.o
 obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
+obj-$(CONFIG_PHY_TI) += ti.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index d7364ff..5633ec2 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -484,6 +484,9 @@
 #ifdef CONFIG_PHY_TERANETICS
 	phy_teranetics_init();
 #endif
+#ifdef CONFIG_PHY_TI
+	phy_ti_init();
+#endif
 #ifdef CONFIG_PHY_VITESSE
 	phy_vitesse_init();
 #endif
diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c
new file mode 100644
index 0000000..541a57f
--- /dev/null
+++ b/drivers/net/phy/ti.c
@@ -0,0 +1,200 @@
+/*
+ * TI PHY drivers
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ *
+ */
+#include <common.h>
+#include <phy.h>
+
+/* TI DP83867 */
+#define DP83867_DEVADDR		0x1f
+
+#define MII_DP83867_PHYCTRL	0x10
+#define MII_DP83867_MICR	0x12
+#define DP83867_CTRL		0x1f
+
+/* Extended Registers */
+#define DP83867_RGMIICTL	0x0032
+#define DP83867_RGMIIDCTL	0x0086
+
+#define DP83867_SW_RESET	BIT(15)
+#define DP83867_SW_RESTART	BIT(14)
+
+/* MICR Interrupt bits */
+#define MII_DP83867_MICR_AN_ERR_INT_EN		BIT(15)
+#define MII_DP83867_MICR_SPEED_CHNG_INT_EN	BIT(14)
+#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN	BIT(13)
+#define MII_DP83867_MICR_PAGE_RXD_INT_EN	BIT(12)
+#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN	BIT(11)
+#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN	BIT(10)
+#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN	BIT(8)
+#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN	BIT(4)
+#define MII_DP83867_MICR_WOL_INT_EN		BIT(3)
+#define MII_DP83867_MICR_XGMII_ERR_INT_EN	BIT(2)
+#define MII_DP83867_MICR_POL_CHNG_INT_EN	BIT(1)
+#define MII_DP83867_MICR_JABBER_INT_EN		BIT(0)
+
+/* RGMIICTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_EN		BIT(1)
+#define DP83867_RGMII_RX_CLK_DELAY_EN		BIT(0)
+
+/* PHY CTRL bits */
+#define DP83867_PHYCR_FIFO_DEPTH_SHIFT		14
+
+/* RGMIIDCTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_SHIFT	4
+
+#define MII_MMD_CTRL	0x0d /* MMD Access Control Register */
+#define MII_MMD_DATA	0x0e /* MMD Access Data Register */
+
+/* MMD Access Control register fields */
+#define MII_MMD_CTRL_DEVAD_MASK	0x1f /* Mask MMD DEVAD*/
+#define MII_MMD_CTRL_ADDR	0x0000 /* Address */
+#define MII_MMD_CTRL_NOINCR	0x4000 /* no post increment */
+#define MII_MMD_CTRL_INCR_RDWT	0x8000 /* post increment on reads & writes */
+#define MII_MMD_CTRL_INCR_ON_WT	0xC000 /* post increment on writes only */
+
+/**
+ * phy_read_mmd_indirect - reads data from the MMD registers
+ * @phydev: The PHY device bus
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ *
+ * Description: it reads data from the MMD registers (clause 22 to access to
+ * clause 45) of the specified phy address.
+ * To read these registers we have:
+ * 1) Write reg 13 // DEVAD
+ * 2) Write reg 14 // MMD Address
+ * 3) Write reg 13 // MMD Data Command for MMD DEVAD
+ * 3) Read  reg 14 // Read MMD data
+ */
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
+			  int devad, int addr)
+{
+	int value = -1;
+
+	/* Write the desired MMD Devad */
+	phy_write(phydev, addr, MII_MMD_CTRL, devad);
+
+	/* Write the desired MMD register address */
+	phy_write(phydev, addr, MII_MMD_DATA, prtad);
+
+	/* Select the Function : DATA with no post increment */
+	phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
+
+	/* Read the content of the MMD's selected register */
+	value = phy_read(phydev, addr, MII_MMD_DATA);
+	return value;
+}
+
+/**
+ * phy_write_mmd_indirect - writes data to the MMD registers
+ * @phydev: The PHY device
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ * @data: data to write in the MMD register
+ *
+ * Description: Write data from the MMD registers of the specified
+ * phy address.
+ * To write these registers we have:
+ * 1) Write reg 13 // DEVAD
+ * 2) Write reg 14 // MMD Address
+ * 3) Write reg 13 // MMD Data Command for MMD DEVAD
+ * 3) Write reg 14 // Write MMD data
+ */
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
+			    int devad, int addr, u32 data)
+{
+	/* Write the desired MMD Devad */
+	phy_write(phydev, addr, MII_MMD_CTRL, devad);
+
+	/* Write the desired MMD register address */
+	phy_write(phydev, addr, MII_MMD_DATA, prtad);
+
+	/* Select the Function : DATA with no post increment */
+	phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
+
+	/* Write the data into MMD's selected register */
+	phy_write(phydev, addr, MII_MMD_DATA, data);
+}
+
+/**
+ * phy_interface_is_rgmii - Convenience function for testing if a PHY interface
+ * is RGMII (all variants)
+ * @phydev: the phy_device struct
+ */
+static inline bool phy_interface_is_rgmii(struct phy_device *phydev)
+{
+	return phydev->interface >= PHY_INTERFACE_MODE_RGMII &&
+		phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID;
+}
+
+/* User setting - can be taken from DTS */
+#define RX_ID_DELAY	8
+#define TX_ID_DELAY	0xa
+#define FIFO_DEPTH	1
+
+static int dp83867_config(struct phy_device *phydev)
+{
+	unsigned int val, delay;
+	int ret;
+
+	/* Restart the PHY.  */
+	val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL);
+	phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL,
+		  val | DP83867_SW_RESTART);
+
+	if (phy_interface_is_rgmii(phydev)) {
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
+			(FIFO_DEPTH << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
+		if (ret)
+			return ret;
+	}
+
+	if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
+	    (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
+		val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
+					    DP83867_DEVADDR, phydev->addr);
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+			val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
+				DP83867_RGMII_RX_CLK_DELAY_EN);
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+			val |= DP83867_RGMII_TX_CLK_DELAY_EN;
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+			val |= DP83867_RGMII_RX_CLK_DELAY_EN;
+
+		phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
+				       DP83867_DEVADDR, phydev->addr, val);
+
+		delay = (RX_ID_DELAY |
+			 (TX_ID_DELAY << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+
+		phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
+				       DP83867_DEVADDR, phydev->addr, delay);
+	}
+
+	genphy_config_aneg(phydev);
+	return 0;
+}
+
+static struct phy_driver DP83867_driver = {
+	.name = "TI DP83867",
+	.uid = 0x2000a231,
+	.mask = 0xfffffff0,
+	.features = PHY_GBIT_FEATURES,
+	.config = &dp83867_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+int phy_ti_init(void)
+{
+	phy_register(&DP83867_driver);
+	return 0;
+}
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 5637a0d..858093f 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -23,6 +23,7 @@
 #include <asm/system.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
+#include <asm-generic/errno.h>
 
 #if !defined(CONFIG_PHYLIB)
 # error XILINX_GEM_ETHERNET requires PHYLIB
@@ -46,6 +47,7 @@
 /* Wrap bit, last descriptor */
 #define ZYNQ_GEM_TXBUF_WRAP_MASK	0x40000000
 #define ZYNQ_GEM_TXBUF_LAST_MASK	0x00008000 /* Last buffer */
+#define ZYNQ_GEM_TXBUF_USED_MASK	0x80000000 /* Used by Hw */
 
 #define ZYNQ_GEM_NWCTRL_TXEN_MASK	0x00000008 /* Enable transmit */
 #define ZYNQ_GEM_NWCTRL_RXEN_MASK	0x00000004 /* Enable receive */
@@ -56,8 +58,7 @@
 #define ZYNQ_GEM_NWCFG_SPEED1000	0x000000400 /* 1Gbps operation */
 #define ZYNQ_GEM_NWCFG_FDEN		0x000000002 /* Full Duplex mode */
 #define ZYNQ_GEM_NWCFG_FSREM		0x000020000 /* FCS removal */
-#define ZYNQ_GEM_NWCFG_MDCCLKDIV	0x000080000 /* Div pclk by 32, 80MHz */
-#define ZYNQ_GEM_NWCFG_MDCCLKDIV2	0x0000c0000 /* Div pclk by 48, 120MHz */
+#define ZYNQ_GEM_NWCFG_MDCCLKDIV	0x0000c0000 /* Div pclk by 48, max 120MHz */
 
 #ifdef CONFIG_ARM64
 # define ZYNQ_GEM_DBUS_WIDTH	(1 << 21) /* 64 bit bus */
@@ -85,6 +86,8 @@
 					ZYNQ_GEM_DMACR_TXSIZE | \
 					ZYNQ_GEM_DMACR_RXBUF)
 
+#define ZYNQ_GEM_TSR_DONE		0x00000020 /* Tx done mask */
+
 /* Use MII register 1 (MII status register) to detect PHY */
 #define PHY_DETECT_REG  1
 
@@ -108,28 +111,33 @@
 
 /* Device registers */
 struct zynq_gem_regs {
-	u32 nwctrl; /* Network Control reg */
-	u32 nwcfg; /* Network Config reg */
-	u32 nwsr; /* Network Status reg */
+	u32 nwctrl; /* 0x0 - Network Control reg */
+	u32 nwcfg; /* 0x4 - Network Config reg */
+	u32 nwsr; /* 0x8 - Network Status reg */
 	u32 reserved1;
-	u32 dmacr; /* DMA Control reg */
-	u32 txsr; /* TX Status reg */
-	u32 rxqbase; /* RX Q Base address reg */
-	u32 txqbase; /* TX Q Base address reg */
-	u32 rxsr; /* RX Status reg */
+	u32 dmacr; /* 0x10 - DMA Control reg */
+	u32 txsr; /* 0x14 - TX Status reg */
+	u32 rxqbase; /* 0x18 - RX Q Base address reg */
+	u32 txqbase; /* 0x1c - TX Q Base address reg */
+	u32 rxsr; /* 0x20 - RX Status reg */
 	u32 reserved2[2];
-	u32 idr; /* Interrupt Disable reg */
+	u32 idr; /* 0x2c - Interrupt Disable reg */
 	u32 reserved3;
-	u32 phymntnc; /* Phy Maintaince reg */
+	u32 phymntnc; /* 0x34 - Phy Maintaince reg */
 	u32 reserved4[18];
-	u32 hashl; /* Hash Low address reg */
-	u32 hashh; /* Hash High address reg */
+	u32 hashl; /* 0x80 - Hash Low address reg */
+	u32 hashh; /* 0x84 - Hash High address reg */
 #define LADDR_LOW	0
 #define LADDR_HIGH	1
-	u32 laddr[4][LADDR_HIGH + 1]; /* Specific1 addr low/high reg */
-	u32 match[4]; /* Type ID1 Match reg */
+	u32 laddr[4][LADDR_HIGH + 1]; /* 0x8c - Specific1 addr low/high reg */
+	u32 match[4]; /* 0xa8 - Type ID1 Match reg */
 	u32 reserved6[18];
-	u32 stat[44]; /* Octects transmitted Low reg - stat start */
+#define STAT_SIZE	44
+	u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */
+	u32 reserved7[164];
+	u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */
+	u32 reserved8[15];
+	u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */
 };
 
 /* BD descriptors */
@@ -144,7 +152,10 @@
  */
 #define BD_SPACE	0x100000
 /* BD separation space */
-#define BD_SEPRN_SPACE	64
+#define BD_SEPRN_SPACE	(RX_BUF * sizeof(struct emac_bd))
+
+/* Setup the first free TX descriptor */
+#define TX_FREE_DESC	2
 
 /* Initialized, rxbd_current, rx_first_buf must be 0 after init */
 struct zynq_gem_priv {
@@ -156,6 +167,7 @@
 	int phyaddr;
 	u32 emio;
 	int init;
+	phy_interface_t interface;
 	struct phy_device *phydev;
 	struct mii_dev *bus;
 };
@@ -208,12 +220,23 @@
 
 static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val)
 {
-	return phy_setup_op(dev, phy_addr, regnum,
+	u32 ret;
+
+	ret = phy_setup_op(dev, phy_addr, regnum,
 				ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val);
+
+	if (!ret)
+		debug("%s: phy_addr %d, regnum 0x%x, val 0x%x\n", __func__,
+		      phy_addr, regnum, *val);
+
+	return ret;
 }
 
 static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data)
 {
+	debug("%s: phy_addr %d, regnum 0x%x, data 0x%x\n", __func__, phy_addr,
+	      regnum, data);
+
 	return phy_setup_op(dev, phy_addr, regnum,
 				ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data);
 }
@@ -289,10 +312,10 @@
 	u32 i;
 	unsigned long clk_rate = 0;
 	struct phy_device *phydev;
-	const u32 stat_size = (sizeof(struct zynq_gem_regs) -
-				offsetof(struct zynq_gem_regs, stat)) / 4;
 	struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
 	struct zynq_gem_priv *priv = dev->priv;
+	struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
+	struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2];
 	const u32 supported = SUPPORTED_10baseT_Half |
 			SUPPORTED_10baseT_Full |
 			SUPPORTED_100baseT_Half |
@@ -318,7 +341,7 @@
 		writel(0x0, &regs->hashh);
 
 		/* Clear all counters */
-		for (i = 0; i <= stat_size; i++)
+		for (i = 0; i < STAT_SIZE; i++)
 			readl(&regs->stat[i]);
 
 		/* Setup RxBD space */
@@ -341,6 +364,23 @@
 		/* Setup for Network Control register, MDIO, Rx and Tx enable */
 		setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
 
+		/* Disable the second priority queue */
+		dummy_tx_bd->addr = 0;
+		dummy_tx_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK |
+				ZYNQ_GEM_TXBUF_LAST_MASK|
+				ZYNQ_GEM_TXBUF_USED_MASK;
+
+		dummy_rx_bd->addr = ZYNQ_GEM_RXBUF_WRAP_MASK |
+				ZYNQ_GEM_RXBUF_NEW_MASK;
+		dummy_rx_bd->status = 0;
+		flush_dcache_range((ulong)&dummy_tx_bd, (ulong)&dummy_tx_bd +
+				   sizeof(dummy_tx_bd));
+		flush_dcache_range((ulong)&dummy_rx_bd, (ulong)&dummy_rx_bd +
+				   sizeof(dummy_rx_bd));
+
+		writel((ulong)dummy_tx_bd, &regs->transmit_q1_ptr);
+		writel((ulong)dummy_rx_bd, &regs->receive_q1_ptr);
+
 		priv->init++;
 	}
 
@@ -348,7 +388,7 @@
 
 	/* interface - look at tsec */
 	phydev = phy_connect(priv->bus, priv->phyaddr, dev,
-			     PHY_INTERFACE_MODE_MII);
+			     priv->interface);
 
 	phydev->supported = supported | ADVERTISED_Pause |
 			    ADVERTISED_Asym_Pause;
@@ -369,8 +409,8 @@
 		clk_rate = ZYNQ_GEM_FREQUENCY_1000;
 		break;
 	case SPEED_100:
-		clrsetbits_le32(&regs->nwcfg, ZYNQ_GEM_NWCFG_SPEED1000,
-				ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100);
+		writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100,
+		       &regs->nwcfg);
 		clk_rate = ZYNQ_GEM_FREQUENCY_100;
 		break;
 	case SPEED_10:
@@ -389,22 +429,54 @@
 	return 0;
 }
 
+static int wait_for_bit(const char *func, u32 *reg, const u32 mask,
+			bool set, unsigned int timeout)
+{
+	u32 val;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		val = readl(reg);
+
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+
+		if (get_timer(start) > timeout)
+			break;
+
+		udelay(1);
+	}
+
+	debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
+	      func, reg, mask, set);
+
+	return -ETIMEDOUT;
+}
+
 static int zynq_gem_send(struct eth_device *dev, void *ptr, int len)
 {
 	u32 addr, size;
 	struct zynq_gem_priv *priv = dev->priv;
 	struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
-
-	/* setup BD */
-	writel((ulong)priv->tx_bd, &regs->txqbase);
+	struct emac_bd *current_bd = &priv->tx_bd[1];
 
 	/* Setup Tx BD */
 	memset(priv->tx_bd, 0, sizeof(struct emac_bd));
 
 	priv->tx_bd->addr = (ulong)ptr;
 	priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) |
-			       ZYNQ_GEM_TXBUF_LAST_MASK |
-			       ZYNQ_GEM_TXBUF_WRAP_MASK;
+			       ZYNQ_GEM_TXBUF_LAST_MASK;
+	/* Dummy descriptor to mark it as the last in descriptor chain */
+	current_bd->addr = 0x0;
+	current_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK |
+			     ZYNQ_GEM_TXBUF_LAST_MASK|
+			     ZYNQ_GEM_TXBUF_USED_MASK;
+
+	/* setup BD */
+	writel((ulong)priv->tx_bd, &regs->txqbase);
 
 	addr = (ulong) ptr;
 	addr &= ~(ARCH_DMA_MINALIGN - 1);
@@ -421,12 +493,11 @@
 	setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK);
 
 	/* Read TX BD status */
-	if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_UNDERRUN)
-		printf("TX underrun\n");
 	if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED)
 		printf("TX buffers exhausted in mid frame\n");
 
-	return 0;
+	return wait_for_bit(__func__, &regs->txsr, ZYNQ_GEM_TSR_DONE,
+			    true, 20000);
 }
 
 /* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */
@@ -535,6 +606,12 @@
 	priv->phyaddr = phy_addr;
 	priv->emio = emio;
 
+#ifndef CONFIG_ZYNQ_GEM_INTERFACE
+	priv->interface = PHY_INTERFACE_MODE_MII;
+#else
+	priv->interface = CONFIG_ZYNQ_GEM_INTERFACE;
+#endif
+
 	sprintf(dev->name, "Gem.%lx", base_addr);
 
 	dev->iobase = base_addr;
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h
index 36c1100..e990512 100644
--- a/include/configs/xilinx_zynqmp.h
+++ b/include/configs/xilinx_zynqmp.h
@@ -94,6 +94,9 @@
 # define CONFIG_SDHCI
 # define CONFIG_ZYNQ_SDHCI
 # define CONFIG_CMD_MMC
+# ifndef CONFIG_ZYNQ_SDHCI_MAX_FREQ
+#  define CONFIG_ZYNQ_SDHCI_MAX_FREQ	200000000
+# endif
 #endif
 
 #if defined(CONFIG_ZYNQ_SDHCI)
@@ -182,6 +185,7 @@
 # define CONFIG_SYS_FAULT_ECHO_LINK_DOWN
 # define CONFIG_PHYLIB
 # define CONFIG_PHY_MARVELL
+# define CONFIG_PHY_TI
 #endif
 
 /* I2C */
diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h
index ed6023a..8bdb5c9 100644
--- a/include/configs/xilinx_zynqmp_ep.h
+++ b/include/configs/xilinx_zynqmp_ep.h
@@ -19,6 +19,7 @@
 #define CONFIG_ZYNQ_GEM_PHY_ADDR0	7
 
 #define CONFIG_ZYNQ_SDHCI0
+#define CONFIG_ZYNQ_SDHCI_MAX_FREQ	52000000
 #define CONFIG_ZYNQ_I2C0
 #define CONFIG_SYS_I2C_ZYNQ
 #define CONFIG_ZYNQ_EEPROM
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 99a3d021..d10f1dd 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -105,6 +105,7 @@
 # define CONFIG_SDHCI
 # define CONFIG_ZYNQ_SDHCI
 # define CONFIG_CMD_MMC
+# define CONFIG_ZYNQ_SDHCI_MAX_FREQ	52000000
 #endif
 
 #ifdef CONFIG_ZYNQ_USB
@@ -331,7 +332,7 @@
 #define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION     1
 #define CONFIG_SPL_LIBDISK_SUPPORT
 #define CONFIG_SPL_FAT_SUPPORT
-#ifdef CONFIG_OF_CONTROL
+#ifdef CONFIG_OF_SEPARATE
 # define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME     "u-boot-dtb.img"
 #else
 # define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME     "u-boot.img"
diff --git a/include/image.h b/include/image.h
index 08ae24a..299d6d2 100644
--- a/include/image.h
+++ b/include/image.h
@@ -248,8 +248,9 @@
 #define IH_TYPE_RKIMAGE		23	/* Rockchip Boot Image		*/
 #define IH_TYPE_RKSD		24	/* Rockchip SD card		*/
 #define IH_TYPE_RKSPI		25	/* Rockchip SPI image		*/
+#define IH_TYPE_ZYNQIMAGE	26	/* Xilinx Zynq Boot Image */
 
-#define IH_TYPE_COUNT		26	/* Number of image types */
+#define IH_TYPE_COUNT		27	/* Number of image types */
 
 /*
  * Compression Types
diff --git a/include/phy.h b/include/phy.h
index 3f826b6..66cf61b 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -251,6 +251,7 @@
 int phy_realtek_init(void);
 int phy_smsc_init(void);
 int phy_teranetics_init(void);
+int phy_ti_init(void);
 int phy_vitesse_init(void);
 
 int board_phy_config(struct phy_device *phydev);
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 8f690eb..96f414a 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -117,6 +117,7 @@
 MLO MLO.byteswap: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkimage)
 
+ifeq ($(CONFIG_SYS_SOC),"at91")
 MKIMAGEFLAGS_boot.bin = -T atmelimage
 
 ifeq ($(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER),y)
@@ -127,6 +128,12 @@
 
 boot.bin: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkimage)
+else
+MKIMAGEFLAGS_boot.bin = -T zynqimage
+
+spl/boot.bin: $(obj)/u-boot-spl-dtb.bin
+	$(call if_changed,mkimage)
+endif
 
 ALL-y	+= $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).cfg
 
@@ -150,6 +157,10 @@
 ALL-y	+= boot.bin
 endif
 
+ifdef CONFIG_ARCH_ZYNQ
+ALL-y	+= $(obj)/boot.bin
+endif
+
 all:	$(ALL-y)
 
 quiet_cmd_cat = CAT     $@
diff --git a/tools/Makefile b/tools/Makefile
index 9082bda..9cfd80b 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -98,6 +98,7 @@
 			lib/sha256.o \
 			common/hash.o \
 			ublimage.o \
+			zynqimage.o \
 			$(LIBFDT_OBJS) \
 			$(RSA_OBJS-y)
 
diff --git a/tools/zynqimage.c b/tools/zynqimage.c
new file mode 100644
index 0000000..25f558d
--- /dev/null
+++ b/tools/zynqimage.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * The following Boot Header format/structures and values are defined in the
+ * following documents:
+ *   * Xilinx Zynq-7000 Technical Reference Manual (Section 6.3)
+ *   * Xilinx Zynq-7000 Software Developers Guide (Appendix A.7 and A.8)
+ *
+ * Expected Header Size = 0x8C0
+ * Forced as 'little' endian, 32-bit words
+ *
+ *  0x  0 - Interrupt Table (8 words)
+ *  ...     (Default value = 0xeafffffe)
+ *  0x 1f
+ *  0x 20 - Width Detection
+ *         * DEFAULT_WIDTHDETECTION    0xaa995566
+ *  0x 24 - Image Identifier
+ *         * DEFAULT_IMAGEIDENTIFIER   0x584c4e58
+ *  0x 28 - Encryption
+ *         * 0x00000000 - None
+ *         * 0xa5c3c5a3 - eFuse
+ *         * 0x3a5c3c5a - bbRam
+ *  0x 2C - User Field
+ *  0x 30 - Image Offset
+ *  0x 34 - Image Size
+ *  0x 38 - Reserved (0x00000000) (according to spec)
+ *          * FSBL defines this field for Image Destination Address.
+ *  0x 3C - Image Load
+ *  0x 40 - Image Stored Size
+ *  0x 44 - Reserved (0x00000000) (according to spec)
+ *          * FSBL defines this field for QSPI configuration Data.
+ *  0x 48 - Checksum
+ *  0x 4c - Unused (21 words)
+ *  ...
+ *  0x 9c
+ *  0x a0 - Register Initialization, 256 Address and Data word pairs
+ *         * List is terminated with an address of 0xffffffff or
+ *  ...    * at the max number of entries
+ *  0x89c
+ *  0x8a0 - Unused (8 words)
+ *  ...
+ *  0x8bf
+ *  0x8c0 - Data/Image starts here or above
+ */
+
+#include "imagetool.h"
+#include "mkimage.h"
+#include <image.h>
+
+#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe))
+#define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff))
+#define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566))
+#define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58))
+
+enum {
+	ENCRYPTION_EFUSE = 0xa5c3c5a3,
+	ENCRYPTION_BBRAM = 0x3a5c3c5a,
+	ENCRYPTION_NONE = 0x0,
+};
+
+struct zynq_reginit {
+	uint32_t address;
+	uint32_t data;
+};
+
+#define HEADER_INTERRUPT_VECTORS 8
+#define HEADER_REGINITS 256
+
+struct zynq_header {
+	uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */
+	uint32_t width_detection; /* 0x20 */
+	uint32_t image_identifier; /* 0x24 */
+	uint32_t encryption; /* 0x28 */
+	uint32_t user_field; /* 0x2c */
+	uint32_t image_offset; /* 0x30 */
+	uint32_t image_size; /* 0x34 */
+	uint32_t __reserved1; /* 0x38 */
+	uint32_t image_load; /* 0x3c */
+	uint32_t image_stored_size; /* 0x40 */
+	uint32_t __reserved2; /* 0x44 */
+	uint32_t checksum; /* 0x48 */
+	uint32_t __reserved3[21]; /* 0x4c */
+	struct zynq_reginit register_init[HEADER_REGINITS]; /* 0xa0 */
+	uint32_t __reserved4[8]; /* 0x8a0 */
+};
+
+static struct zynq_header zynqimage_header;
+
+static uint32_t zynqimage_checksum(struct zynq_header *ptr)
+{
+	uint32_t checksum = 0;
+
+	if (ptr == NULL)
+		return 0;
+
+	checksum += le32_to_cpu(ptr->width_detection);
+	checksum += le32_to_cpu(ptr->image_identifier);
+	checksum += le32_to_cpu(ptr->encryption);
+	checksum += le32_to_cpu(ptr->user_field);
+	checksum += le32_to_cpu(ptr->image_offset);
+	checksum += le32_to_cpu(ptr->image_size);
+	checksum += le32_to_cpu(ptr->__reserved1);
+	checksum += le32_to_cpu(ptr->image_load);
+	checksum += le32_to_cpu(ptr->image_stored_size);
+	checksum += le32_to_cpu(ptr->__reserved2);
+	checksum = ~checksum;
+
+	return cpu_to_le32(checksum);
+}
+
+static void zynqimage_default_header(struct zynq_header *ptr)
+{
+	int i;
+
+	if (ptr == NULL)
+		return;
+
+	ptr->width_detection = HEADER_WIDTHDETECTION;
+	ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
+	ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
+
+	/* Setup not-supported/constant/reserved fields */
+	for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++)
+		ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT;
+
+	for (i = 0; i < HEADER_REGINITS; i++) {
+		ptr->register_init[i].address = HEADER_REGINIT_NULL;
+		ptr->register_init[i].data = HEADER_REGINIT_NULL;
+	}
+
+	/*
+	 * Certain reserved fields are required to be set to 0, ensure they are
+	 * set as such.
+	 */
+	ptr->__reserved1 = 0x0;
+	ptr->__reserved2 = 0x0;
+}
+
+/* mkimage glue functions */
+static int zynqimage_verify_header(unsigned char *ptr, int image_size,
+		struct image_tool_params *params)
+{
+	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
+
+	if (image_size < sizeof(struct zynq_header))
+		return -1;
+
+	if (zynqhdr->width_detection != HEADER_WIDTHDETECTION)
+		return -1;
+	if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER)
+		return -1;
+
+	if (zynqimage_checksum(zynqhdr) != zynqhdr->checksum)
+		return -1;
+
+	return 0;
+}
+
+static void zynqimage_print_header(const void *ptr)
+{
+	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
+	int i;
+
+	printf("Image Type   : Xilinx Zynq Boot Image support\n");
+	printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset));
+	printf("Image Size   : %lu bytes (%lu bytes packed)\n",
+	       (unsigned long)le32_to_cpu(zynqhdr->image_size),
+	       (unsigned long)le32_to_cpu(zynqhdr->image_stored_size));
+	printf("Image Load   : 0x%08x\n", le32_to_cpu(zynqhdr->image_load));
+	printf("User Field   : 0x%08x\n", le32_to_cpu(zynqhdr->user_field));
+	printf("Checksum     : 0x%08x\n", le32_to_cpu(zynqhdr->checksum));
+
+	for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) {
+		if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT)
+			continue;
+
+		printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i,
+		       le32_to_cpu(zynqhdr->interrupt_vectors[i]));
+	}
+
+	for (i = 0; i < HEADER_REGINITS; i++) {
+		if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL)
+			break;
+
+		if (i == 0)
+			printf("Custom Register Initialization:\n");
+
+		printf("    @ 0x%08x -> 0x%08x\n",
+		       le32_to_cpu(zynqhdr->register_init[i].address),
+		       le32_to_cpu(zynqhdr->register_init[i].data));
+	}
+}
+
+static int zynqimage_check_params(struct image_tool_params *params)
+{
+	if (!params)
+		return 0;
+
+	if (params->addr != 0x0) {
+		fprintf(stderr, "Error: Load Address cannot be specified.\n");
+		return -1;
+	}
+
+	/*
+	 * If the entry point is specified ensure it is 64 byte aligned.
+	 */
+	if (params->eflag && (params->ep % 64 != 0)) {
+		fprintf(stderr,
+			"Error: Entry Point must be aligned to a 64-byte boundary.\n");
+		return -1;
+	}
+
+	return !((params->lflag || params->dflag) ||
+			(params->dflag && params->eflag));
+}
+
+static int zynqimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_ZYNQIMAGE)
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
+
+static void zynqimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+		struct image_tool_params *params)
+{
+	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
+	zynqimage_default_header(zynqhdr);
+
+	/* place image directly after header */
+	zynqhdr->image_offset =
+		cpu_to_le32((uint32_t)sizeof(struct zynq_header));
+	zynqhdr->image_size = cpu_to_le32((uint32_t)sbuf->st_size);
+	zynqhdr->image_stored_size = zynqhdr->image_size;
+	zynqhdr->image_load = 0x0;
+	if (params->eflag)
+		zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep);
+
+	zynqhdr->checksum = zynqimage_checksum(zynqhdr);
+}
+
+U_BOOT_IMAGE_TYPE(
+	zynqimage,
+	"Xilinx Zynq Boot Image support",
+	sizeof(struct zynq_header),
+	(void *)&zynqimage_header,
+	zynqimage_check_params,
+	zynqimage_verify_header,
+	zynqimage_print_header,
+	zynqimage_set_header,
+	NULL,
+	zynqimage_check_image_types,
+	NULL,
+	NULL
+);