Procházet zdrojové kódy

Merge branch 'master' of git://git.denx.de/u-boot-net

* 'master' of git://git.denx.de/u-boot-net:
  net/designware: Change timeout loop implementation
  net/designware: Set ANAR to 0x1e1
  net/designware: Program phy registers when auto-negotiation is ON
  net/designware: Try configuring phy on each dw_eth_init
  net/designware: Consecutive writes must have delay
  net/designware: Phy address fix
  net/designware: Fix the max frame length size
  net/designware: Fix to restore hw mac address
  microblaze: Wire up LL_TEMAC driver initialization
  microblaze: Add faked LL_TEMAC driver configuration
  microblaze: Enable several ethernet driver compilation
  net: ll_temac: Add LL TEMAC driver to u-boot
  Update net subsystem maintainer in doc/git-mailrc
  net/eth.c: fix eth_write_hwaddr() to use dev->enetaddr as fall back
  mvgbe: remove warning for unused methods
Wolfgang Denk před 13 roky
rodič
revize
2c734cd932

+ 4 - 2
board/xilinx/microblaze-generic/config.mk

@@ -21,8 +21,10 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
 #
-# CAUTION: This file is automatically generated by libgen.
-# Version: Xilinx EDK 6.3 EDK_Gmm.12.3
+# CAUTION: This file is a faked configuration !!!
+#          There is no real target for the microblaze-generic
+#          configuration. You have to replace this file with
+#          the generated file from your Xilinx design flow.
 #
 
 CONFIG_SYS_TEXT_BASE = 0x29000000

+ 36 - 0
board/xilinx/microblaze-generic/microblaze-generic.c

@@ -90,5 +90,41 @@ int board_eth_init(bd_t *bis)
 	ret |= xilinx_emaclite_initialize(bis, XILINX_EMACLITE_BASEADDR,
 			txpp, rxpp);
 #endif
+
+#ifdef CONFIG_XILINX_LL_TEMAC
+# ifdef XILINX_LLTEMAC_BASEADDR
+#  ifdef XILINX_LLTEMAC_FIFO_BASEADDR
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR,
+			XILINX_LL_TEMAC_M_FIFO, XILINX_LLTEMAC_FIFO_BASEADDR);
+#  elif XILINX_LLTEMAC_SDMA_CTRL_BASEADDR
+#   if XILINX_LLTEMAC_SDMA_USE_DCR == 1
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR,
+			XILINX_LL_TEMAC_M_SDMA_DCR,
+			XILINX_LLTEMAC_SDMA_CTRL_BASEADDR);
+#   else
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR,
+			XILINX_LL_TEMAC_M_SDMA_PLB,
+			XILINX_LLTEMAC_SDMA_CTRL_BASEADDR);
+#   endif
+#  endif
+# endif
+# ifdef XILINX_LLTEMAC_BASEADDR1
+#  ifdef XILINX_LLTEMAC_FIFO_BASEADDR1
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR1,
+			XILINX_LL_TEMAC_M_FIFO, XILINX_LLTEMAC_FIFO_BASEADDR1);
+#  elif XILINX_LLTEMAC_SDMA_CTRL_BASEADDR1
+#   if XILINX_LLTEMAC_SDMA_USE_DCR == 1
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR1,
+			XILINX_LL_TEMAC_M_SDMA_DCR,
+			XILINX_LLTEMAC_SDMA_CTRL_BASEADDR1);
+#   else
+	ret |= xilinx_ll_temac_eth_init(bis, XILINX_LLTEMAC_BASEADDR1,
+			XILINX_LL_TEMAC_M_SDMA_PLB,
+			XILINX_LLTEMAC_SDMA_CTRL_BASEADDR1);
+#   endif
+#  endif
+# endif
+#endif
+
 	return ret;
 }

+ 10 - 2
board/xilinx/microblaze-generic/xparameters.h

@@ -21,8 +21,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  *
- * CAUTION: This file is automatically generated by libgen.
- * Version: Xilinx EDK 8.2.02 EDK_Im_Sp2.4
+ * CAUTION: This file is a faked configuration !!!
+ *          There is no real target for the microblaze-generic
+ *          configuration. You have to replace this file with
+ *          the generated file from your Xilinx design flow.
  */
 
 #define XILINX_BOARD_NAME	microblaze-generic
@@ -69,3 +71,9 @@
 
 /* Ethernet controller is Ethernet_MAC */
 #define XILINX_EMACLITE_BASEADDR       0x40C00000
+
+/* LL_TEMAC Ethernet controller */
+#define XILINX_LLTEMAC_BASEADDR			0x44000000
+#define XILINX_LLTEMAC_SDMA_CTRL_BASEADDR	0x42000180
+#define XILINX_LLTEMAC_BASEADDR1		0x44200000
+#define XILINX_LLTEMAC_FIFO_BASEADDR1		0x42100000

+ 2 - 1
doc/git-mailrc

@@ -18,6 +18,7 @@ alias gruss          Graeme Russ <graeme.russ@gmail.com>
 alias hs             Heiko Schocher <hs@denx.de>
 alias iwamatsu       Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
 alias jasonjin       Jason Jin <jason.jin@freescale.com>
+alias jhersh         Joe Hershberger <joe.hershberger@gmail.com>
 alias kimphill       Kim Phillips <kim.phillips@freescale.com>
 alias macpaul        Macpaul Lin <macpaul@andestech.com>
 alias marex          Marek Vasut <marek.vasut@gmail.com>
@@ -97,6 +98,6 @@ alias fdt            uboot, Jerry Van Baren <vanbaren@cideas.com>
 alias i2c            uboot, hs
 alias mmc            uboot, afleming
 alias nand           uboot, scottwood
-alias net            uboot, wd
+alias net            uboot, jhersh
 alias usb            uboot, marex
 alias video          uboot, ag

+ 2 - 0
drivers/net/Makefile

@@ -77,6 +77,8 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o
 COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
 COBJS-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o
 COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
+COBJS-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \
+		xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o
 
 COBJS	:= $(sort $(COBJS-y))
 SRCS	:= $(COBJS:.o=.c)

+ 90 - 38
drivers/net/designware.c

@@ -32,6 +32,8 @@
 #include <asm/io.h>
 #include "designware.h"
 
+static int configure_phy(struct eth_device *dev);
+
 static void tx_descs_init(struct eth_device *dev)
 {
 	struct dw_eth_dev *priv = dev->priv;
@@ -106,16 +108,20 @@ static int mac_reset(struct eth_device *dev)
 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
 
+	ulong start;
 	int timeout = CONFIG_MACRESET_TIMEOUT;
 
 	writel(DMAMAC_SRST, &dma_p->busmode);
 	writel(MII_PORTSELECT, &mac_p->conf);
 
-	do {
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
 		if (!(readl(&dma_p->busmode) & DMAMAC_SRST))
 			return 0;
-		udelay(1000);
-	} while (timeout--);
+
+		/* Try again after 10usec */
+		udelay(10);
+	};
 
 	return -1;
 }
@@ -144,10 +150,16 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
 	u32 conf;
 
+	if (priv->phy_configured != 1)
+		configure_phy(dev);
+
 	/* Reset ethernet hardware */
 	if (mac_reset(dev) < 0)
 		return -1;
 
+	/* Resore the HW MAC address as it has been lost during MAC reset */
+	dw_write_hwaddr(dev);
+
 	writel(FIXEDBURST | PRIORXTX_41 | BURST_16,
 			&dma_p->busmode);
 
@@ -172,8 +184,7 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
 	writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode);
 	writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode);
 
-	writel(readl(&mac_p->conf) | RXENABLE, &mac_p->conf);
-	writel(readl(&mac_p->conf) | TXENABLE, &mac_p->conf);
+	writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
 
 	return 0;
 }
@@ -266,6 +277,7 @@ static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val)
 {
 	struct dw_eth_dev *priv = dev->priv;
 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
+	ulong start;
 	u32 miiaddr;
 	int timeout = CONFIG_MDIO_TIMEOUT;
 
@@ -274,13 +286,16 @@ static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val)
 
 	writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
 
-	do {
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
 		if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
 			*val = readl(&mac_p->miidata);
 			return 0;
 		}
-		udelay(1000);
-	} while (timeout--);
+
+		/* Try again after 10usec */
+		udelay(10);
+	};
 
 	return -1;
 }
@@ -289,6 +304,7 @@ static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val)
 {
 	struct dw_eth_dev *priv = dev->priv;
 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
+	ulong start;
 	u32 miiaddr;
 	int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
 	u16 value;
@@ -299,11 +315,16 @@ static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val)
 
 	writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
 
-	do {
-		if (!(readl(&mac_p->miiaddr) & MII_BUSY))
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
+		if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
 			ret = 0;
-		udelay(1000);
-	} while (timeout--);
+			break;
+		}
+
+		/* Try again after 10usec */
+		udelay(10);
+	};
 
 	/* Needed as a fix for ST-Phy */
 	eth_mdio_read(dev, addr, reg, &value);
@@ -344,18 +365,23 @@ static int dw_reset_phy(struct eth_device *dev)
 {
 	struct dw_eth_dev *priv = dev->priv;
 	u16 ctrl;
+	ulong start;
 	int timeout = CONFIG_PHYRESET_TIMEOUT;
 	u32 phy_addr = priv->address;
 
 	eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET);
-	do {
+
+	start = get_timer(0);
+	while (get_timer(start) < timeout) {
 		eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
 		if (!(ctrl & BMCR_RESET))
 			break;
-		udelay(1000);
-	} while (timeout--);
 
-	if (timeout < 0)
+		/* Try again after 10usec */
+		udelay(10);
+	};
+
+	if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT)
 		return -1;
 
 #ifdef CONFIG_PHY_RESET_DELAY
@@ -372,6 +398,7 @@ static int configure_phy(struct eth_device *dev)
 #if defined(CONFIG_DW_AUTONEG)
 	u16 bmsr;
 	u32 timeout;
+	ulong start;
 	u16 anlpar, btsr;
 #else
 	u16 ctrl;
@@ -379,7 +406,7 @@ static int configure_phy(struct eth_device *dev)
 
 #if defined(CONFIG_DW_SEARCH_PHY)
 	phy_addr = find_phy(dev);
-	if (phy_addr > 0)
+	if (phy_addr >= 0)
 		priv->address = phy_addr;
 	else
 		return -1;
@@ -390,8 +417,10 @@ static int configure_phy(struct eth_device *dev)
 		return -1;
 
 #if defined(CONFIG_DW_AUTONEG)
-	bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100 | \
-	       BMCR_FULLDPLX | BMCR_SPEED1000;
+	/* Set Auto-Neg Advertisement capabilities to 10/100 half/full */
+	eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1);
+
+	bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
 #else
 	bmcr = BMCR_SPEED100 | BMCR_FULLDPLX;
 
@@ -408,33 +437,56 @@ static int configure_phy(struct eth_device *dev)
 	/* Read the phy status register and populate priv structure */
 #if defined(CONFIG_DW_AUTONEG)
 	timeout = CONFIG_AUTONEG_TIMEOUT;
-	do {
+	start = get_timer(0);
+
+	while (get_timer(start) < timeout) {
 		eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
 		if (bmsr & BMSR_ANEGCOMPLETE)
 			break;
-		udelay(1000);
-	} while (timeout--);
+
+		/* Try again after 10usec */
+		udelay(10);
+	};
 
 	eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar);
 	eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr);
 
-	if (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
-		priv->speed = SPEED_1000M;
-		if (btsr & PHY_1000BTSR_1000FD)
+	if (bmsr & BMSR_ANEGCOMPLETE) {
+		if (btsr & PHY_1000BTSR_1000FD) {
+			priv->speed = SPEED_1000M;
+			bmcr |= BMCR_SPEED1000;
 			priv->duplex = FULL_DUPLEX;
-		else
+			bmcr |= BMCR_FULLDPLX;
+		} else if (btsr & PHY_1000BTSR_1000HD) {
+			priv->speed = SPEED_1000M;
+			bmcr |= BMCR_SPEED1000;
 			priv->duplex = HALF_DUPLEX;
-	} else {
-		if (anlpar & LPA_100)
+			bmcr &= ~BMCR_FULLDPLX;
+		} else if (anlpar & LPA_100FULL) {
 			priv->speed = SPEED_100M;
-		else
-			priv->speed = SPEED_10M;
-
-		if (anlpar & (LPA_10FULL | LPA_100FULL))
+			bmcr |= BMCR_SPEED100;
 			priv->duplex = FULL_DUPLEX;
-		else
+			bmcr |= BMCR_FULLDPLX;
+		} else if (anlpar & LPA_100HALF) {
+			priv->speed = SPEED_100M;
+			bmcr |= BMCR_SPEED100;
 			priv->duplex = HALF_DUPLEX;
-	}
+			bmcr &= ~BMCR_FULLDPLX;
+		} else if (anlpar & LPA_10FULL) {
+			priv->speed = SPEED_10M;
+			bmcr &= ~BMCR_SPEED100;
+			priv->duplex = FULL_DUPLEX;
+			bmcr |= BMCR_FULLDPLX;
+		} else {
+				priv->speed = SPEED_10M;
+				bmcr &= ~BMCR_SPEED100;
+				priv->duplex = HALF_DUPLEX;
+				bmcr &= ~BMCR_FULLDPLX;
+		}
+		if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
+			return -1;
+	} else
+		return -1;
 #else
 	if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0)
 		return -1;
@@ -451,6 +503,8 @@ static int configure_phy(struct eth_device *dev)
 	else
 		priv->speed = SPEED_10M;
 #endif
+	priv->phy_configured = 1;
+
 	return 0;
 }
 
@@ -511,14 +565,12 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
 	priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
 			DW_DMA_BASE_OFFSET);
 	priv->address = phy_addr;
+	priv->phy_configured = 0;
 
 	if (mac_reset(dev) < 0)
 		return -1;
 
-	if (configure_phy(dev) < 0) {
-		printf("Phy could not be configured\n");
-		return -1;
-	}
+	configure_phy(dev);
 
 	dev->init = dw_eth_init;
 	dev->send = dw_eth_send;

+ 2 - 1
drivers/net/designware.h

@@ -121,7 +121,7 @@ struct eth_dma_regs {
 #define RXSTART			(1 << 1)
 
 /* Descriptior related definitions */
-#define MAC_MAX_FRAME_SZ	(2048)
+#define MAC_MAX_FRAME_SZ	(1600)
 
 struct dmamacdescr {
 	u32 txrx_status;
@@ -238,6 +238,7 @@ struct dw_eth_dev {
 	u32 duplex;
 	u32 tx_currdescnum;
 	u32 rx_currdescnum;
+	u32 phy_configured;
 	u32 padding;
 
 	struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];

+ 2 - 0
drivers/net/mvgbe.c

@@ -52,6 +52,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define MV_PHY_ADR_REQUEST 0xee
 #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
 
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 /*
  * smi_reg_read - miiphy_read callback function.
  *
@@ -181,6 +182,7 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
 
 	return 0;
 }
+#endif
 
 /* Stop and checks all queues */
 static void stop_queue(u32 * qreg)

+ 399 - 0
drivers/net/xilinx_ll_temac.c

@@ -0,0 +1,399 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * supports SDMA or FIFO access and MDIO bus communication
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <miiphy.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_fifo.h"
+#include "xilinx_ll_temac_sdma.h"
+#include "xilinx_ll_temac_mdio.h"
+
+#if !defined(CONFIG_MII)
+# error "LL_TEMAC requires MII -- missing CONFIG_MII"
+#endif
+
+#if !defined(CONFIG_PHYLIB)
+# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
+#endif
+
+struct ll_temac_info {
+	int			flags;
+	unsigned long		base_addr;
+	unsigned long		ctrl_addr;
+	char			*devname;
+	unsigned int		phyaddr;
+	char			*mdio_busname;
+};
+
+/* Ethernet interface ready status */
+int ll_temac_check_status(struct temac_reg *regs, u32 mask)
+{
+	unsigned timeout = 50;	/* 1usec * 50 = 50usec */
+
+	/*
+	 * Quote from LL TEMAC documentation: The bits in the RDY
+	 * register are asserted when there is no access in progress.
+	 * When an access is in progress, a bit corresponding to the
+	 * type of access is automatically de-asserted. The bit is
+	 * automatically re-asserted when the access is complete.
+	 */
+	while (timeout && (!(in_be32(&regs->rdy) & mask))) {
+		timeout--;
+		udelay(1);
+	}
+
+	if (!timeout) {
+		printf("%s: Timeout on 0x%08x @%p\n", __func__,
+				mask, &regs->rdy);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Indirect write to ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 23, second paragraph, The use of CTL0 register or CTL1 register
+ */
+int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data)
+{
+	out_be32(&regs->lsw, (reg_data & MLSW_MASK));
+	out_be32(&regs->ctl, CTL_WEN | (regn & CTL_ADDR_MASK));
+
+	if (ll_temac_check_status(regs, RSE_CFG_WR))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Indirect read from ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 23, second paragraph, The use of CTL0 register or CTL1 register
+ */
+int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data)
+{
+	out_be32(&regs->ctl, (regn & CTL_ADDR_MASK));
+
+	if (ll_temac_check_status(regs, RSE_CFG_RR))
+		return 0;
+
+	*reg_data = in_be32(&regs->lsw) & MLSW_MASK;
+	return 1;
+}
+
+/* setting sub-controller and ll_temac to proper setting */
+static int ll_temac_setup_ctrl(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	if (ll_temac->ctrlreset && ll_temac->ctrlreset(dev))
+		return 0;
+
+	if (ll_temac->ctrlinit && ll_temac->ctrlinit(dev))
+		return 0;
+
+	/* Promiscuous mode disable */
+	if (!ll_temac_indirect_set(regs, TEMAC_AFM, 0))
+		return 0;
+
+	/* Enable Receiver - RX bit */
+	if (!ll_temac_indirect_set(regs, TEMAC_RCW1, RCW1_RX))
+		return 0;
+
+	/* Enable Transmitter - TX bit */
+	if (!ll_temac_indirect_set(regs, TEMAC_TC, TC_TX))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Configure ll_temac based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static int ll_temac_adjust_link(struct eth_device *dev)
+{
+	unsigned int speed, emmc_reg;
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+	struct ll_temac *ll_temac = dev->priv;
+	struct phy_device *phydev = ll_temac->phydev;
+
+	if (!phydev->link) {
+		printf("%s: No link.\n", phydev->dev->name);
+		return 0;
+	}
+
+	switch (phydev->speed) {
+	case 1000:
+		speed = EMMC_LSPD_1000;
+		break;
+	case 100:
+		speed = EMMC_LSPD_100;
+		break;
+	case 10:
+		speed = EMMC_LSPD_10;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!ll_temac_indirect_get(regs, TEMAC_EMMC, &emmc_reg))
+		return 0;
+
+	emmc_reg &= ~EMMC_LSPD_MASK;
+	emmc_reg |= speed;
+
+	if (!ll_temac_indirect_set(regs, TEMAC_EMMC, emmc_reg))
+		return 0;
+
+	printf("%s: PHY is %s with %dbase%s, %s%s\n",
+			dev->name, phydev->drv->name,
+			phydev->speed, (phydev->port == PORT_TP) ? "T" : "X",
+			(phydev->duplex) ? "FDX" : "HDX",
+			(phydev->port == PORT_OTHER) ? ", unkown mode" : "");
+
+	return 1;
+}
+
+/* setup mac addr */
+static int ll_temac_setup_mac_addr(struct eth_device *dev)
+{
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+	u32 val;
+
+	/* set up unicast MAC address filter */
+	val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) |
+			(dev->enetaddr[1] << 8) | (dev->enetaddr[0]));
+	val &= UAW0_UADDR_MASK;
+
+	if (!ll_temac_indirect_set(regs, TEMAC_UAW0, val))
+		return 1;
+
+	val = ((dev->enetaddr[5] << 8) | dev->enetaddr[4]);
+	val &= UAW1_UADDR_MASK;
+
+	if (!ll_temac_indirect_set(regs, TEMAC_UAW1, val))
+		return 1;
+
+	return 0;
+}
+
+/* halt device */
+static void ll_temac_halt(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	/* Disable Receiver */
+	ll_temac_indirect_set(regs, TEMAC_RCW0, 0);
+
+	/* Disable Transmitter */
+	ll_temac_indirect_set(regs, TEMAC_TC, 0);
+
+	if (ll_temac->ctrlhalt)
+		ll_temac->ctrlhalt(dev);
+
+	/* Shut down the PHY, as needed */
+	phy_shutdown(ll_temac->phydev);
+}
+
+static int ll_temac_init(struct eth_device *dev, bd_t *bis)
+{
+	struct ll_temac *ll_temac = dev->priv;
+
+	printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.\n",
+		dev->name, dev->index, dev->iobase);
+
+	if (!ll_temac_setup_ctrl(dev))
+		return -1;
+
+	/* Start up the PHY */
+	phy_startup(ll_temac->phydev);
+
+	if (!ll_temac_adjust_link(dev)) {
+		ll_temac_halt(dev);
+		return -1;
+	}
+
+	/* If there's no link, fail */
+	return ll_temac->phydev->link ? 0 : -1;
+}
+
+/*
+ * Discover which PHY is attached to the device, and configure it
+ * properly.  If the PHY is not recognized, then return 0
+ * (failure).  Otherwise, return 1
+ */
+static int ll_temac_phy_init(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct phy_device *phydev;
+	unsigned int supported = PHY_GBIT_FEATURES;
+
+	/* interface - look at driver/net/tsec.c */
+	phydev = phy_connect(ll_temac->bus, ll_temac->phyaddr,
+			dev, PHY_INTERFACE_MODE_NONE);
+
+	phydev->supported &= supported;
+	phydev->advertising = phydev->supported;
+
+	ll_temac->phydev = phydev;
+
+	phy_config(phydev);
+
+	return 1;
+}
+
+/*
+ * Initialize a single ll_temac devices
+ *
+ * Returns the result of ll_temac phy interface that were initialized
+ */
+int xilinx_ll_temac_initialize(bd_t *bis, struct ll_temac_info *devinf)
+{
+	struct eth_device *dev;
+	struct ll_temac *ll_temac;
+
+	dev = calloc(1, sizeof(*dev));
+	if (dev == NULL)
+		return 0;
+
+	ll_temac = calloc(1, sizeof(struct ll_temac));
+	if (ll_temac == NULL) {
+		free(dev);
+		return 0;
+	}
+
+	/* use given name or generate its own unique name */
+	if (devinf->devname) {
+		strncpy(dev->name, devinf->devname, NAMESIZE);
+	} else {
+		snprintf(dev->name, NAMESIZE, "lltemac.%lx", devinf->base_addr);
+		devinf->devname = dev->name;
+	}
+
+	dev->iobase = devinf->base_addr;
+
+	dev->priv = ll_temac;
+	dev->init = ll_temac_init;
+	dev->halt = ll_temac_halt;
+	dev->write_hwaddr = ll_temac_setup_mac_addr;
+
+	ll_temac->ctrladdr = devinf->ctrl_addr;
+	if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_PLB) {
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+		if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_DCR) {
+			ll_temac_collect_xldcr_sdma_reg_addr(dev);
+			ll_temac->in32 = ll_temac_xldcr_in32;
+			ll_temac->out32 = ll_temac_xldcr_out32;
+		} else
+#endif
+		{
+			ll_temac_collect_xlplb_sdma_reg_addr(dev);
+			ll_temac->in32 = ll_temac_xlplb_in32;
+			ll_temac->out32 = ll_temac_xlplb_out32;
+		}
+		ll_temac->ctrlinit = ll_temac_init_sdma;
+		ll_temac->ctrlhalt = ll_temac_halt_sdma;
+		ll_temac->ctrlreset = ll_temac_reset_sdma;
+		dev->recv = ll_temac_recv_sdma;
+		dev->send = ll_temac_send_sdma;
+	} else {
+		ll_temac->in32 = NULL;
+		ll_temac->out32 = NULL;
+		ll_temac->ctrlinit = NULL;
+		ll_temac->ctrlhalt = NULL;
+		ll_temac->ctrlreset = ll_temac_reset_fifo;
+		dev->recv = ll_temac_recv_fifo;
+		dev->send = ll_temac_send_fifo;
+	}
+
+	/* Link to specified MDIO bus */
+	strncpy(ll_temac->mdio_busname, devinf->mdio_busname, MDIO_NAME_LEN);
+	ll_temac->bus = miiphy_get_dev_by_name(ll_temac->mdio_busname);
+
+	/* Looking for a valid PHY address if it is not yet set */
+	if (devinf->phyaddr == -1)
+		ll_temac->phyaddr = ll_temac_phy_addr(ll_temac->bus);
+	else
+		ll_temac->phyaddr = devinf->phyaddr;
+
+	eth_register(dev);
+
+	/* Try to initialize PHY here, and return */
+	return ll_temac_phy_init(dev);
+}
+
+/*
+ * Initialize a single ll_temac device with its mdio bus behind ll_temac
+ *
+ * Returns 1 if the ll_temac device and the mdio bus were initialized
+ * otherwise returns 0
+ */
+int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags,
+							unsigned long ctrl_addr)
+{
+	struct ll_temac_info devinf;
+	struct ll_temac_mdio_info mdioinf;
+	int ret;
+
+	/* prepare the internal driver informations */
+	devinf.flags = flags;
+	devinf.base_addr = base_addr;
+	devinf.ctrl_addr = ctrl_addr;
+	devinf.devname = NULL;
+	devinf.phyaddr = -1;
+
+	mdioinf.name = devinf.mdio_busname = NULL;
+	mdioinf.regs = (struct temac_reg *)devinf.base_addr;
+
+	ret = xilinx_ll_temac_mdio_initialize(bis, &mdioinf);
+	if (ret >= 0) {
+
+		/*
+		 * If there was no MDIO bus name then take over the
+		 * new automaticaly generated by the MDIO init code.
+		 */
+		if (mdioinf.name != devinf.mdio_busname)
+			devinf.mdio_busname = mdioinf.name;
+
+		ret = xilinx_ll_temac_initialize(bis, &devinf);
+		if (ret > 0)
+			return 1;
+
+	}
+
+	return 0;
+}

+ 310 - 0
drivers/net/xilinx_ll_temac.h

@@ -0,0 +1,310 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * LL_TEMAC interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_
+#define _XILINX_LL_TEMAC_
+
+#include <config.h>
+#include <net.h>
+#include <phy.h>
+#include <miiphy.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include "xilinx_ll_temac_sdma.h"
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * TEMAC Memory and Register Definition
+ *
+ * [1]:	[0]/ip_documentation/xps_ll_temac.pdf
+ *	page 19, Memory and Register Descriptions
+ */
+struct temac_reg {
+	/* direct soft registers (low part) */
+	u32 raf;	/* Reset and Address Filter */
+	u32 tpf;	/* Transmit Pause Frame */
+	u32 ifgp;	/* Transmit Inter Frame Gap Adjustment */
+	u32 is;		/* Interrupt Status */
+	u32 ip;		/* Interrupt Pending */
+	u32 ie;		/* Interrupt Enable */
+	u32 ttag;	/* Transmit VLAN Tag */
+	u32 rtag;	/* Receive VLAN Tag */
+	/* hard TEMAC registers */
+	u32 msw;	/* Most Significant Word Data */
+	u32 lsw;	/* Least Significant Word Data */
+	u32 ctl;	/* Control */
+	u32 rdy;	/* Ready Status */
+	/* direct soft registers (high part) */
+	u32 uawl;	/* Unicast Address Word Lower */
+	u32 uawu;	/* Unicast Address Word Upper */
+	u32 tpid0;	/* VLAN TPID Word 0 */
+	u32 tpid1;	/* VLAN TPID Word 1 */
+};
+
+/* Reset and Address Filter Registers (raf), [1] p25 */
+#define RAF_SR			(1 << 13)
+#define RAF_EMFE		(1 << 12)
+#define RAF_NFE			(1 << 11)
+#define RAF_RVSTM_POS		9
+#define RAF_RVSTM_MASK		(3 << RAF_RVSTM_POS)
+#define RAF_TVSTM_POS		7
+#define RAF_TVSTM_MASK		(3 << RAF_TVSTM_POS)
+#define RAF_RVTM_POS		5
+#define RAF_RVTM_MASK		(3 << RAF_RVTM_POS)
+#define RAF_TVTM_POS		3
+#define RAF_TVTM_MASK		(3 << RAF_TVTM_POS)
+#define RAF_BCREJ		(1 << 2)
+#define RAF_MCREJ		(1 << 1)
+#define RAF_HTRST		(1 << 0)
+
+/* Transmit Pause Frame Registers (tpf), [1] p28 */
+#define TPF_TPFV_POS		0
+#define TPF_TPFV_MASK		(0xFFFF << TPF_TPFV_POS)
+
+/* Transmit Inter Frame Gap Adjustment Registers (ifgp), [1] p28 */
+#define IFGP_POS		0
+#define IFGP_MASK		(0xFF << IFGP_POS)
+
+/* Interrupt Status, Pending, Enable Registers (is, ip, ie), [1] p29-33 */
+#define ISPE_MR			(1 << 7)
+#define ISPE_RDL		(1 << 6)
+#define ISPE_TC			(1 << 5)
+#define ISPE_RFO		(1 << 4)
+#define ISPE_RR			(1 << 3)
+#define ISPE_RC			(1 << 2)
+#define ISPE_AN			(1 << 1)
+#define ISPE_HAC		(1 << 0)
+
+/* Transmit, Receive VLAN Tag Registers (ttag, rtag), [1] p34-35 */
+#define TRTAG_TPID_POS		16
+#define TRTAG_TPID_MASK		(0xFFFF << TRTAG_TPID_POS)
+#define TRTAG_PRIO_POS		13
+#define TRTAG_PRIO_MASK		(7 << TRTAG_PRIO_POS)
+#define TRTAG_CFI		(1 << 12)
+#define TRTAG_VID_POS		0
+#define TRTAG_VID_MASK		(0xFFF << TRTAG_VID_POS)
+
+/* Most, Least Significant Word Data Register (msw, lsw), [1] p46 */
+#define MLSW_POS		0
+#define MLSW_MASK		(~0UL << MLSW_POS)
+
+/* LSW Data Register for PHY addresses (lsw), [1] p66 */
+#define LSW_REGAD_POS		0
+#define LSW_REGAD_MASK		(0x1F << LSW_REGAD_POS)
+#define LSW_PHYAD_POS		5
+#define LSW_PHYAD_MASK		(0x1F << LSW_PHYAD_POS)
+
+/* LSW Data Register for PHY data (lsw), [1] p66 */
+#define LSW_REGDAT_POS		0
+#define LSW_REGDAT_MASK		(0xFFFF << LSW_REGDAT_POS)
+
+/* Control Register (ctl), [1] p47 */
+#define CTL_WEN			(1 << 15)
+#define CTL_ADDR_POS		0
+#define CTL_ADDR_MASK		(0x3FF << CTL_ADDR_POS)
+
+/* Ready Status Register Ethernet (rdy), [1] p48 */
+#define RSE_HACS_RDY		(1 << 14)
+#define RSE_CFG_WR		(1 << 6)
+#define RSE_CFG_RR		(1 << 5)
+#define RSE_AF_WR		(1 << 4)
+#define RSE_AF_RR		(1 << 3)
+#define RSE_MIIM_WR		(1 << 2)
+#define RSE_MIIM_RR		(1 << 1)
+#define RSE_FABR_RR		(1 << 0)
+
+/* Unicast Address Word Lower, Upper Registers (uawl, uawu), [1] p35-36 */
+#define UAWL_UADDR_POS		0
+#define UAWL_UADDR_MASK		(~0UL << UAWL_UADDR_POS)
+#define UAWU_UADDR_POS		0
+#define UAWU_UADDR_MASK		(0xFFFF << UAWU_UADDR_POS)
+
+/* VLAN TPID Word 0, 1 Registers (tpid0, tpid1), [1] p37 */
+#define TPID0_V0_POS		0
+#define TPID0_V0_MASK		(0xFFFF << TPID0_V0_POS)
+#define TPID0_V1_POS		16
+#define TPID0_V1_MASK		(0xFFFF << TPID0_V1_POS)
+#define TPID1_V2_POS		0
+#define TPID1_V2_MASK		(0xFFFF << TPID1_V2_POS)
+#define TPID1_V3_POS		16
+#define TPID1_V3_MASK		(0xFFFF << TPID1_V3_POS)
+
+/*
+ * TEMAC Indirectly Addressable Register Index Enumeration
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [1]:	[0]/ip_documentation/xps_ll_temac.pdf
+ *	page 23, PLB Indirectly Addressable TEMAC Registers
+ */
+enum temac_ctrl {
+	TEMAC_RCW0	= 0x200,
+	TEMAC_RCW1	= 0x240,
+	TEMAC_TC	= 0x280,
+	TEMAC_FCC	= 0x2C0,
+	TEMAC_EMMC	= 0x300,
+	TEMAC_PHYC	= 0x320,
+	TEMAC_MC	= 0x340,
+	TEMAC_UAW0	= 0x380,
+	TEMAC_UAW1	= 0x384,
+	TEMAC_MAW0	= 0x388,
+	TEMAC_MAW1	= 0x38C,
+	TEMAC_AFM	= 0x390,
+	TEMAC_TIS	= 0x3A0,
+	TEMAC_TIE	= 0x3A4,
+	TEMAC_MIIMWD	= 0x3B0,
+	TEMAC_MIIMAI	= 0x3B4
+};
+
+/* Receive Configuration Word 0, 1 Registers (RCW0, RCW1), [1] p50-51 */
+#define RCW0_PADDR_POS		0
+#define RCW0_PADDR_MASK		(~0UL << RCW_PADDR_POS)
+#define RCW1_RST		(1 << 31)
+#define RCW1_JUM		(1 << 30)
+#define RCW1_FCS		(1 << 29)
+#define RCW1_RX			(1 << 28)
+#define RCW1_VLAN		(1 << 27)
+#define RCW1_HD			(1 << 26)
+#define RCW1_LT_DIS		(1 << 25)
+#define RCW1_PADDR_POS		0
+#define RCW1_PADDR_MASK		(0xFFFF << RCW_PADDR_POS)
+
+/* Transmit Configuration Registers (TC), [1] p52 */
+#define TC_RST			(1 << 31)
+#define TC_JUM			(1 << 30)
+#define TC_FCS			(1 << 29)
+#define TC_TX			(1 << 28)
+#define TC_VLAN			(1 << 27)
+#define TC_HD			(1 << 26)
+#define TC_IFG			(1 << 25)
+
+/* Flow Control Configuration Registers (FCC), [1] p54 */
+#define FCC_FCTX		(1 << 30)
+#define FCC_FCRX		(1 << 29)
+
+/* Ethernet MAC Mode Configuration Registers (EMMC), [1] p54 */
+#define EMMC_LSPD_POS		30
+#define EMMC_LSPD_MASK		(3 << EMMC_LSPD_POS)
+#define EMMC_LSPD_1000		(2 << EMMC_LSPD_POS)
+#define EMMC_LSPD_100		(1 << EMMC_LSPD_POS)
+#define EMMC_LSPD_10		0
+#define EMMC_RGMII		(1 << 29)
+#define EMMC_SGMII		(1 << 28)
+#define EMMC_GPCS		(1 << 27)
+#define EMMC_HOST		(1 << 26)
+#define EMMC_TX16		(1 << 25)
+#define EMMC_RX16		(1 << 24)
+
+/* RGMII/SGMII Configuration Registers (PHYC), [1] p56 */
+#define PHYC_SLSPD_POS		30
+#define PHYC_SLSPD_MASK		(3 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_1000		(2 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_100		(1 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_10		0
+#define PHYC_RLSPD_POS		2
+#define PHYC_RLSPD_MASK		(3 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_1000		(2 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_100		(1 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_10		0
+#define PHYC_RGMII_HD		(1 << 1)
+#define PHYC_RGMII_LINK		(1 << 0)
+
+/* Management Configuration Registers (MC), [1] p57 */
+#define MC_MDIOEN		(1 << 6)
+#define MC_CLKDIV_POS		0
+#define MC_CLKDIV_MASK		(0x3F << MC_CLKDIV_POS)
+
+/*
+ *             fHOSTCLK          fMDC =                  fHOSTCLK
+ * fMDC = -------------------   --------->   MC_CLKDIV = -------- - 1
+ *        (1 + MC_CLKDIV) * 2    2.5 MHz                   5MHz
+ */
+#define MC_CLKDIV(f, m)		((f / (2 * m)) - 1)
+#define MC_CLKDIV_25(f)		MC_CLKDIV(f, 2500000)
+#define MC_CLKDIV_20(f)		MC_CLKDIV(f, 2000000)
+#define MC_CLKDIV_15(f)		MC_CLKDIV(f, 1500000)
+#define MC_CLKDIV_10(f)		MC_CLKDIV(f, 1000000)
+
+/* Unicast Address Word 0, 1 Registers (UAW0, UAW1), [1] p58-59 */
+#define UAW0_UADDR_POS		0
+#define UAW0_UADDR_MASK		(~0UL << UAW0_UADDR_POS)
+#define UAW1_UADDR_POS		0
+#define UAW1_UADDR_MASK		(0xFFFF << UAW1_UADDR_POS)
+
+/* Multicast Address Word 0, 1 Registers (MAW0, MAW1), [1] p60 */
+#define MAW0_MADDR_POS		0
+#define MAW0_MADDR_MASK		(~0UL << MAW0_MADDR_POS)
+#define MAW1_RNW		(1 << 23)
+#define MAW1_MAIDX_POS		16
+#define MAW1_MAIDX_MASK		(3 << MAW1_MAIDX_POS)
+#define MAW1_MADDR_POS		0
+#define MAW1_MADDR_MASK		(0xFFFF << MAW1_MADDR_POS)
+
+/* Address Filter Mode Registers (AFM), [1] p63 */
+#define AFM_PM			(1 << 31)
+
+/* Interrupt Status, Enable Registers (TIS, TIE), [1] p63-65 */
+#define TISE_CFG_W		(1 << 6)
+#define TISE_CFG_R		(1 << 5)
+#define TISE_AF_W		(1 << 4)
+#define TISE_AF_R		(1 << 3)
+#define TISE_MIIM_W		(1 << 2)
+#define TISE_MIIM_R		(1 << 1)
+#define TISE_FABR_R		(1 << 0)
+
+/* MII Management Write Data Registers (MIIMWD), [1] p66 */
+#define MIIMWD_DATA_POS		0
+#define MIIMWD_DATA_MASK	(0xFFFF << MIIMWD_DATA_POS)
+
+/* Ethernet interface ready status */
+int ll_temac_check_status(struct temac_reg *regs, u32 mask);
+
+/* Indirect write to ll_temac. */
+int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data);
+
+/* Indirect read from ll_temac. */
+int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data);
+
+struct ll_temac {
+	phys_addr_t		ctrladdr;
+	phys_addr_t		sdma_reg_addr[SDMA_CTRL_REGNUMS];
+
+	unsigned		(*in32)(phys_addr_t);
+	void			(*out32)(phys_addr_t, unsigned);
+
+	int			(*ctrlinit) (struct eth_device *);
+	int			(*ctrlhalt) (struct eth_device *);
+	int			(*ctrlreset) (struct eth_device *);
+
+	int			phyaddr;
+	struct phy_device	*phydev;
+	struct mii_dev		*bus;
+	char			mdio_busname[MDIO_NAME_LEN];
+};
+
+#endif /* _XILINX_LL_TEMAC_ */

+ 143 - 0
drivers/net/xilinx_ll_temac_fifo.c

@@ -0,0 +1,143 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO sub-controller
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [F]:	[0]/ip_documentation/xps_ll_fifo.pdf
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_fifo.h"
+
+int ll_temac_reset_fifo(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+	out_be32(&fifo_ctrl->tdfr, LL_FIFO_TDFR_KEY);
+	out_be32(&fifo_ctrl->rdfr, LL_FIFO_RDFR_KEY);
+	out_be32(&fifo_ctrl->isr, ~0UL);
+	out_be32(&fifo_ctrl->ier, 0);
+
+	return 0;
+}
+
+int ll_temac_recv_fifo(struct eth_device *dev)
+{
+	int i, length = 0;
+	u32 *buf = (u32 *)NetRxPackets[0];
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+	if (in_be32(&fifo_ctrl->isr) & LL_FIFO_ISR_RC) {
+
+		/* reset isr */
+		out_be32(&fifo_ctrl->isr, ~0UL);
+
+		/*
+		 * MAYBE here:
+		 *   while (fifo_ctrl->isr);
+		 */
+
+		/*
+		 * The length is written (into RLR) by the XPS LL FIFO
+		 * when the packet is received across the RX LocalLink
+		 * interface and the receive data FIFO had enough
+		 * locations that all of the packet data has been saved.
+		 * The RLR should only be read when a receive packet is
+		 * available for processing (the receive occupancy is
+		 * not zero). Once the RLR is read, the receive packet
+		 * data should be read from the receive data FIFO before
+		 * the RLR is read again.
+		 *
+		 * [F] page 17, Receive Length Register (RLR)
+		 */
+		if (in_be32(&fifo_ctrl->rdfo) & LL_FIFO_RDFO_MASK) {
+			length = in_be32(&fifo_ctrl->rlf) & LL_FIFO_RLF_MASK;
+		} else {
+			printf("%s: Got error, no receive occupancy\n",
+					__func__);
+			return -1;
+		}
+
+		if (length > PKTSIZE_ALIGN) {
+			printf("%s: Got error, receive package too big (%i)\n",
+					__func__, length);
+			ll_temac_reset_fifo(dev);
+			return -1;
+		}
+
+		for (i = 0; i < length; i += 4)
+			*buf++ = in_be32(&fifo_ctrl->rdfd);
+
+		NetReceive(NetRxPackets[0], length);
+	}
+
+	return 0;
+}
+
+int ll_temac_send_fifo(struct eth_device *dev, volatile void *packet,
+							int length)
+{
+	int i;
+	u32 *buf = (u32 *)packet;
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+	if (length < LL_FIFO_TLF_MIN) {
+		printf("%s: Got error, transmit package too small (%i)\n",
+				__func__, length);
+		return -1;
+	}
+
+	if (length > LL_FIFO_TLF_MAX) {
+		printf("%s: Got error, transmit package too big (%i)\n",
+				__func__, length);
+		return -1;
+	}
+
+	for (i = 0; i < length; i += 4)
+		out_be32(&fifo_ctrl->tdfd, *buf++);
+
+	/*
+	 * Once the packet length is written to the TLR it is
+	 * automatically moved to the transmit data FIFO with
+	 * the packet data freeing up the TLR for another value.
+	 * The packet length must be written to the TLR after
+	 * the packet data is written to the transmit data FIFO.
+	 * It is not valid to write data for multiple packets
+	 * to the transmit data FIFO before writing the packet
+	 * length values.
+	 *
+	 * [F] page 17, Transmit Length Register (TLR)
+	 */
+	out_be32(&fifo_ctrl->tlf, length);
+
+	return 0;
+}

+ 122 - 0
drivers/net/xilinx_ll_temac_fifo.h

@@ -0,0 +1,122 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO sub-controller interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_FIFO_
+#define _XILINX_LL_TEMAC_FIFO_
+
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * FIFO Register Definition
+ *
+ * Used for memory mapped access from and to (Rd/Td) the LocalLink (LL)
+ * Tri-Mode Ether MAC (TEMAC) via the 2 kb full duplex FIFO Controller,
+ * one for each.
+ *
+ * [1]: [0]/ip_documentation/xps_ll_fifo.pdf
+ *      page 10, Registers Definition
+ */
+struct fifo_ctrl {
+	u32 isr;	/* Interrupt Status Register (RW) */
+	u32 ier;	/* Interrupt Enable Register (RW) */
+	u32 tdfr;	/* Transmit Data FIFO Reset (WO) */
+	u32 tdfv;	/* Transmit Data FIFO Vacancy (RO) */
+	u32 tdfd;	/* Transmit Data FIFO 32bit wide Data write port (WO) */
+	u32 tlf;	/* Transmit Length FIFO (WO) */
+	u32 rdfr;	/* Receive Data FIFO Reset (WO) */
+	u32 rdfo;	/* Receive Data FIFO Occupancy (RO) */
+	u32 rdfd;	/* Receive Data FIFO 32bit wide Data read port (RO) */
+	u32 rlf;	/* Receive Length FIFO (RO) */
+	u32 llr;	/* LocalLink Reset (WO) */
+};
+
+/* Interrupt Status Register (ISR), [1] p11 */
+#define LL_FIFO_ISR_RPURE	(1 << 31) /* Receive Packet Underrun Read Err */
+#define LL_FIFO_ISR_RPORE	(1 << 30) /* Receive Packet Overrun Read Err */
+#define LL_FIFO_ISR_RPUE	(1 << 29) /* Receive Packet Underrun Error */
+#define LL_FIFO_ISR_TPOE	(1 << 28) /* Transmit Packet Overrun Error */
+#define LL_FIFO_ISR_TC		(1 << 27) /* Transmit Complete */
+#define LL_FIFO_ISR_RC		(1 << 26) /* Receive Complete */
+#define LL_FIFO_ISR_TSE		(1 << 25) /* Transmit Size Error */
+#define LL_FIFO_ISR_TRC		(1 << 24) /* Transmit Reset Complete */
+#define LL_FIFO_ISR_RRC		(1 << 23) /* Receive Reset Complete */
+
+/* Interrupt Enable Register (IER), [1] p12/p13 */
+#define LL_FIFO_IER_RPURE	(1 << 31) /* Receive Packet Underrun Read Err */
+#define LL_FIFO_IER_RPORE	(1 << 30) /* Receive Packet Overrun Read Err */
+#define LL_FIFO_IER_RPUE	(1 << 29) /* Receive Packet Underrun Error */
+#define LL_FIFO_IER_TPOE	(1 << 28) /* Transmit Packet Overrun Error */
+#define LL_FIFO_IER_TC		(1 << 27) /* Transmit Complete */
+#define LL_FIFO_IER_RC		(1 << 26) /* Receive Complete */
+#define LL_FIFO_IER_TSE		(1 << 25) /* Transmit Size Error */
+#define LL_FIFO_IER_TRC		(1 << 24) /* Transmit Reset Complete */
+#define LL_FIFO_IER_RRC		(1 << 23) /* Receive Reset Complete */
+
+/* Transmit Data FIFO Reset (TDFR), [1] p13/p14 */
+#define LL_FIFO_TDFR_KEY	0x000000A5UL
+
+/* Transmit Data FIFO Vacancy (TDFV), [1] p14 */
+#define LL_FIFO_TDFV_POS	0
+#define LL_FIFO_TDFV_MASK	(0x000001FFUL << LL_FIFO_TDFV_POS)
+
+/* Transmit Length FIFO (TLF), [1] p16/p17 */
+#define LL_FIFO_TLF_POS		0
+#define LL_FIFO_TLF_MASK	(0x000007FFUL << LL_FIFO_TLF_POS)
+#define LL_FIFO_TLF_MIN		((4 * sizeof(u32)) & LL_FIFO_TLF_MASK)
+#define LL_FIFO_TLF_MAX		((510 * sizeof(u32)) & LL_FIFO_TLF_MASK)
+
+/* Receive Data FIFO Reset (RDFR), [1] p15 */
+#define LL_FIFO_RDFR_KEY	0x000000A5UL
+
+/* Receive Data FIFO Occupancy (RDFO), [1] p16 */
+#define LL_FIFO_RDFO_POS	0
+#define LL_FIFO_RDFO_MASK	(0x000001FFUL << LL_FIFO_RDFO_POS)
+
+/* Receive Length FIFO (RLF), [1] p17/p18 */
+#define LL_FIFO_RLF_POS		0
+#define LL_FIFO_RLF_MASK	(0x000007FFUL << LL_FIFO_RLF_POS)
+#define LL_FIFO_RLF_MIN		((4 * sizeof(uint32)) & LL_FIFO_RLF_MASK)
+#define LL_FIFO_RLF_MAX		((510 * sizeof(uint32)) & LL_FIFO_RLF_MASK)
+
+/* LocalLink Reset (LLR), [1] p18 */
+#define LL_FIFO_LLR_KEY		0x000000A5UL
+
+
+/* reset FIFO and IRQ, disable interrupts */
+int ll_temac_reset_fifo(struct eth_device *dev);
+
+/* receive buffered data from FIFO (polling ISR) */
+int ll_temac_recv_fifo(struct eth_device *dev);
+
+/* send buffered data to FIFO */
+int ll_temac_send_fifo(struct eth_device *dev, volatile void *packet,
+							int length);
+
+#endif /* _XILINX_LL_TEMAC_FIFO_ */

+ 180 - 0
drivers/net/xilinx_ll_temac_mdio.c

@@ -0,0 +1,180 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * MDIO bus access
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_mdio.h"
+
+#if !defined(CONFIG_MII)
+# error "LL_TEMAC requires MII -- missing CONFIG_MII"
+#endif
+
+#if !defined(CONFIG_PHYLIB)
+# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
+#endif
+
+/*
+ * Prior to PHY access, the MDIO clock must be setup. This driver will set a
+ * safe default that should work with PLB bus speeds of up to 150 MHz and keep
+ * the MDIO clock below 2.5 MHz. If the user wishes faster access to the PHY
+ * then the clock divisor can be set to a different value by setting the
+ * correct bus speed value with CONFIG_XILINX_LL_TEMAC_CLK.
+ */
+#if !defined(CONFIG_XILINX_LL_TEMAC_CLK)
+#define MDIO_CLOCK_DIV		MC_CLKDIV_10(150000000)
+#else
+#define MDIO_CLOCK_DIV		MC_CLKDIV_25(CONFIG_XILINX_LL_TEMAC_CLK)
+#endif
+
+static int ll_temac_mdio_setup(struct mii_dev *bus)
+{
+	struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+	/* setup MDIO clock */
+	ll_temac_indirect_set(regs, TEMAC_MC,
+			MC_MDIOEN | (MDIO_CLOCK_DIV & MC_CLKDIV_MASK));
+
+	return 0;
+}
+
+/*
+ * Indirect MII PHY read via ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
+				int regnum)
+{
+	out_be32(&regs->lsw,
+		((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+		(regnum & LSW_REGAD_MASK));
+	out_be32(&regs->ctl, TEMAC_MIIMAI);
+
+	ll_temac_check_status(regs, RSE_MIIM_RR);
+
+	return in_be32(&regs->lsw) & LSW_REGDAT_MASK;
+}
+
+/*
+ * Indirect MII PHY write via ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
+				int regnum, u16 value)
+{
+	out_be32(&regs->lsw, (value & LSW_REGDAT_MASK));
+	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
+
+	out_be32(&regs->lsw,
+		((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+		(regnum & LSW_REGAD_MASK));
+	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
+
+	ll_temac_check_status(regs, RSE_MIIM_WR);
+}
+
+int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
+{
+	struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+	return ll_temac_local_mdio_read(regs, addr, devad, regnum);
+}
+
+int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
+			u16 value)
+{
+	struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+	ll_temac_local_mdio_write(regs, addr, devad, regnum, value);
+
+	return 0;
+}
+
+/*
+ * Use MII register 1 (MII status register) to detect PHY
+ *
+ * A Mask used to verify certain PHY features (register content)
+ * in the PHY detection register:
+ *  Auto-negotiation support, 10Mbps half/full duplex support
+ */
+#define PHY_DETECT_REG		MII_BMSR
+#define PHY_DETECT_MASK		(BMSR_10FULL | BMSR_10HALF | BMSR_ANEGCAPABLE)
+
+/* Looking for a valid PHY address */
+int ll_temac_phy_addr(struct mii_dev *bus)
+{
+	struct temac_reg *regs = (struct temac_reg *)bus->priv;
+	unsigned short val;
+	unsigned int phy;
+
+	for (phy = PHY_MAX_ADDR; phy >= 0; phy--) {
+		val = ll_temac_local_mdio_read(regs, phy, 0, PHY_DETECT_REG);
+		if ((val != 0xFFFF) &&
+		((val & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+			/* Found a valid PHY address */
+			return phy;
+		}
+	}
+
+	return -1;
+}
+
+int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info)
+{
+	struct mii_dev *bus = mdio_alloc();
+
+	if (!bus) {
+		printf("Failed to allocate LL_TEMAC MDIO bus: %s\n",
+				info->name);
+		return -1;
+	}
+
+	bus->read = ll_temac_phy_read;
+	bus->write = ll_temac_phy_write;
+	bus->reset = NULL;
+
+	/* use given name or generate its own unique name */
+	if (info->name) {
+		strncpy(bus->name, info->name, MDIO_NAME_LEN);
+	} else {
+		snprintf(bus->name, MDIO_NAME_LEN, "lltemii.%p", info->regs);
+		info->name = bus->name;
+	}
+
+	bus->priv = info->regs;
+
+	ll_temac_mdio_setup(bus);
+	return mdio_register(bus);
+}

+ 53 - 0
drivers/net/xilinx_ll_temac_mdio.h

@@ -0,0 +1,53 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * MDIO bus access interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_MDIO_
+#define _XILINX_LL_TEMAC_MDIO_
+
+#include <net.h>
+#include <miiphy.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include "xilinx_ll_temac.h"
+
+int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
+				int regnum);
+void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
+				int regnum, u16 value);
+
+int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum);
+int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
+			u16 value);
+
+int ll_temac_phy_addr(struct mii_dev *bus);
+
+struct ll_temac_mdio_info {
+	struct temac_reg *regs;
+	char *name;
+};
+
+int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info);
+
+#endif /* _XILINX_LL_TEMAC_MDIO_ */

+ 370 - 0
drivers/net/xilinx_ll_temac_sdma.c

@@ -0,0 +1,370 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA sub-controller
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [M]:	[0]/ip_documentation/mpmc.pdf
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_sdma.h"
+
+#define TX_BUF_CNT		2
+
+static unsigned int rx_idx;	/* index of the current RX buffer */
+static unsigned int tx_idx;	/* index of the current TX buffer */
+
+struct rtx_cdmac_bd {
+	struct cdmac_bd rx[PKTBUFSRX];
+	struct cdmac_bd tx[TX_BUF_CNT];
+};
+
+/*
+ * DMA Buffer Descriptor alignment
+ *
+ * If the address contained in the Next Descriptor Pointer register is not
+ * 8-word aligned or reaches beyond the range of available memory, the SDMA
+ * halts processing and sets the CDMAC_BD_STCTRL_ERROR bit in the respective
+ * status register (tx_chnl_sts or rx_chnl_sts).
+ *
+ * [1]: [0]/ip_documentation/mpmc.pdf
+ *      page 161, Next Descriptor Pointer
+ */
+static struct rtx_cdmac_bd cdmac_bd __aligned(32);
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+
+/*
+ * Indirect DCR access operations mi{ft}dcr_xilinx() espacialy
+ * for Xilinx PowerPC implementations on FPGA.
+ *
+ * FIXME: This part should go up to arch/powerpc -- but where?
+ */
+#include <asm/processor.h>
+#define XILINX_INDIRECT_DCR_ADDRESS_REG	0
+#define XILINX_INDIRECT_DCR_ACCESS_REG	1
+inline unsigned mifdcr_xilinx(const unsigned dcrn)
+{
+	mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+	return mfdcr(XILINX_INDIRECT_DCR_ACCESS_REG);
+}
+inline void mitdcr_xilinx(const unsigned dcrn, int val)
+{
+	mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+	mtdcr(XILINX_INDIRECT_DCR_ACCESS_REG, val);
+}
+
+/* Xilinx Device Control Register (DCR) in/out accessors */
+inline unsigned ll_temac_xldcr_in32(phys_addr_t addr)
+{
+	return mifdcr_xilinx((const unsigned)addr);
+}
+inline void ll_temac_xldcr_out32(phys_addr_t addr, unsigned value)
+{
+	mitdcr_xilinx((const unsigned)addr, value);
+}
+
+void ll_temac_collect_xldcr_sdma_reg_addr(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t dmac_ctrl = ll_temac->ctrladdr;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	ra[TX_NXTDESC_PTR]   = dmac_ctrl + TX_NXTDESC_PTR;
+	ra[TX_CURBUF_ADDR]   = dmac_ctrl + TX_CURBUF_ADDR;
+	ra[TX_CURBUF_LENGTH] = dmac_ctrl + TX_CURBUF_LENGTH;
+	ra[TX_CURDESC_PTR]   = dmac_ctrl + TX_CURDESC_PTR;
+	ra[TX_TAILDESC_PTR]  = dmac_ctrl + TX_TAILDESC_PTR;
+	ra[TX_CHNL_CTRL]     = dmac_ctrl + TX_CHNL_CTRL;
+	ra[TX_IRQ_REG]       = dmac_ctrl + TX_IRQ_REG;
+	ra[TX_CHNL_STS]      = dmac_ctrl + TX_CHNL_STS;
+	ra[RX_NXTDESC_PTR]   = dmac_ctrl + RX_NXTDESC_PTR;
+	ra[RX_CURBUF_ADDR]   = dmac_ctrl + RX_CURBUF_ADDR;
+	ra[RX_CURBUF_LENGTH] = dmac_ctrl + RX_CURBUF_LENGTH;
+	ra[RX_CURDESC_PTR]   = dmac_ctrl + RX_CURDESC_PTR;
+	ra[RX_TAILDESC_PTR]  = dmac_ctrl + RX_TAILDESC_PTR;
+	ra[RX_CHNL_CTRL]     = dmac_ctrl + RX_CHNL_CTRL;
+	ra[RX_IRQ_REG]       = dmac_ctrl + RX_IRQ_REG;
+	ra[RX_CHNL_STS]      = dmac_ctrl + RX_CHNL_STS;
+	ra[DMA_CONTROL_REG]  = dmac_ctrl + DMA_CONTROL_REG;
+}
+
+#endif /* CONFIG_XILINX_440 || ONFIG_XILINX_405 */
+
+/* Xilinx Processor Local Bus (PLB) in/out accessors */
+inline unsigned ll_temac_xlplb_in32(phys_addr_t addr)
+{
+	return in_be32((void *)addr);
+}
+inline void ll_temac_xlplb_out32(phys_addr_t addr, unsigned value)
+{
+	out_be32((void *)addr, value);
+}
+
+/* collect all register addresses for Xilinx PLB in/out accessors */
+void ll_temac_collect_xlplb_sdma_reg_addr(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	ra[TX_NXTDESC_PTR]   = (phys_addr_t)&sdma_ctrl->tx_nxtdesc_ptr;
+	ra[TX_CURBUF_ADDR]   = (phys_addr_t)&sdma_ctrl->tx_curbuf_addr;
+	ra[TX_CURBUF_LENGTH] = (phys_addr_t)&sdma_ctrl->tx_curbuf_length;
+	ra[TX_CURDESC_PTR]   = (phys_addr_t)&sdma_ctrl->tx_curdesc_ptr;
+	ra[TX_TAILDESC_PTR]  = (phys_addr_t)&sdma_ctrl->tx_taildesc_ptr;
+	ra[TX_CHNL_CTRL]     = (phys_addr_t)&sdma_ctrl->tx_chnl_ctrl;
+	ra[TX_IRQ_REG]       = (phys_addr_t)&sdma_ctrl->tx_irq_reg;
+	ra[TX_CHNL_STS]      = (phys_addr_t)&sdma_ctrl->tx_chnl_sts;
+	ra[RX_NXTDESC_PTR]   = (phys_addr_t)&sdma_ctrl->rx_nxtdesc_ptr;
+	ra[RX_CURBUF_ADDR]   = (phys_addr_t)&sdma_ctrl->rx_curbuf_addr;
+	ra[RX_CURBUF_LENGTH] = (phys_addr_t)&sdma_ctrl->rx_curbuf_length;
+	ra[RX_CURDESC_PTR]   = (phys_addr_t)&sdma_ctrl->rx_curdesc_ptr;
+	ra[RX_TAILDESC_PTR]  = (phys_addr_t)&sdma_ctrl->rx_taildesc_ptr;
+	ra[RX_CHNL_CTRL]     = (phys_addr_t)&sdma_ctrl->rx_chnl_ctrl;
+	ra[RX_IRQ_REG]       = (phys_addr_t)&sdma_ctrl->rx_irq_reg;
+	ra[RX_CHNL_STS]      = (phys_addr_t)&sdma_ctrl->rx_chnl_sts;
+	ra[DMA_CONTROL_REG]  = (phys_addr_t)&sdma_ctrl->dma_control_reg;
+}
+
+/* Check for TX and RX channel errors. */
+static inline int ll_temac_sdma_error(struct eth_device *dev)
+{
+	int err;
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	err = ll_temac->in32(ra[TX_CHNL_STS]) & CHNL_STS_ERROR;
+	err |= ll_temac->in32(ra[RX_CHNL_STS]) & CHNL_STS_ERROR;
+
+	return err;
+}
+
+int ll_temac_init_sdma(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct cdmac_bd *rx_dp;
+	struct cdmac_bd *tx_dp;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+	int i;
+
+	printf("%s: SDMA: %d Rx buffers, %d Tx buffers\n",
+			dev->name, PKTBUFSRX, TX_BUF_CNT);
+
+	/* Initialize the Rx Buffer descriptors */
+	for (i = 0; i < PKTBUFSRX; i++) {
+		rx_dp = &cdmac_bd.rx[i];
+		memset(rx_dp, 0, sizeof(*rx_dp));
+		rx_dp->next_p = rx_dp;
+		rx_dp->buf_len = PKTSIZE_ALIGN;
+		rx_dp->phys_buf_p = (u8 *)NetRxPackets[i];
+		flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
+	}
+	flush_cache((u32)cdmac_bd.rx, sizeof(cdmac_bd.rx));
+
+	/* Initialize the TX Buffer Descriptors */
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		tx_dp = &cdmac_bd.tx[i];
+		memset(tx_dp, 0, sizeof(*tx_dp));
+		tx_dp->next_p = tx_dp;
+	}
+	flush_cache((u32)cdmac_bd.tx, sizeof(cdmac_bd.tx));
+
+	/* Reset index counter to the Rx and Tx Buffer descriptors */
+	rx_idx = tx_idx = 0;
+
+	/* initial Rx DMA start by writing to respective TAILDESC_PTR */
+	ll_temac->out32(ra[RX_CURDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+	ll_temac->out32(ra[RX_TAILDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+
+	return 0;
+}
+
+int ll_temac_halt_sdma(struct eth_device *dev)
+{
+	unsigned timeout = 50;	/* 1usec * 50 = 50usec */
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	/*
+	 * Soft reset the DMA
+	 *
+	 * Quote from MPMC documentation: Writing a 1 to this field
+	 * forces the DMA engine to shutdown and reset itself. After
+	 * setting this bit, software must poll it until the bit is
+	 * cleared by the DMA. This indicates that the reset process
+	 * is done and the pipeline has been flushed.
+	 */
+	ll_temac->out32(ra[DMA_CONTROL_REG], DMA_CONTROL_RESET);
+	while (timeout && (ll_temac->in32(ra[DMA_CONTROL_REG])
+					& DMA_CONTROL_RESET)) {
+		timeout--;
+		udelay(1);
+	}
+
+	if (!timeout) {
+		printf("%s: Timeout\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+int ll_temac_reset_sdma(struct eth_device *dev)
+{
+	u32 r;
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	/* Soft reset the DMA.  */
+	if (ll_temac_halt_sdma(dev))
+		return -1;
+
+	/* Now clear the interrupts.  */
+	r = ll_temac->in32(ra[TX_CHNL_CTRL]);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	ll_temac->out32(ra[TX_CHNL_CTRL], r);
+
+	r = ll_temac->in32(ra[RX_CHNL_CTRL]);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	ll_temac->out32(ra[RX_CHNL_CTRL], r);
+
+	/* Now ACK pending IRQs.  */
+	ll_temac->out32(ra[TX_IRQ_REG], IRQ_REG_IRQ_MASK);
+	ll_temac->out32(ra[RX_IRQ_REG], IRQ_REG_IRQ_MASK);
+
+	/* Set tail-ptr mode, disable errors for both channels.  */
+	ll_temac->out32(ra[DMA_CONTROL_REG],
+			/* Enable use of tail pointer register */
+			DMA_CONTROL_TPE |
+			/* Disable error when 2 or 4 bit coalesce cnt overfl */
+			DMA_CONTROL_RXOCEID |
+			/* Disable error when 2 or 4 bit coalesce cnt overfl */
+			DMA_CONTROL_TXOCEID);
+
+	return 0;
+}
+
+int ll_temac_recv_sdma(struct eth_device *dev)
+{
+	int length, pb_idx;
+	struct cdmac_bd *rx_dp = &cdmac_bd.rx[rx_idx];
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	if (ll_temac_sdma_error(dev)) {
+
+		if (ll_temac_reset_sdma(dev))
+			return -1;
+
+		ll_temac_init_sdma(dev);
+	}
+
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+	if (!(rx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED))
+		return 0;
+
+	if (rx_dp->sca.stctrl & (CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP)) {
+		pb_idx = rx_idx;
+		length = rx_dp->sca.app[4] & CDMAC_BD_APP4_RXBYTECNT_MASK;
+	} else {
+		pb_idx = -1;
+		length = 0;
+		printf("%s: Got part of package, unsupported (%x)\n",
+				__func__, rx_dp->sca.stctrl);
+	}
+
+	/* flip the buffer */
+	flush_cache((u32)rx_dp->phys_buf_p, length);
+
+	/* reset the current descriptor */
+	rx_dp->sca.stctrl = 0;
+	rx_dp->sca.app[4] = 0;
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+	/* Find next empty buffer descriptor, preparation for next iteration */
+	rx_idx = (rx_idx + 1) % PKTBUFSRX;
+	rx_dp = &cdmac_bd.rx[rx_idx];
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+	/* DMA start by writing to respective TAILDESC_PTR */
+	ll_temac->out32(ra[RX_CURDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+	ll_temac->out32(ra[RX_TAILDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+
+	if (length > 0 && pb_idx != -1)
+		NetReceive(NetRxPackets[pb_idx], length);
+
+	return 0;
+}
+
+int ll_temac_send_sdma(struct eth_device *dev, volatile void *packet,
+							int length)
+{
+	unsigned timeout = 50;	/* 1usec * 50 = 50usec */
+	struct cdmac_bd *tx_dp = &cdmac_bd.tx[tx_idx];
+	struct ll_temac *ll_temac = dev->priv;
+	phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+	if (ll_temac_sdma_error(dev)) {
+
+		if (ll_temac_reset_sdma(dev))
+			return -1;
+
+		ll_temac_init_sdma(dev);
+	}
+
+	tx_dp->phys_buf_p = (u8 *)packet;
+	tx_dp->buf_len = length;
+	tx_dp->sca.stctrl = CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP |
+			CDMAC_BD_STCTRL_STOP_ON_END;
+
+	flush_cache((u32)packet, length);
+	flush_cache((u32)tx_dp, sizeof(*tx_dp));
+
+	/* DMA start by writing to respective TAILDESC_PTR */
+	ll_temac->out32(ra[TX_CURDESC_PTR], (int)tx_dp);
+	ll_temac->out32(ra[TX_TAILDESC_PTR], (int)tx_dp);
+
+	/* Find next empty buffer descriptor, preparation for next iteration */
+	tx_idx = (tx_idx + 1) % TX_BUF_CNT;
+	tx_dp = &cdmac_bd.tx[tx_idx];
+
+	do {
+		flush_cache((u32)tx_dp, sizeof(*tx_dp));
+		udelay(1);
+	} while (timeout-- && !(tx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED));
+
+	if (!timeout) {
+		printf("%s: Timeout\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}

+ 281 - 0
drivers/net/xilinx_ll_temac_sdma.h

@@ -0,0 +1,281 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA sub-controller interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * 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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
+ * [A]:	[0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_SDMA_
+#define _XILINX_LL_TEMAC_SDMA_
+
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include <linux/compiler.h>
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * DMA Buffer Descriptor for CDMAC
+ *
+ * Used for data connection from and to (Rx/Tx) the LocalLink (LL) TEMAC via
+ * the Communications Direct Memory Access Controller (CDMAC) -- one for each.
+ *
+ * overview:
+ *      ftp://ftp.xilinx.com/pub/documentation/misc/mpmc_getting_started.pdf
+ *
+ * [1]: [0]/ip_documentation/mpmc.pdf
+ *      page 140, DMA Operation Descriptors
+ *
+ * [2]:	[0]/user_guides/ug200.pdf
+ *	page 229, DMA Controller -- Descriptor Format
+ *
+ * [3]:	[0]/ip_documentation/xps_ll_temac.pdf
+ *	page 72, Transmit LocalLink Frame Format
+ *	page 73, Receive LocalLink Frame Format
+ */
+struct cdmac_bd {
+	struct cdmac_bd *next_p;	/* Next Descriptor Pointer */
+	u8 *phys_buf_p;			/* Buffer Address */
+	u32 buf_len;			/* Buffer Length */
+	union {
+		u8 stctrl;		/* Status/Control the DMA transfer */
+		u32 app[5];		/* application specific data */
+	} __packed __aligned(1) sca;
+};
+
+/* CDMAC Descriptor Status and Control (stctrl), [1] p140, [2] p230 */
+#define CDMAC_BD_STCTRL_ERROR		(1 << 7)
+#define CDMAC_BD_STCTRL_IRQ_ON_END	(1 << 6)
+#define CDMAC_BD_STCTRL_STOP_ON_END	(1 << 5)
+#define CDMAC_BD_STCTRL_COMPLETED	(1 << 4)
+#define CDMAC_BD_STCTRL_SOP		(1 << 3)
+#define CDMAC_BD_STCTRL_EOP		(1 << 2)
+#define CDMAC_BD_STCTRL_DMACHBUSY	(1 << 1)
+
+/* CDMAC Descriptor APP0: Transmit LocalLink Footer Word 3, [3] p72 */
+#define CDMAC_BD_APP0_TXCSCNTRL		(1 << 0)
+
+/* CDMAC Descriptor APP1: Transmit LocalLink Footer Word 4, [3] p73 */
+#define CDMAC_BD_APP1_TXCSBEGIN_POS	16
+#define CDMAC_BD_APP1_TXCSBEGIN_MASK	(0xFFFF << CDMAC_BD_APP1_TXCSBEGIN_POS)
+#define CDMAC_BD_APP1_TXCSINSERT_POS	0
+#define CDMAC_BD_APP1_TXCSINSERT_MASK	(0xFFFF << CDMAC_BD_APP1_TXCSINSERT_POS)
+
+/* CDMAC Descriptor APP2: Transmit LocalLink Footer Word 5, [3] p73 */
+#define CDMAC_BD_APP2_TXCSINIT_POS	0
+#define CDMAC_BD_APP2_TXCSINIT_MASK	(0xFFFF << CDMAC_BD_APP2_TXCSINIT_POS)
+
+/* CDMAC Descriptor APP0: Receive LocalLink Footer Word 3, [3] p73 */
+#define CDMAC_BD_APP0_MADDRU_POS	0
+#define CDMAC_BD_APP0_MADDRU_MASK	(0xFFFF << CDMAC_BD_APP0_MADDRU_POS)
+
+/* CDMAC Descriptor APP1: Receive LocalLink Footer Word 4, [3] p74 */
+#define CDMAC_BD_APP1_MADDRL_POS	0
+#define CDMAC_BD_APP1_MADDRL_MASK	(~0UL << CDMAC_BD_APP1_MADDRL_POS)
+
+/* CDMAC Descriptor APP2: Receive LocalLink Footer Word 5, [3] p74 */
+#define CDMAC_BD_APP2_BCAST_FRAME	(1 << 2)
+#define CDMAC_BD_APP2_IPC_MCAST_FRAME	(1 << 1)
+#define CDMAC_BD_APP2_MAC_MCAST_FRAME	(1 << 0)
+
+/* CDMAC Descriptor APP3: Receive LocalLink Footer Word 6, [3] p74 */
+#define CDMAC_BD_APP3_TLTPID_POS	16
+#define CDMAC_BD_APP3_TLTPID_MASK	(0xFFFF << CDMAC_BD_APP3_TLTPID_POS)
+#define CDMAC_BD_APP3_RXCSRAW_POS	0
+#define CDMAC_BD_APP3_RXCSRAW_MASK	(0xFFFF << CDMAC_BD_APP3_RXCSRAW_POS)
+
+/* CDMAC Descriptor APP4: Receive LocalLink Footer Word 7, [3] p74 */
+#define CDMAC_BD_APP4_VLANTAG_POS	16
+#define CDMAC_BD_APP4_VLANTAG_MASK	(0xFFFF << CDMAC_BD_APP4_VLANTAG_POS)
+#define CDMAC_BD_APP4_RXBYTECNT_POS	0
+#define CDMAC_BD_APP4_RXBYTECNT_MASK	(0x3FFF << CDMAC_BD_APP4_RXBYTECNT_POS)
+
+/*
+ * SDMA Register Definition
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [1]:	[0]/ip_documentation/mpmc.pdf
+ *	page 54, SDMA Register Summary
+ *	page 160, SDMA Registers
+ *
+ * [2]:	[0]/user_guides/ug200.pdf
+ *	page 244, DMA Controller -- Programming Interface and Registers
+ */
+#define SDMA_CTRL_REGTYPE	u32
+#define SDMA_CTRL_REGSIZE	sizeof(SDMA_CTRL_REGTYPE)
+struct sdma_ctrl {
+	/* Transmit Registers */
+	SDMA_CTRL_REGTYPE tx_nxtdesc_ptr;   /* TX Next Description Pointer */
+	SDMA_CTRL_REGTYPE tx_curbuf_addr;   /* TX Current Buffer Address */
+	SDMA_CTRL_REGTYPE tx_curbuf_length; /* TX Current Buffer Length */
+	SDMA_CTRL_REGTYPE tx_curdesc_ptr;   /* TX Current Descriptor Pointer */
+	SDMA_CTRL_REGTYPE tx_taildesc_ptr;  /* TX Tail Descriptor Pointer */
+	SDMA_CTRL_REGTYPE tx_chnl_ctrl;     /* TX Channel Control */
+	SDMA_CTRL_REGTYPE tx_irq_reg;       /* TX Interrupt Register */
+	SDMA_CTRL_REGTYPE tx_chnl_sts;      /* TX Status Register */
+	/* Receive Registers */
+	SDMA_CTRL_REGTYPE rx_nxtdesc_ptr;   /* RX Next Descriptor Pointer */
+	SDMA_CTRL_REGTYPE rx_curbuf_addr;   /* RX Current Buffer Address */
+	SDMA_CTRL_REGTYPE rx_curbuf_length; /* RX Current Buffer Length */
+	SDMA_CTRL_REGTYPE rx_curdesc_ptr;   /* RX Current Descriptor Pointer */
+	SDMA_CTRL_REGTYPE rx_taildesc_ptr;  /* RX Tail Descriptor Pointer */
+	SDMA_CTRL_REGTYPE rx_chnl_ctrl;     /* RX Channel Control */
+	SDMA_CTRL_REGTYPE rx_irq_reg;       /* RX Interrupt Register */
+	SDMA_CTRL_REGTYPE rx_chnl_sts;      /* RX Status Register */
+	/* Control Registers */
+	SDMA_CTRL_REGTYPE dma_control_reg;  /* DMA Control Register */
+};
+
+#define SDMA_CTRL_REGNUMS	sizeof(struct sdma_ctrl)/SDMA_CTRL_REGSIZE
+
+/*
+ * DMAC Register Index Enumeration
+ *
+ * [2]:	http://www.xilinx.com/support/documentation/user_guides/ug200.pdf
+ *	page 244, DMA Controller -- Programming Interface and Registers
+ */
+enum dmac_ctrl {
+	/* Transmit Registers */
+	TX_NXTDESC_PTR = 0,	/* TX Next Description Pointer */
+	TX_CURBUF_ADDR,		/* TX Current Buffer Address */
+	TX_CURBUF_LENGTH,	/* TX Current Buffer Length */
+	TX_CURDESC_PTR,		/* TX Current Descriptor Pointer */
+	TX_TAILDESC_PTR,	/* TX Tail Descriptor Pointer */
+	TX_CHNL_CTRL,		/* TX Channel Control */
+	TX_IRQ_REG,		/* TX Interrupt Register */
+	TX_CHNL_STS,		/* TX Status Register */
+	/* Receive Registers */
+	RX_NXTDESC_PTR,		/* RX Next Descriptor Pointer */
+	RX_CURBUF_ADDR,		/* RX Current Buffer Address */
+	RX_CURBUF_LENGTH,	/* RX Current Buffer Length */
+	RX_CURDESC_PTR,		/* RX Current Descriptor Pointer */
+	RX_TAILDESC_PTR,	/* RX Tail Descriptor Pointer */
+	RX_CHNL_CTRL,		/* RX Channel Control */
+	RX_IRQ_REG,		/* RX Interrupt Register */
+	RX_CHNL_STS,		/* RX Status Register */
+	/* Control Registers */
+	DMA_CONTROL_REG		/* DMA Control Register */
+};
+
+/* Rx/Tx Channel Control Register (*_chnl_ctrl), [1] p163, [2] p246/p252 */
+#define CHNL_CTRL_ITO_POS	24
+#define CHNL_CTRL_ITO_MASK	(0xFF << CHNL_CTRL_ITO_POS)
+#define CHNL_CTRL_IC_POS	16
+#define CHNL_CTRL_IC_MASK	(0xFF << CHNL_CTRL_IC_POS)
+#define CHNL_CTRL_MSBADDR_POS	12
+#define CHNL_CTRL_MSBADDR_MASK	(0xF << CHNL_CTRL_MSBADDR_POS)
+#define CHNL_CTRL_AME		(1 << 11)
+#define CHNL_CTRL_OBWC		(1 << 10)
+#define CHNL_CTRL_IOE		(1 << 9)
+#define CHNL_CTRL_LIC		(1 << 8)
+#define CHNL_CTRL_IE		(1 << 7)
+#define CHNL_CTRL_IEE		(1 << 2)
+#define CHNL_CTRL_IDE		(1 << 1)
+#define CHNL_CTRL_ICE		(1 << 0)
+
+/* All interrupt enable bits */
+#define CHNL_CTRL_IRQ_MASK	(CHNL_CTRL_IE | \
+				 CHNL_CTRL_IEE | \
+				 CHNL_CTRL_IDE | \
+				 CHNL_CTRL_ICE)
+
+/* Rx/Tx Interrupt Status Register (*_irq_reg), [1] p164, [2] p247/p253 */
+#define IRQ_REG_DTV_POS		24
+#define IRQ_REG_DTV_MASK	(0xFF << IRQ_REG_DTV_POS)
+#define IRQ_REG_CCV_POS		16
+#define IRQ_REG_CCV_MASK	(0xFF << IRQ_REG_CCV_POS)
+#define IRQ_REG_WRCQ_EMPTY	(1 << 14)
+#define IRQ_REG_CIC_POS		10
+#define IRQ_REG_CIC_MASK	(0xF << IRQ_REG_CIC_POS)
+#define IRQ_REG_DIC_POS		8
+#define IRQ_REG_DIC_MASK	(3 << 8)
+#define IRQ_REG_PLB_RD_NMI	(1 << 4)
+#define IRQ_REG_PLB_WR_NMI	(1 << 3)
+#define IRQ_REG_EI		(1 << 2)
+#define IRQ_REG_DI		(1 << 1)
+#define IRQ_REG_CI		(1 << 0)
+
+/* All interrupt bits */
+#define IRQ_REG_IRQ_MASK	(IRQ_REG_PLB_RD_NMI | \
+				 IRQ_REG_PLB_WR_NMI | \
+				 IRQ_REG_EI | IRQ_REG_DI | IRQ_REG_CI)
+
+/* Rx/Tx Channel Status Register (*_chnl_sts), [1] p165, [2] p249/p255 */
+#define CHNL_STS_ERROR_TAIL	(1 << 21)
+#define CHNL_STS_ERROR_CMP	(1 << 20)
+#define CHNL_STS_ERROR_ADDR	(1 << 19)
+#define CHNL_STS_ERROR_NXTP	(1 << 18)
+#define CHNL_STS_ERROR_CURP	(1 << 17)
+#define CHNL_STS_ERROR_BSYWR	(1 << 16)
+#define CHNL_STS_ERROR		(1 << 7)
+#define CHNL_STS_IOE		(1 << 6)
+#define CHNL_STS_SOE		(1 << 5)
+#define CHNL_STS_CMPLT		(1 << 4)
+#define CHNL_STS_SOP		(1 << 3)
+#define CHNL_STS_EOP		(1 << 2)
+#define CHNL_STS_EBUSY		(1 << 1)
+
+/* DMA Control Register (dma_control_reg), [1] p166, [2] p256 */
+#define DMA_CONTROL_PLBED	(1 << 5)
+#define DMA_CONTROL_RXOCEID	(1 << 4)
+#define DMA_CONTROL_TXOCEID	(1 << 3)
+#define DMA_CONTROL_TPE		(1 << 2)
+#define DMA_CONTROL_RESET	(1 << 0)
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+
+/* Xilinx Device Control Register (DCR) in/out accessors */
+unsigned ll_temac_xldcr_in32(phys_addr_t addr);
+void ll_temac_xldcr_out32(phys_addr_t addr, unsigned value);
+
+/* collect all register addresses for Xilinx DCR in/out accessors */
+void ll_temac_collect_xldcr_sdma_reg_addr(struct eth_device *dev);
+
+#endif /* CONFIG_XILINX_440 || CONFIG_XILINX_405 */
+
+/* Xilinx Processor Local Bus (PLB) in/out accessors */
+unsigned ll_temac_xlplb_in32(phys_addr_t base);
+void ll_temac_xlplb_out32(phys_addr_t base, unsigned value);
+
+/* collect all register addresses for Xilinx PLB in/out accessors */
+void ll_temac_collect_xlplb_sdma_reg_addr(struct eth_device *dev);
+
+/* initialize both Rx/Tx buffer descriptors */
+int ll_temac_init_sdma(struct eth_device *dev);
+
+/* halt both Rx/Tx transfers */
+int ll_temac_halt_sdma(struct eth_device *dev);
+
+/* reset SDMA and IRQ, disable interrupts and errors */
+int ll_temac_reset_sdma(struct eth_device *dev);
+
+/* receive buffered data from SDMA (polling ISR) */
+int ll_temac_recv_sdma(struct eth_device *dev);
+
+/* send buffered data to SDMA */
+int ll_temac_send_sdma(struct eth_device *dev, volatile void *packet,
+							int length);
+
+#endif /* _XILINX_LL_TEMAC_SDMA_ */

+ 6 - 5
include/configs/microblaze-generic.h

@@ -65,11 +65,12 @@
 
 /* ethernet */
 #undef CONFIG_SYS_ENET
-#ifdef XILINX_EMACLITE_BASEADDR
-# define CONFIG_XILINX_EMACLITE		1
+#if defined(XILINX_EMACLITE_BASEADDR)
+# define CONFIG_XILINX_EMACLITE	1
 # define CONFIG_SYS_ENET
-#elif XILINX_LLTEMAC_BASEADDR
-# define CONFIG_XILINX_LL_TEMAC		1
+#endif
+#if defined(XILINX_LLTEMAC_BASEADDR)
+# define CONFIG_XILINX_LL_TEMAC	1
 # define CONFIG_SYS_ENET
 #endif
 #if defined(XILINX_AXIEMAC_BASEADDR)
@@ -339,7 +340,7 @@
 #define CONFIG_FIT		1
 #define CONFIG_OF_LIBFDT	1
 
-#if defined(CONFIG_XILINX_AXIEMAC)
+#if defined(CONFIG_XILINX_LL_TEMAC) || defined(CONFIG_XILINX_AXIEMAC)
 # define CONFIG_MII		1
 # define CONFIG_CMD_MII		1
 # define CONFIG_PHY_GIGE	1

+ 12 - 0
include/netdev.h

@@ -102,6 +102,18 @@ int xilinx_axiemac_initialize(bd_t *bis, unsigned long base_addr,
 							unsigned long dma_addr);
 int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr,
 							int txpp, int rxpp);
+int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags,
+						unsigned long ctrl_addr);
+
+/*
+ * As long as the Xilinx xps_ll_temac ethernet driver has not its own interface
+ * exported by a public hader file, we need a global definition at this point.
+ */
+#if defined(CONFIG_XILINX_LL_TEMAC)
+#define XILINX_LL_TEMAC_M_FIFO		0	/* use FIFO Ctrl */
+#define XILINX_LL_TEMAC_M_SDMA_PLB	(1 << 0)/* use SDMA Ctrl via PLB */
+#define XILINX_LL_TEMAC_M_SDMA_DCR	(1 << 1)/* use SDMA Ctrl via DCR */
+#endif
 
 /* Boards with PCI network controllers can call this from their board_eth_init()
  * function to initialize whatever's on board.

+ 1 - 2
net/eth.c

@@ -172,8 +172,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
 	unsigned char env_enetaddr[6];
 	int ret = 0;
 
-	if (!eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr))
-		return -1;
+	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
 
 	if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
 		if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&