Patchwork [U-Boot,v6] net: ll_temac: Add LL TEMAC driver to u-boot

login
register
mail settings
Submitter Stephan Linz
Date Nov. 27, 2011, 6:43 p.m.
Message ID <1322419397-26326-2-git-send-email-linz@li-pro.net>
Download mbox | patch
Permalink /patch/127898/
State Changes Requested
Headers show

Comments

Stephan Linz - Nov. 27, 2011, 6:43 p.m.
Xilinx LocalLink Tri-Mode Ether MAC driver can be
used by Xilinx Microblaze or Xilinx ppc405/440 in
SDMA and FIFO mode. DCR or XPS bus can be used.

The driver uses and requires MII and PHYLIB.

Signed-off-by: Stephan Linz <linz@li-pro.net>
---
v6: Code cleanup with ./tools/checkpatch.pl

v5: Remove more endless loops
    Remove useless parenthesis in pointer operations
    Move phyaddr predefinition on top
    Remove supernumerary newlines
    Remove parenthesis around numbers (globally)

v4: Separate fifo and sdma code from driver core
    Split sdma code into separate DCR and XPS bus access code
    Add extensive register struct definitions and enumerations
    Add new callbacks into fifo an sdma code
    Prepare CDMAC buffer handling to be unique for every instance
    Separate Xilinx specific indirect DCR access, so we can move to arch
    Remove useless 'emac' parameter from indirect access helper functions
    Correct MDIO clock setup.
    Remove endless loops
    Common code beautifying

v3: Use helper functions for fifo mode
    Use helper functions for indirect accesses
    Code cleanup
    Add comments for MAGIC values
    Simplify code in fifo mode

v2: Remove helper function for access to temac
    Remove SDMA/FIFO/DCR macros and configure it in board
    Setup mac by write_hwaddr
---
 drivers/net/Makefile               |    2 +
 drivers/net/xilinx_ll_temac.c      |  395 ++++++++++++++++++++++++++++++++++
 drivers/net/xilinx_ll_temac.h      |  306 ++++++++++++++++++++++++++
 drivers/net/xilinx_ll_temac_fifo.c |   93 ++++++++
 drivers/net/xilinx_ll_temac_fifo.h |  115 ++++++++++
 drivers/net/xilinx_ll_temac_sdma.c |  415 ++++++++++++++++++++++++++++++++++++
 drivers/net/xilinx_ll_temac_sdma.h |  277 ++++++++++++++++++++++++
 include/netdev.h                   |    2 +
 8 files changed, 1605 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/xilinx_ll_temac.c
 create mode 100644 drivers/net/xilinx_ll_temac.h
 create mode 100644 drivers/net/xilinx_ll_temac_fifo.c
 create mode 100644 drivers/net/xilinx_ll_temac_fifo.h
 create mode 100644 drivers/net/xilinx_ll_temac_sdma.c
 create mode 100644 drivers/net/xilinx_ll_temac_sdma.h
Wolfgang Denk - Nov. 27, 2011, 7:09 p.m.
Dear Stephan Linz,

In message <1322419397-26326-2-git-send-email-linz@li-pro.net> you wrote:
> Xilinx LocalLink Tri-Mode Ether MAC driver can be
> used by Xilinx Microblaze or Xilinx ppc405/440 in
> SDMA and FIFO mode. DCR or XPS bus can be used.
> 
> The driver uses and requires MII and PHYLIB.
> 
> Signed-off-by: Stephan Linz <linz@li-pro.net>
...

> +static inline void xps_ll_temac_check_status(struct temac_reg *regs, u32 mask)
> +{
> +	unsigned timeout = 2000;
> +	while (timeout && (!(in_be32(&regs->rdy) & mask)))
> +		timeout--;

This has been asked before:  what exactly is the limit for the timeout
here?  2000 loops though that loop is not exactly a known value.
Please add some udelay() here (which is also good for triggering the
watchdog, should you have one running).


> +	if (!timeout)
> +		printf("%s: Timeout\n", __func__);

Why is this function void when you are know that you might have to
handle error situations (like a timeout)?

> +static void xps_ll_temac_hostif_set(struct eth_device *dev, u8 phy_addr,
> +					u8 reg_addr, u16 phy_data)
> +{
> +	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
> +
> +	out_be32(&regs->lsw, (phy_data & LSW_REGDAT_MASK));
> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
> +	out_be32(&regs->lsw,
> +		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
> +		(reg_addr & LSW_REGAD_MASK));
> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
> +	xps_ll_temac_check_status(regs, RSE_MIIM_WR);
> +}

So what happens here if we have a timeout in
xps_ll_temac_check_status()?  SHould such an error not be handled?

Ditto for all following functions.

> + * Undirect hostif read to ll_temac.

"Undirect"??  Or "Indirect" ?

"read to"??  Or "read from" ?

Please fix globally.

> +#ifdef DEBUG
> +static inline void read_phy_reg(struct eth_device *dev, u8 phy_addr)
> +{
> +	int j, result;
> +	debug("phy%d ", phy_addr);

Please always have one blank line between declarations and code.
Please fix globally.


> +	if (ll_temac->ctrlreset)
> +		if (ll_temac->ctrlreset(dev))
> +			return -1;

Braces needed for multiline statements.  Please fix globally.

> +/* halt device */
> +static void ll_temac_halt(struct eth_device *dev)
> +{
> +#ifdef ETH_HALTING
> +	struct ll_temac *ll_temac = dev->priv;
> +
> +	/* Disable Receiver */
> +	xps_ll_temac_indirect_set(dev, TEMAC_RCW0, 0);
> +
> +	/* Disable Transmitter */
> +	xps_ll_temac_indirect_set(dev, TEMAC_TC, 0);
> +
> +	if (ll_temac->ctrlhalt)
> +		ll_temac->ctrlhalt(dev);
> +#endif
> +}

ETH_HALTING is permanently undef'ed, so all this is dead code.  Please
remove.

> +static int ll_temac_bus_reset(struct mii_dev *bus)
> +{
> +	debug("Just bus reset\n");
> +	return 0;
> +}

Can we remove this function?  It does not appear to perform any useful
operation?

> + * FIXME: This part should going up to arch/powerpc -- but where?

s/going/go/ ?

> +/* Check for TX and RX channel errrors. */

s/rrr/rr/ ?

> +int ll_temac_halt_sdma(struct eth_device *dev)
> +{
> +	unsigned timeout = 2000;

See comments above.

> +	if (!timeout) {
> +		printf("%s: Timeout\n", __func__);
> +		return 1;
> +	}

Interesting - here you return an error code, above you don't :-(

...
> +
> +int ll_temac_send_sdma(struct eth_device *dev,
> +				volatile void *buffer, int length)
> +{
> +	unsigned timeout = 2000;
...
> +	if (!timeout)
> +		printf("%s: Timeout\n", __func__);
> +
> +	return 0;

Same issues again.  Please fix timout and error handling globally.

> +
> +#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
> +/* Check for TX and RX channel errrors. */
> +static inline int ll_temac_dmac_error(struct eth_device *dev)
> +{
> +	int err;
> +	struct ll_temac *ll_temac = dev->priv;
> +	unsigned dmac_ctrl = ll_temac->ctrladdr;
> +
> +	err = mifdcr_xilinx(dmac_ctrl + TX_CHNL_STS) & CHNL_STS_ERROR;
> +	err |= mifdcr_xilinx(dmac_ctrl + RX_CHNL_STS) & CHNL_STS_ERROR;
> +	return err;
> +}
> +
> +void ll_temac_init_dmac(struct eth_device *dev)
> +{
> +	struct ll_temac *ll_temac = dev->priv;
> +	unsigned dmac_ctrl = ll_temac->ctrladdr;
> +	struct cdmac_bd *rx_dp = ll_temac->rx_dp;
> +	struct cdmac_bd *tx_dp = ll_temac->tx_dp;
> +
> +	memset(tx_dp, 0, sizeof(*tx_dp));
> +	memset(rx_dp, 0, sizeof(*rx_dp));
> +
> +	/* from LL TEMAC (Rx) */
> +	rx_dp->phys_buf_p = ll_temac->rx_bp;
> +
> +	rx_dp->next_p = rx_dp;
> +	rx_dp->buf_len = PKTSIZE_ALIGN;
> +	flush_cache((u32)rx_dp, sizeof(*tx_dp));
> +	flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
> +
> +	/* setup first fd */
> +	mitdcr_xilinx(dmac_ctrl + RX_CURDESC_PTR, (u32)rx_dp);
> +	mitdcr_xilinx(dmac_ctrl + RX_TAILDESC_PTR, (u32)rx_dp);
> +	mitdcr_xilinx(dmac_ctrl + RX_NXTDESC_PTR, (u32)rx_dp);
> +
> +	/* to LL TEMAC (Tx) */
> +	tx_dp->phys_buf_p = ll_temac->tx_bp;
> +	tx_dp->next_p = tx_dp;
> +
> +	flush_cache((u32)tx_dp, sizeof(*tx_dp));
> +	mitdcr_xilinx(dmac_ctrl + TX_CURDESC_PTR, (u32)rx_dp);
> +}
> +
> +int ll_temac_halt_dmac(struct eth_device *dev)
> +{
> +	unsigned timeout = 2000;
> +	struct ll_temac *ll_temac = dev->priv;
> +	unsigned dmac_ctrl = ll_temac->ctrladdr;
> +
> +	/*
> +	 * 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.
> +	 */
> +	mitdcr_xilinx(dmac_ctrl + DMA_CONTROL_REG, DMA_CONTROL_RESET);
> +	while (timeout && (mifdcr_xilinx(dmac_ctrl + DMA_CONTROL_REG)
> +					& DMA_CONTROL_RESET))
> +		timeout--;
> +
> +	if (!timeout) {
> +		printf("%s: Timeout\n", __func__);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int ll_temac_reset_dmac(struct eth_device *dev)
> +{
> +	u32 r;
> +	struct ll_temac *ll_temac = dev->priv;
> +	unsigned dmac_ctrl = ll_temac->ctrladdr;
> +
> +	/* Soft reset the DMA.  */
> +	if (ll_temac_halt_dmac(dev))
> +		return 1;
> +
> +	/* Now clear the interrupts.  */
> +	r = mifdcr_xilinx(dmac_ctrl + TX_CHNL_CTRL);
> +	r &= ~CHNL_CTRL_IRQ_MASK;
> +	mitdcr_xilinx(dmac_ctrl + TX_CHNL_CTRL, r);
> +
> +	r = mifdcr_xilinx(dmac_ctrl + RX_CHNL_CTRL);
> +	r &= ~CHNL_CTRL_IRQ_MASK;
> +	mitdcr_xilinx(dmac_ctrl + RX_CHNL_CTRL, r);
> +
> +	/* Now ACK pending IRQs.  */
> +	mitdcr_xilinx(dmac_ctrl + TX_IRQ_REG, IRQ_REG_IRQ_MASK);
> +	mitdcr_xilinx(dmac_ctrl + RX_IRQ_REG, IRQ_REG_IRQ_MASK);
> +
> +	/* Set tail-ptr mode, disable errors for both channels.  */
> +	mitdcr_xilinx(dmac_ctrl + 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_dmac(struct eth_device *dev)
> +{
> +	int length;
> +	struct ll_temac *ll_temac = dev->priv;
> +	unsigned dmac_ctrl = ll_temac->ctrladdr;
> +	struct cdmac_bd *rx_dp = ll_temac->rx_dp;

Umm.... this code is more or less exactly the same as for
ll_temac_recv_sdma().  Can we please avoid this duplication of code?

Ditto for the other duplicated functions.


Best regards,

Wolfgang Denk
Stephan Linz - Nov. 27, 2011, 8:06 p.m.
Am Sonntag, den 27.11.2011, 20:09 +0100 schrieb Wolfgang Denk: 
> Dear Stephan Linz,
> 
> In message <1322419397-26326-2-git-send-email-linz@li-pro.net> you wrote:
> > Xilinx LocalLink Tri-Mode Ether MAC driver can be
> > used by Xilinx Microblaze or Xilinx ppc405/440 in
> > SDMA and FIFO mode. DCR or XPS bus can be used.
> > 
> > The driver uses and requires MII and PHYLIB.
> > 
> > Signed-off-by: Stephan Linz <linz@li-pro.net>
> ...
> 
> > +static inline void xps_ll_temac_check_status(struct temac_reg *regs, u32 mask)
> > +{
> > +	unsigned timeout = 2000;
> > +	while (timeout && (!(in_be32(&regs->rdy) & mask)))
> > +		timeout--;
> 
> This has been asked before:  what exactly is the limit for the timeout
> here?  2000 loops though that loop is not exactly a known value.
> Please add some udelay() here (which is also good for triggering the
> watchdog, should you have one running).

Hi Wolfgang,

I'll try to make the timeout handling more precise. Your argument with
the watchdog is an interesting issue I forget completely. Thanks for the
hint.

> 
> 
> > +	if (!timeout)
> > +		printf("%s: Timeout\n", __func__);
> 
> Why is this function void when you are know that you might have to
> handle error situations (like a timeout)?
> 
> > +static void xps_ll_temac_hostif_set(struct eth_device *dev, u8 phy_addr,
> > +					u8 reg_addr, u16 phy_data)
> > +{
> > +	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
> > +
> > +	out_be32(&regs->lsw, (phy_data & LSW_REGDAT_MASK));
> > +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
> > +	out_be32(&regs->lsw,
> > +		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
> > +		(reg_addr & LSW_REGAD_MASK));
> > +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
> > +	xps_ll_temac_check_status(regs, RSE_MIIM_WR);
> > +}
> 
> So what happens here if we have a timeout in
> xps_ll_temac_check_status()?  SHould such an error not be handled?

Yes we should. I'll fix it.


> > + * Undirect hostif read to ll_temac.
> "Undirect"??  Or "Indirect" ?
> "read to"??  Or "read from" ?
> 
> Please fix globally.

yep.

> 
> > +#ifdef DEBUG
> > +static inline void read_phy_reg(struct eth_device *dev, u8 phy_addr)
> > +{
> > +	int j, result;
> > +	debug("phy%d ", phy_addr);
> 
> Please always have one blank line between declarations and code.
> Please fix globally.

yep.

> > +	if (ll_temac->ctrlreset)
> > +		if (ll_temac->ctrlreset(dev))
> > +			return -1;
> 
> Braces needed for multiline statements.  Please fix globally.

yep.

> 
> > +/* halt device */
> > +static void ll_temac_halt(struct eth_device *dev)
> > +{
> > +#ifdef ETH_HALTING
> > +	struct ll_temac *ll_temac = dev->priv;
> > +
> > +	/* Disable Receiver */
> > +	xps_ll_temac_indirect_set(dev, TEMAC_RCW0, 0);
> > +
> > +	/* Disable Transmitter */
> > +	xps_ll_temac_indirect_set(dev, TEMAC_TC, 0);
> > +
> > +	if (ll_temac->ctrlhalt)
> > +		ll_temac->ctrlhalt(dev);
> > +#endif
> > +}
> 
> ETH_HALTING is permanently undef'ed, so all this is dead code.  Please
> remove.

@Michal: Is there any platform which can not halt the TEMAC? I have no
problem with this code but I left ETH_HALTING undefined from original
driver code. I would like to remove all the ETH_HALTING statements and
hold this code.

> 
> > +static int ll_temac_bus_reset(struct mii_dev *bus)
> > +{
> > +	debug("Just bus reset\n");
> > +	return 0;
> > +}
> 
> Can we remove this function?  It does not appear to perform any useful
> operation?

@Michal: Have you any objections?

@all: What is the meaning of mii_dev bus reset? What is expacted from
the perspective of the MII driver code?

> 
> > + * FIXME: This part should going up to arch/powerpc -- but where?
> 
> s/going/go/ ?
> s/rrr/rr/ ?

yep.

> 
> > +int ll_temac_halt_sdma(struct eth_device *dev)
> > +{
> > +	unsigned timeout = 2000;
> 
> See comments above.
> 
> > +	if (!timeout) {
> > +		printf("%s: Timeout\n", __func__);
> > +		return 1;
> > +	}
> 
> Interesting - here you return an error code, above you don't :-(

Grr, ache on my head. I need one more look to the timeouts (see above).


> Same issues again.  Please fix timout and error handling globally.
> 
> > +
> > +#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
> > +/* Check for TX and RX channel errrors. */
> > +static inline int ll_temac_dmac_error(struct eth_device *dev)
> > +{
> > +	int err;
> > +--snip--
> 
> Umm.... this code is more or less exactly the same as for
> ll_temac_recv_sdma().  Can we please avoid this duplication of code?
> 
> Ditto for the other duplicated functions.

You are completely right, but for more than one week I have not found
any practicable way to avoid duplicate code here. The only really good
approach would be to use private function pointers in struct ll_temac
for all the in_*/out_* calls we need in sdma code and refactor the DCR
code to use its special in_*/out_* functions with the same prototype.
This special 'DCR' function can map into indirect DCR access. But
unfortunately in_be32() and out_be32() for Microblaze are not real
functions. They are CPP defines :-(

I will review arch/microblaze/include/asm/io.h together with Michal.
Until then it would be nice if we could keep this code as it is. I will
fix the dublicate code if we have in/out functions -- no defines.
Wolfgang Denk - Nov. 27, 2011, 10:29 p.m.
Dear Stephan Linz,

In message <1322424370.3870.370.camel@keto> you wrote:
>
> > ETH_HALTING is permanently undef'ed, so all this is dead code.  Please
> > remove.
> 
> @Michal: Is there any platform which can not halt the TEMAC? I have no
> problem with this code but I left ETH_HALTING undefined from original
> driver code. I would like to remove all the ETH_HALTING statements and
> hold this code.

I have no idea. But there is no code in mainline that uses
ETH_HALTING, and your file #undef's it.

> > Interesting - here you return an error code, above you don't :-(
> 
> Grr, ache on my head. I need one more look to the timeouts (see above).

ache != ash.  I'm nut sure which you prefer, though ;-)

> > Umm.... this code is more or less exactly the same as for
> > ll_temac_recv_sdma().  Can we please avoid this duplication of code?
> > 
> > Ditto for the other duplicated functions.
> 
> You are completely right, but for more than one week I have not found
> any practicable way to avoid duplicate code here. The only really good
> approach would be to use private function pointers in struct ll_temac
> for all the in_*/out_* calls we need in sdma code and refactor the DCR
> code to use its special in_*/out_* functions with the same prototype.

diff'ing the functions it appears there are only very few function
pointers that would be needed.

> This special 'DCR' function can map into indirect DCR access. But
> unfortunately in_be32() and out_be32() for Microblaze are not real
> functions. They are CPP defines :-(

Change it?  Turning them into inline functions should be not too
difficult.

> I will review arch/microblaze/include/asm/io.h together with Michal.
> Until then it would be nice if we could keep this code as it is. I will
> fix the dublicate code if we have in/out functions -- no defines.

Hm... past experience has shown that the stragey of adding bad code
first and then cleaning it up has never worked really well, nor fast. 
Insisting on clean patches from the beginning is probably more
painful, but almost always faster, and more reliable.

Best regards,

Wolfgang Denk
Michal Simek - Nov. 28, 2011, 11:06 a.m.
Stephan Linz wrote:
> Am Sonntag, den 27.11.2011, 20:09 +0100 schrieb Wolfgang Denk: 
>> Dear Stephan Linz,
>>
>> In message <1322419397-26326-2-git-send-email-linz@li-pro.net> you wrote:
>>> Xilinx LocalLink Tri-Mode Ether MAC driver can be
>>> used by Xilinx Microblaze or Xilinx ppc405/440 in
>>> SDMA and FIFO mode. DCR or XPS bus can be used.
>>>
>>> The driver uses and requires MII and PHYLIB.
>>>
>>> Signed-off-by: Stephan Linz <linz@li-pro.net>
>> ...
>>
>>> +static inline void xps_ll_temac_check_status(struct temac_reg *regs, u32 mask)
>>> +{
>>> +	unsigned timeout = 2000;
>>> +	while (timeout && (!(in_be32(&regs->rdy) & mask)))
>>> +		timeout--;
>> This has been asked before:  what exactly is the limit for the timeout
>> here?  2000 loops though that loop is not exactly a known value.
>> Please add some udelay() here (which is also good for triggering the
>> watchdog, should you have one running).
> 
> Hi Wolfgang,
> 
> I'll try to make the timeout handling more precise. Your argument with
> the watchdog is an interesting issue I forget completely. Thanks for the
> hint.
> 
>>
>>> +	if (!timeout)
>>> +		printf("%s: Timeout\n", __func__);
>> Why is this function void when you are know that you might have to
>> handle error situations (like a timeout)?
>>
>>> +static void xps_ll_temac_hostif_set(struct eth_device *dev, u8 phy_addr,
>>> +					u8 reg_addr, u16 phy_data)
>>> +{
>>> +	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
>>> +
>>> +	out_be32(&regs->lsw, (phy_data & LSW_REGDAT_MASK));
>>> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
>>> +	out_be32(&regs->lsw,
>>> +		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
>>> +		(reg_addr & LSW_REGAD_MASK));
>>> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
>>> +	xps_ll_temac_check_status(regs, RSE_MIIM_WR);
>>> +}
>> So what happens here if we have a timeout in
>> xps_ll_temac_check_status()?  SHould such an error not be handled?
> 
> Yes we should. I'll fix it.
> 
> 
>>> + * Undirect hostif read to ll_temac.
>> "Undirect"??  Or "Indirect" ?
>> "read to"??  Or "read from" ?
>>
>> Please fix globally.
> 
> yep.
> 
>>> +#ifdef DEBUG
>>> +static inline void read_phy_reg(struct eth_device *dev, u8 phy_addr)
>>> +{
>>> +	int j, result;
>>> +	debug("phy%d ", phy_addr);
>> Please always have one blank line between declarations and code.
>> Please fix globally.
> 
> yep.
> 
>>> +	if (ll_temac->ctrlreset)
>>> +		if (ll_temac->ctrlreset(dev))
>>> +			return -1;
>> Braces needed for multiline statements.  Please fix globally.
> 
> yep.
> 
>>> +/* halt device */
>>> +static void ll_temac_halt(struct eth_device *dev)
>>> +{
>>> +#ifdef ETH_HALTING
>>> +	struct ll_temac *ll_temac = dev->priv;
>>> +
>>> +	/* Disable Receiver */
>>> +	xps_ll_temac_indirect_set(dev, TEMAC_RCW0, 0);
>>> +
>>> +	/* Disable Transmitter */
>>> +	xps_ll_temac_indirect_set(dev, TEMAC_TC, 0);
>>> +
>>> +	if (ll_temac->ctrlhalt)
>>> +		ll_temac->ctrlhalt(dev);
>>> +#endif
>>> +}
>> ETH_HALTING is permanently undef'ed, so all this is dead code.  Please
>> remove.
> 
> @Michal: Is there any platform which can not halt the TEMAC? I have no
> problem with this code but I left ETH_HALTING undefined from original
> driver code. I would like to remove all the ETH_HALTING statements and
> hold this code.
> 
>>> +static int ll_temac_bus_reset(struct mii_dev *bus)
>>> +{
>>> +	debug("Just bus reset\n");
>>> +	return 0;
>>> +}
>> Can we remove this function?  It does not appear to perform any useful
>> operation?
> 
> @Michal: Have you any objections?
> 
> @all: What is the meaning of mii_dev bus reset? What is expacted from
> the perspective of the MII driver code?

It was necessary before this patch.

phylib: reset mii bus only if reset handler is registered
sha1: e3a77218a256edbe201112a39beeed8adcabae3f

Currently you can simple remove.

Michal
Michal Simek - Nov. 28, 2011, 11:11 a.m.
Stephan Linz wrote:
> Am Sonntag, den 27.11.2011, 20:09 +0100 schrieb Wolfgang Denk: 
>> Dear Stephan Linz,
>>
>> In message <1322419397-26326-2-git-send-email-linz@li-pro.net> you wrote:
>>> Xilinx LocalLink Tri-Mode Ether MAC driver can be
>>> used by Xilinx Microblaze or Xilinx ppc405/440 in
>>> SDMA and FIFO mode. DCR or XPS bus can be used.
>>>
>>> The driver uses and requires MII and PHYLIB.
>>>
>>> Signed-off-by: Stephan Linz <linz@li-pro.net>
>> ...
>>
>>> +static inline void xps_ll_temac_check_status(struct temac_reg *regs, u32 mask)
>>> +{
>>> +	unsigned timeout = 2000;
>>> +	while (timeout && (!(in_be32(&regs->rdy) & mask)))
>>> +		timeout--;
>> This has been asked before:  what exactly is the limit for the timeout
>> here?  2000 loops though that loop is not exactly a known value.
>> Please add some udelay() here (which is also good for triggering the
>> watchdog, should you have one running).
> 
> Hi Wolfgang,
> 
> I'll try to make the timeout handling more precise. Your argument with
> the watchdog is an interesting issue I forget completely. Thanks for the
> hint.
> 
>>
>>> +	if (!timeout)
>>> +		printf("%s: Timeout\n", __func__);
>> Why is this function void when you are know that you might have to
>> handle error situations (like a timeout)?
>>
>>> +static void xps_ll_temac_hostif_set(struct eth_device *dev, u8 phy_addr,
>>> +					u8 reg_addr, u16 phy_data)
>>> +{
>>> +	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
>>> +
>>> +	out_be32(&regs->lsw, (phy_data & LSW_REGDAT_MASK));
>>> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
>>> +	out_be32(&regs->lsw,
>>> +		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
>>> +		(reg_addr & LSW_REGAD_MASK));
>>> +	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
>>> +	xps_ll_temac_check_status(regs, RSE_MIIM_WR);
>>> +}
>> So what happens here if we have a timeout in
>> xps_ll_temac_check_status()?  SHould such an error not be handled?
> 
> Yes we should. I'll fix it.
> 
> 
>>> + * Undirect hostif read to ll_temac.
>> "Undirect"??  Or "Indirect" ?
>> "read to"??  Or "read from" ?
>>
>> Please fix globally.
> 
> yep.
> 
>>> +#ifdef DEBUG
>>> +static inline void read_phy_reg(struct eth_device *dev, u8 phy_addr)
>>> +{
>>> +	int j, result;
>>> +	debug("phy%d ", phy_addr);
>> Please always have one blank line between declarations and code.
>> Please fix globally.
> 
> yep.
> 
>>> +	if (ll_temac->ctrlreset)
>>> +		if (ll_temac->ctrlreset(dev))
>>> +			return -1;
>> Braces needed for multiline statements.  Please fix globally.
> 
> yep.
> 
>>> +/* halt device */
>>> +static void ll_temac_halt(struct eth_device *dev)
>>> +{
>>> +#ifdef ETH_HALTING
>>> +	struct ll_temac *ll_temac = dev->priv;
>>> +
>>> +	/* Disable Receiver */
>>> +	xps_ll_temac_indirect_set(dev, TEMAC_RCW0, 0);
>>> +
>>> +	/* Disable Transmitter */
>>> +	xps_ll_temac_indirect_set(dev, TEMAC_TC, 0);
>>> +
>>> +	if (ll_temac->ctrlhalt)
>>> +		ll_temac->ctrlhalt(dev);
>>> +#endif
>>> +}
>> ETH_HALTING is permanently undef'ed, so all this is dead code.  Please
>> remove.
> 
> @Michal: Is there any platform which can not halt the TEMAC? I have no
> problem with this code but I left ETH_HALTING undefined from original
> driver code. I would like to remove all the ETH_HALTING statements and
> hold this code.

I am not aware about any problem with halting. I had it there for debugging
purpose. You can simple remove ETH_HALTING statemets.

Michal
Stephan Linz - Nov. 29, 2011, 7:55 p.m.
Am Sonntag, den 27.11.2011, 23:29 +0100 schrieb Wolfgang Denk: 
> Dear Stephan Linz,
> 
--snip-- 
> 
> > This special 'DCR' function can map into indirect DCR access. But
> > unfortunately in_be32() and out_be32() for Microblaze are not real
> > functions. They are CPP defines :-(
> 
> Change it?  Turning them into inline functions should be not too
> difficult.

Hello Wolfgang,
Hello Michal,

I have sync arch/microblaze/include/asm/io.h with Linux kernel code. Now
I ask me whether there is any option to test all the io helper functions
in a simple way? Do you know one?

Best regards,
Stephan

> 
> > I will review arch/microblaze/include/asm/io.h together with Michal.
> > Until then it would be nice if we could keep this code as it is. I will
> > fix the dublicate code if we have in/out functions -- no defines.
> 
> Hm... past experience has shown that the stragey of adding bad code
> first and then cleaning it up has never worked really well, nor fast. 
> Insisting on clean patches from the beginning is probably more
> painful, but almost always faster, and more reliable.
> 
> Best regards,
> 
> Wolfgang Denk
>

Patch

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d3df82e..14d71a7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -76,6 +76,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_fifo.o xilinx_ll_temac_sdma.o
 
 COBJS	:= $(sort $(COBJS-y))
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/net/xilinx_ll_temac.c b/drivers/net/xilinx_ll_temac.c
new file mode 100644
index 0000000..d7003d9
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac.c
@@ -0,0 +1,395 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * supports SDMA or FIFO access
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <phy.h>
+#include <miiphy.h>
+
+#include "xilinx_ll_temac.h"
+
+#undef ETH_HALTING
+
+#if !defined(CONFIG_MII) || !defined(CONFIG_CMD_MII)
+# error "LL_TEMAC requires MII -- missing CONFIG_MII or CONFIG_CMD_MII"
+#endif
+
+#if !defined(CONFIG_PHYLIB)
+# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
+#endif
+
+#ifndef CONFIG_PHY_ADDR
+#define CONFIG_PHY_ADDR -1
+#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
+
+/* Data buffer for LL TEMAC Rx and Tx direction */
+static unsigned char rx_buffer[PKTSIZE_ALIGN] __attribute((aligned(DMAALIGN)));
+static unsigned char tx_buffer[PKTSIZE_ALIGN] __attribute((aligned(DMAALIGN)));
+
+/* CDMAC buffer descriptor for LL TEMAC Rx and Tx buffer handling */
+static struct cdmac_bd rx_descr __attribute((aligned(DMAALIGN)));
+static struct cdmac_bd tx_descr __attribute((aligned(DMAALIGN)));
+
+static inline void xps_ll_temac_check_status(struct temac_reg *regs, u32 mask)
+{
+	unsigned timeout = 2000;
+	while (timeout && (!(in_be32(&regs->rdy) & mask)))
+		timeout--;
+	if (!timeout)
+		printf("%s: Timeout\n", __func__);
+}
+
+/*
+ * Undirect hostif write to ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+static void xps_ll_temac_hostif_set(struct eth_device *dev, u8 phy_addr,
+					u8 reg_addr, u16 phy_data)
+{
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	out_be32(&regs->lsw, (phy_data & LSW_REGDAT_MASK));
+	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
+	out_be32(&regs->lsw,
+		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+		(reg_addr & LSW_REGAD_MASK));
+	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
+	xps_ll_temac_check_status(regs, RSE_MIIM_WR);
+}
+
+/*
+ * Undirect hostif read to ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+static u16 xps_ll_temac_hostif_get(struct eth_device *dev, u8 phy_addr,
+					u8 reg_addr)
+{
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	out_be32(&regs->lsw,
+		((phy_addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+		(reg_addr & LSW_REGAD_MASK));
+	out_be32(&regs->ctl, TEMAC_MIIMAI);
+	xps_ll_temac_check_status(regs, RSE_MIIM_RR);
+	return in_be32(&regs->lsw) & LSW_REGDAT_MASK;
+}
+
+/*
+ * Undirect 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
+ */
+static void xps_ll_temac_indirect_set(struct eth_device *dev, u16 regn,
+					u32 reg_data)
+{
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	out_be32(&regs->lsw, (reg_data & MLSW_MASK));
+	out_be32(&regs->ctl, CTL_WEN | (regn & CTL_ADDR_MASK));
+	xps_ll_temac_check_status(regs, RSE_CFG_WR);
+}
+
+/*
+ * Undirect 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
+ */
+static u32 xps_ll_temac_indirect_get(struct eth_device *dev, u16 regn)
+{
+	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+	out_be32(&regs->ctl, (regn & CTL_ADDR_MASK));
+	xps_ll_temac_check_status(regs, RSE_CFG_RR);
+	return in_be32(&regs->lsw) & MLSW_MASK;
+}
+
+#ifdef DEBUG
+static inline void read_phy_reg(struct eth_device *dev, u8 phy_addr)
+{
+	int j, result;
+	debug("phy%d ", phy_addr);
+	for (j = 0; j < 32; j++) {
+		result = xps_ll_temac_hostif_get(dev, phy_addr, j);
+		debug("%d: 0x%x ", j, result);
+	}
+	debug("\n");
+}
+#endif
+
+/* setting ll_temac and phy to proper setting */
+static int xps_ll_temac_phy_ctrl(struct eth_device *dev)
+{
+	int i;
+	unsigned int temp, speed;
+	struct ll_temac *ll_temac = dev->priv;
+	struct phy_device *phydev;
+
+	u32 supported = SUPPORTED_10baseT_Half |
+			SUPPORTED_10baseT_Full |
+			SUPPORTED_100baseT_Half |
+			SUPPORTED_100baseT_Full |
+			SUPPORTED_1000baseT_Half |
+			SUPPORTED_1000baseT_Full;
+
+	if (ll_temac->phyaddr == -1) {
+		for (i = 31; i >= 0; i--) {
+			temp = xps_ll_temac_hostif_get(dev, i, 1);
+			if ((temp & 0x0ffff) != 0x0ffff) {
+				debug("phy %x result %x\n", i, temp);
+				ll_temac->phyaddr = i;
+				break;
+			}
+		}
+	}
+
+	/* interface - look at tsec */
+	phydev = phy_connect(ll_temac->bus, ll_temac->phyaddr, dev, 0);
+
+	phydev->supported &= supported;
+	phydev->advertising = phydev->supported;
+	ll_temac->phydev = phydev;
+	phy_config(phydev);
+	phy_startup(phydev);
+
+	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;
+	}
+	temp = xps_ll_temac_indirect_get(dev, TEMAC_EMMC);
+	temp &= ~EMMC_LSPD_MASK;
+	temp |= speed;
+	xps_ll_temac_indirect_set(dev, TEMAC_EMMC, temp);
+
+	return 1;
+}
+
+/* setup mac addr */
+static int ll_temac_addr_setup(struct eth_device *dev)
+{
+	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;
+	xps_ll_temac_indirect_set(dev, TEMAC_UAW0, val);
+
+	val = ((dev->enetaddr[5] << 8) | dev->enetaddr[4]);
+	val &= UAW1_UADDR_MASK;
+	xps_ll_temac_indirect_set(dev, TEMAC_UAW1, val);
+
+	return 0;
+}
+
+static int xps_ll_temac_init(struct eth_device *dev, bd_t *bis)
+{
+	struct ll_temac *ll_temac = dev->priv;
+
+	if (ll_temac->ctrlreset)
+		if (ll_temac->ctrlreset(dev))
+			return -1;
+
+	if (ll_temac->ctrlinit)
+		ll_temac->ctrlinit(dev);
+
+	xps_ll_temac_indirect_set(dev, TEMAC_MC,
+			MC_MDIOEN | (MDIO_CLOCK_DIV & MC_CLKDIV_MASK));
+
+	/* Promiscuous mode disable */
+	xps_ll_temac_indirect_set(dev, TEMAC_AFM, 0);
+
+	/* Enable Receiver - RX bit */
+	xps_ll_temac_indirect_set(dev, TEMAC_RCW1, RCW1_RX);
+
+	/* Enable Transmitter - TX bit */
+	xps_ll_temac_indirect_set(dev, TEMAC_TC, TC_TX);
+
+	return 0;
+}
+
+/* halt device */
+static void ll_temac_halt(struct eth_device *dev)
+{
+#ifdef ETH_HALTING
+	struct ll_temac *ll_temac = dev->priv;
+
+	/* Disable Receiver */
+	xps_ll_temac_indirect_set(dev, TEMAC_RCW0, 0);
+
+	/* Disable Transmitter */
+	xps_ll_temac_indirect_set(dev, TEMAC_TC, 0);
+
+	if (ll_temac->ctrlhalt)
+		ll_temac->ctrlhalt(dev);
+#endif
+}
+
+static int ll_temac_init(struct eth_device *dev, bd_t *bis)
+{
+#if DEBUG
+	int i;
+#endif
+	xps_ll_temac_init(dev, bis);
+
+	printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.\n",
+		dev->name, 0, dev->iobase);
+
+#if DEBUG
+	for (i = 0; i < 32; i++)
+		read_phy_reg(dev, i);
+#endif
+
+	if (!xps_ll_temac_phy_ctrl(dev)) {
+		ll_temac_halt(dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int ll_temac_miiphy_read(const char *devname, unsigned char addr,
+				unsigned char reg, unsigned short *value)
+{
+	struct eth_device *dev = eth_get_dev();
+
+	*value = xps_ll_temac_hostif_get(dev, addr, reg);
+
+	debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *value);
+	return 0;
+}
+
+static int ll_temac_miiphy_write(const char *devname, unsigned char addr,
+				unsigned char reg, unsigned short value)
+{
+	struct eth_device *dev = eth_get_dev();
+	debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, value);
+
+	xps_ll_temac_hostif_set(dev, addr, reg, value);
+
+	return 0;
+}
+
+static int ll_temac_bus_reset(struct mii_dev *bus)
+{
+	debug("Just bus reset\n");
+	return 0;
+}
+
+/*
+ * bis:		board information
+ * base_addr:	LL TEMAC register bank
+ * ctrl_addr:	LL TEMAC sub-controller register bank (FIFO or SDMA)
+ * mode:	driver mode bit flags (see xilinx_ll_temac.h)
+ */
+int xilinx_ll_temac_initialize(bd_t *bis, unsigned long base_addr,
+				int mode, unsigned long ctrl_addr)
+{
+	struct eth_device *dev;
+	struct ll_temac *ll_temac;
+
+	dev = calloc(1, sizeof(*dev));
+	if (dev == NULL)
+		return -1;
+
+	dev->priv = calloc(1, sizeof(struct ll_temac));
+	if (dev->priv == NULL) {
+		free(dev);
+		return -1;
+	}
+
+	ll_temac = dev->priv;
+
+	sprintf(dev->name, "Xlltem.%lx", base_addr);
+
+	dev->iobase = base_addr;
+	ll_temac->ctrladdr = ctrl_addr;
+	ll_temac->rx_bp = rx_buffer;
+	ll_temac->tx_bp = tx_buffer;
+	ll_temac->rx_dp = &rx_descr;
+	ll_temac->tx_dp = &tx_descr;
+	ll_temac->phyaddr = CONFIG_PHY_ADDR;
+
+	dev->init = ll_temac_init;
+	dev->halt = ll_temac_halt;
+	dev->write_hwaddr = ll_temac_addr_setup;
+
+	if (mode & M_SDMA) {
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+		if (mode & M_DCR) {
+			ll_temac->ctrlinit = ll_temac_init_dmac;
+			ll_temac->ctrlhalt = ll_temac_halt_dmac;
+			ll_temac->ctrlreset = ll_temac_reset_dmac;
+			dev->recv = ll_temac_recv_dmac;
+			dev->send = ll_temac_send_dmac;
+		} else
+#endif
+		{
+			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->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;
+	}
+
+	eth_register(dev);
+
+	miiphy_register(dev->name, ll_temac_miiphy_read, ll_temac_miiphy_write);
+	ll_temac->bus = miiphy_get_dev_by_name(dev->name);
+	ll_temac->bus->reset = ll_temac_bus_reset;
+	return 1;
+}
diff --git a/drivers/net/xilinx_ll_temac.h b/drivers/net/xilinx_ll_temac.h
new file mode 100644
index 0000000..9e94f71
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac.h
@@ -0,0 +1,306 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * private interface
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+#ifndef _XILINX_LL_TEMAC_
+#define _XILINX_LL_TEMAC_
+
+#include <net.h>
+#include <phy.h>
+#include <miiphy.h>
+#include <asm/byteorder.h>
+
+#include "xilinx_ll_temac_fifo.h"
+#include "xilinx_ll_temac_sdma.h"
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+struct ll_temac {
+	int	ctrladdr;
+	void	(*ctrlinit) (struct eth_device *);
+	int	(*ctrlhalt) (struct eth_device *);
+	int	(*ctrlreset) (struct eth_device *);
+
+	unsigned char		*rx_bp;
+	unsigned char		*tx_bp;
+
+	struct cdmac_bd		*rx_dp;
+	struct cdmac_bd		*tx_dp;
+
+	int			phyaddr;
+	struct phy_device	*phydev;
+	struct mii_dev		*bus;
+};
+
+/*
+ * Driver mode bit flags
+ *
+ * FIXME: this should going up to include -- but where?
+ */
+#define M_FIFO		0		/* use FIFO Ctrl */
+#define M_SDMA		(1 << 0)	/* use SDMA Ctrl */
+#define M_DCR		(1 << 1)	/* use DCR Bus */
+
+/*
+ * TEMAC Memory and Register Definition
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [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)
+
+#endif /* _XILINX_LL_TEMAC_ */
diff --git a/drivers/net/xilinx_ll_temac_fifo.c b/drivers/net/xilinx_ll_temac_fifo.c
new file mode 100644
index 0000000..a2c66ab
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac_fifo.c
@@ -0,0 +1,93 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO interface
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+
+#ifdef DEBUG
+static void debugll(struct eth_device *dev, int count)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+	printf("FIFO: %d isr 0x%08x, ier 0x%08x, rdfr 0x%08x, "
+		"rdfo 0x%08x rlr 0x%08x\n", count,
+		in_be32(&fifo_ctrl->isr), in_be32(&fifo_ctrl->ier),
+		in_be32(&fifo_ctrl->rdfr), in_be32(&fifo_ctrl->rdfo),
+		in_be32(&fifo_ctrl->rlf));
+}
+#endif
+
+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)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+	u32 i, len = 0;
+	u32 *buf = (u32 *)&ll_temac->rx_bp;
+
+	if (in_be32(&fifo_ctrl->isr) & LL_FIFO_ISR_RC) {
+		out_be32(&fifo_ctrl->isr, ~0UL); /* reset isr */
+
+		/* while (fifo_ctrl->isr); */
+		len = in_be32(&fifo_ctrl->rlf) & LL_FIFO_RLF_MASK;
+
+		for (i = 0; i < len; i += 4)
+			*buf++ = in_be32(&fifo_ctrl->rdfd);
+
+#ifdef DEBUG
+		debugll(dev, 1);
+#endif
+		NetReceive((uchar *)&ll_temac->rx_bp, len);
+	}
+	return len;
+}
+
+int ll_temac_send_fifo(struct eth_device *dev,
+			volatile void *buffer, int length)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+	u32 *buf = (u32 *)buffer;
+	u32 i;
+
+	for (i = 0; i < length; i += 4)
+		out_be32(&fifo_ctrl->tdfd, *buf++);
+
+	out_be32(&fifo_ctrl->tlf, length);
+	return 0;
+}
diff --git a/drivers/net/xilinx_ll_temac_fifo.h b/drivers/net/xilinx_ll_temac_fifo.h
new file mode 100644
index 0000000..13236ac
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac_fifo.h
@@ -0,0 +1,115 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO interface
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+#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.
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [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)
+
+/* 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 (TLF), [1] p17/p18 */
+#define LL_FIFO_RLF_POS		0
+#define LL_FIFO_RLF_MASK	(0x000007FFUL << LL_FIFO_RLF_POS)
+
+/* 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 *buffer, int length);
+
+#endif /* _XILINX_LL_TEMAC_FIFO_ */
diff --git a/drivers/net/xilinx_ll_temac_sdma.c b/drivers/net/xilinx_ll_temac_sdma.c
new file mode 100644
index 0000000..24a0909
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac_sdma.c
@@ -0,0 +1,415 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA interface
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+
+#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 going up to arch/powerpc -- but where?
+ */
+#include <asm/processor.h>
+#define XILINX_INDIRECT_DCR_ADDRESS_REG	0
+#define XILINX_INDIRECT_DCR_ACCESS_REG	1
+unsigned mifdcr_xilinx(const unsigned dcrn)
+{
+	mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+	return mfdcr(XILINX_INDIRECT_DCR_ACCESS_REG);
+}
+unsigned mitdcr_xilinx(const unsigned dcrn, int val)
+{
+	mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+	mtdcr(XILINX_INDIRECT_DCR_ACCESS_REG, val);
+}
+#endif
+
+/* Check for TX and RX channel errrors. */
+static inline int ll_temac_sdma_error(struct eth_device *dev)
+{
+	int err;
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+
+	err = in_be32(&sdma_ctrl->tx_chnl_sts) & CHNL_STS_ERROR;
+	err |= in_be32(&sdma_ctrl->rx_chnl_sts) & CHNL_STS_ERROR;
+	return err;
+}
+
+void ll_temac_init_sdma(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+	struct cdmac_bd *rx_dp = ll_temac->rx_dp;
+	struct cdmac_bd *tx_dp = ll_temac->tx_dp;
+
+	memset(tx_dp, 0, sizeof(*tx_dp));
+	memset(rx_dp, 0, sizeof(*rx_dp));
+
+	/* from LL TEMAC (Rx) */
+	rx_dp->phys_buf_p = ll_temac->rx_bp;
+
+	rx_dp->next_p = rx_dp;
+	rx_dp->buf_len = PKTSIZE_ALIGN;
+	flush_cache((u32)rx_dp, sizeof(*tx_dp));
+	flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
+
+	out_be32(&sdma_ctrl->rx_curdesc_ptr, (u32)rx_dp);
+	out_be32(&sdma_ctrl->rx_taildesc_ptr, (u32)rx_dp);
+	out_be32(&sdma_ctrl->rx_nxtdesc_ptr, (u32)rx_dp); /* setup first fd */
+
+	/* to LL TEMAC (Tx) */
+	tx_dp->phys_buf_p = ll_temac->tx_bp;
+	tx_dp->next_p = tx_dp;
+
+	flush_cache((u32)tx_dp, sizeof(*tx_dp));
+	out_be32(&sdma_ctrl->tx_curdesc_ptr, (u32)tx_dp);
+}
+
+int ll_temac_halt_sdma(struct eth_device *dev)
+{
+	unsigned timeout = 2000;
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+
+	/*
+	 * 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.
+	 */
+	out_be32(&sdma_ctrl->dma_control_reg, DMA_CONTROL_RESET);
+	while (timeout && (in_be32(&sdma_ctrl->dma_control_reg)
+					& DMA_CONTROL_RESET))
+		timeout--;
+
+	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;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+
+	/* Soft reset the DMA.  */
+	if (ll_temac_halt_sdma(dev))
+		return 1;
+
+	/* Now clear the interrupts.  */
+	r = in_be32(&sdma_ctrl->tx_chnl_ctrl);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	out_be32(&sdma_ctrl->tx_chnl_ctrl, r);
+
+	r = in_be32(&sdma_ctrl->rx_chnl_ctrl);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	out_be32(&sdma_ctrl->rx_chnl_ctrl, r);
+
+	/* Now ACK pending IRQs.  */
+	out_be32(&sdma_ctrl->tx_irq_reg, IRQ_REG_IRQ_MASK);
+	out_be32(&sdma_ctrl->rx_irq_reg, IRQ_REG_IRQ_MASK);
+
+	/* Set tail-ptr mode, disable errors for both channels.  */
+	out_be32(&sdma_ctrl->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;
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+	struct cdmac_bd *rx_dp = ll_temac->rx_dp;
+
+	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;
+
+	/*
+	 * Read out the packet info and start the DMA
+	 * onto the second buffer to enable the ethernet rx
+	 * path to run in parallel with sw processing
+	 * packets.
+	 */
+	length = rx_dp->sca.app[4] & CDMAC_BD_APP4_RXBYTECNT_MASK;
+	if (length > 0)
+		NetReceive(rx_dp->phys_buf_p, length);
+
+	/* flip the buffer and re-enable the DMA.  */
+	flush_cache((u32)rx_dp->phys_buf_p, length);
+
+	rx_dp->buf_len = PKTSIZE_ALIGN;
+	rx_dp->sca.stctrl = 0;
+	rx_dp->sca.app[4] = 0;
+
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+	out_be32(&sdma_ctrl->rx_taildesc_ptr, (u32)rx_dp);
+
+	return length;
+}
+
+int ll_temac_send_sdma(struct eth_device *dev,
+				volatile void *buffer, int length)
+{
+	unsigned timeout = 2000;
+	struct ll_temac *ll_temac = dev->priv;
+	struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+	struct cdmac_bd *tx_dp = ll_temac->tx_dp;
+
+	if (ll_temac_sdma_error(dev)) {
+		if (ll_temac_reset_sdma(dev))
+			return -1;
+		ll_temac_init_sdma(dev);
+	}
+
+	memcpy(ll_temac->tx_bp, (void *)buffer, length);
+	flush_cache((u32)ll_temac->tx_bp, length);
+
+	tx_dp->sca.stctrl = CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP |
+			CDMAC_BD_STCTRL_STOP_ON_END;
+	tx_dp->buf_len = length;
+	flush_cache((u32)tx_dp, sizeof(*tx_dp));
+
+	out_be32(&sdma_ctrl->tx_curdesc_ptr, (u32)tx_dp);
+	out_be32(&sdma_ctrl->tx_taildesc_ptr, (u32)tx_dp); /* DMA start */
+
+	do {
+		flush_cache((u32)tx_dp, sizeof(*tx_dp));
+	} while (timeout-- && !(tx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED));
+
+	if (!timeout)
+		printf("%s: Timeout\n", __func__);
+
+	return 0;
+}
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+/* Check for TX and RX channel errrors. */
+static inline int ll_temac_dmac_error(struct eth_device *dev)
+{
+	int err;
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+
+	err = mifdcr_xilinx(dmac_ctrl + TX_CHNL_STS) & CHNL_STS_ERROR;
+	err |= mifdcr_xilinx(dmac_ctrl + RX_CHNL_STS) & CHNL_STS_ERROR;
+	return err;
+}
+
+void ll_temac_init_dmac(struct eth_device *dev)
+{
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+	struct cdmac_bd *rx_dp = ll_temac->rx_dp;
+	struct cdmac_bd *tx_dp = ll_temac->tx_dp;
+
+	memset(tx_dp, 0, sizeof(*tx_dp));
+	memset(rx_dp, 0, sizeof(*rx_dp));
+
+	/* from LL TEMAC (Rx) */
+	rx_dp->phys_buf_p = ll_temac->rx_bp;
+
+	rx_dp->next_p = rx_dp;
+	rx_dp->buf_len = PKTSIZE_ALIGN;
+	flush_cache((u32)rx_dp, sizeof(*tx_dp));
+	flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
+
+	/* setup first fd */
+	mitdcr_xilinx(dmac_ctrl + RX_CURDESC_PTR, (u32)rx_dp);
+	mitdcr_xilinx(dmac_ctrl + RX_TAILDESC_PTR, (u32)rx_dp);
+	mitdcr_xilinx(dmac_ctrl + RX_NXTDESC_PTR, (u32)rx_dp);
+
+	/* to LL TEMAC (Tx) */
+	tx_dp->phys_buf_p = ll_temac->tx_bp;
+	tx_dp->next_p = tx_dp;
+
+	flush_cache((u32)tx_dp, sizeof(*tx_dp));
+	mitdcr_xilinx(dmac_ctrl + TX_CURDESC_PTR, (u32)rx_dp);
+}
+
+int ll_temac_halt_dmac(struct eth_device *dev)
+{
+	unsigned timeout = 2000;
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+
+	/*
+	 * 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.
+	 */
+	mitdcr_xilinx(dmac_ctrl + DMA_CONTROL_REG, DMA_CONTROL_RESET);
+	while (timeout && (mifdcr_xilinx(dmac_ctrl + DMA_CONTROL_REG)
+					& DMA_CONTROL_RESET))
+		timeout--;
+
+	if (!timeout) {
+		printf("%s: Timeout\n", __func__);
+		return 1;
+	}
+
+	return 0;
+}
+
+int ll_temac_reset_dmac(struct eth_device *dev)
+{
+	u32 r;
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+
+	/* Soft reset the DMA.  */
+	if (ll_temac_halt_dmac(dev))
+		return 1;
+
+	/* Now clear the interrupts.  */
+	r = mifdcr_xilinx(dmac_ctrl + TX_CHNL_CTRL);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	mitdcr_xilinx(dmac_ctrl + TX_CHNL_CTRL, r);
+
+	r = mifdcr_xilinx(dmac_ctrl + RX_CHNL_CTRL);
+	r &= ~CHNL_CTRL_IRQ_MASK;
+	mitdcr_xilinx(dmac_ctrl + RX_CHNL_CTRL, r);
+
+	/* Now ACK pending IRQs.  */
+	mitdcr_xilinx(dmac_ctrl + TX_IRQ_REG, IRQ_REG_IRQ_MASK);
+	mitdcr_xilinx(dmac_ctrl + RX_IRQ_REG, IRQ_REG_IRQ_MASK);
+
+	/* Set tail-ptr mode, disable errors for both channels.  */
+	mitdcr_xilinx(dmac_ctrl + 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_dmac(struct eth_device *dev)
+{
+	int length;
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+	struct cdmac_bd *rx_dp = ll_temac->rx_dp;
+
+	if (ll_temac_dmac_error(dev)) {
+		if (ll_temac_reset_dmac(dev))
+			return -1;
+		ll_temac_init_dmac(dev);
+	}
+
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+	if (!(rx_dp.sca.stctrl & CDMAC_BD_STCTRL_COMPLETED))
+		return 0;
+
+	/*
+	 * Read out the packet info and start the DMA
+	 * onto the second buffer to enable the ethernet rx
+	 * path to run in parallel with sw processing
+	 * packets.
+	 */
+	length = rx_dp->sca.app[4] & CDMAC_BD_APP4_RXBYTECNT_MASK;
+	if (length > 0)
+		NetReceive(rx_dp->phys_buf_p, length);
+
+	/* flip the buffer and re-enable the DMA.  */
+	flush_cache((u32)rx_dp->phys_buf_p, length);
+
+	rx_dp->buf_len = PKTSIZE_ALIGN;
+	rx_dp->sca.stctrl = 0;
+	rx_dp->sca.app[4] = 0;
+
+	flush_cache((u32)rx_dp, sizeof(*rx_dp));
+	mitdcr_xilinx(dmac_ctrl + RX_TAILDESC_PTR, (u32)rx_dp);
+
+	return length;
+}
+
+int ll_temac_send_dmac(struct eth_device *dev,
+				volatile void *buffer, int length)
+{
+	unsigned timeout = 2000;
+	struct ll_temac *ll_temac = dev->priv;
+	unsigned dmac_ctrl = ll_temac->ctrladdr;
+	struct cdmac_bd *tx_dp = ll_temac->tx_dp;
+
+	if (ll_temac_dmac_error(dev)) {
+		if (ll_temac_reset_dmac(dev))
+			return -1;
+		ll_temac_init_dmac(dev);
+	}
+
+	memcpy(ll_temac->tx_bp, (void *)buffer, length);
+	flush_cache((u32)ll_temac->tx_bp, length);
+
+	tx_dp->sca.stctrl = CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP |
+			CDMAC_BD_STCTRL_STOP_ON_END;
+	tx_dp->buf_len = length;
+	flush_cache((u32)tx_dp, sizeof(*tx_dp));
+
+	mitdcr_xilinx(dmac_ctrl + TX_CURDESC_PTR, (u32)tx_dp);
+	mitdcr_xilinx(dmac_ctrl + TX_TAILDESC_PTR, (u32)tx_dp); /* DMA start */
+
+	do {
+		flush_cache((u32)tx_dp, sizeof(*tx_dp));
+	} while (timeout-- && !(tx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED));
+
+	if (!timeout)
+		printf("%s: Timeout\n", __func__);
+
+	return 0;
+}
+#endif /* CONFIG_XILINX_440 || CONFIG_XILINX_405 */
diff --git a/drivers/net/xilinx_ll_temac_sdma.h b/drivers/net/xilinx_ll_temac_sdma.h
new file mode 100644
index 0000000..d9a158c
--- /dev/null
+++ b/drivers/net/xilinx_ll_temac_sdma.h
@@ -0,0 +1,277 @@ 
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA interface
+ *
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Copyright (C) 2011 Stepahn Linz <linz@li-pro.net>
+ *
+ * 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.
+ */
+#ifndef _XILINX_LL_TEMAC_SDMA_
+#define _XILINX_LL_TEMAC_SDMA_
+
+#include <net.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+#if defined(CONFIG_SYS_CACHELINE_SIZE)
+#define DMAALIGN CONFIG_SYS_CACHELINE_SIZE
+#else
+/* we expact to live in a 32 bit processor environment */
+#define DMAALIGN 32
+#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
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [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
+ */
+struct sdma_ctrl {
+	/* Transmit Registers */
+	u32 tx_nxtdesc_ptr;	/* TX Next Description Pointer */
+	u32 tx_curbuf_addr;	/* TX Current Buffer Address */
+	u32 tx_curbuf_length;	/* TX Current Buffer Length */
+	u32 tx_curdesc_ptr;	/* TX Current Descriptor Pointer */
+	u32 tx_taildesc_ptr;	/* TX Tail Descriptor Pointer */
+	u32 tx_chnl_ctrl;	/* TX Channel Control */
+	u32 tx_irq_reg;		/* TX Interrupt Register */
+	u32 tx_chnl_sts;	/* TX Status Register */
+	/* Receive Registers */
+	u32 rx_nxtdesc_ptr;	/* RX Next Descriptor Pointer */
+	u32 rx_curbuf_addr;	/* RX Current Buffer Address */
+	u32 rx_curbuf_length;	/* RX Current Buffer Length */
+	u32 rx_curdesc_ptr;	/* RX Current Descriptor Pointer */
+	u32 rx_taildesc_ptr;	/* RX Tail Descriptor Pointer */
+	u32 rx_chnl_ctrl;	/* RX Channel Control */
+	u32 rx_irq_reg;		/* RX Interrupt Register */
+	u32 rx_chnl_sts;	/* RX Status Register */
+	/* Control Registers */
+	u32 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)
+
+/* initialize both Rx/Tx buffer descriptors */
+void 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 *buffer, int length);
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+/*
+ * 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 {
+	TX_NXTDESC_PTR = 0,
+	TX_CURBUF_ADDR,
+	TX_CURBUF_LENGTH,
+	TX_CURDESC_PTR,
+	TX_TAILDESC_PTR,
+	TX_CHNL_CTRL,
+	TX_IRQ_REG,
+	TX_CHNL_STS,
+	RX_NXTDESC_PTR,
+	RX_CURBUF_ADDR,
+	RX_CURBUF_LENGTH,
+	RX_CURDESC_PTR,
+	RX_TAILDESC_PTR,
+	RX_CHNL_CTRL,
+	RX_IRQ_REG,
+	RX_CHNL_STS,
+	DMA_CONTROL_REG
+};
+
+/* initialize both Rx/Tx buffer descriptors */
+void ll_temac_init_dmac(struct eth_device *dev);
+
+/* halt both Rx/Tx transfers */
+int ll_temac_halt_dmac(struct eth_device *dev);
+
+/* reset SDMA and IRQ, disable interrupts and errors */
+int ll_temac_reset_dmac(struct eth_device *dev);
+
+/* receive buffered data from SDMA (polling ISR) */
+int ll_temac_recv_dmac(struct eth_device *dev);
+
+/* send buffered data to SDMA */
+int ll_temac_send_dmac(struct eth_device *dev,
+			volatile void *buffer, int length);
+
+#endif /* CONFIG_XILINX_440 || CONFIG_XILINX_405 */
+
+#endif /* _XILINX_LL_TEMAC_SDMA_ */
diff --git a/include/netdev.h b/include/netdev.h
index 04d9f75..061c1f1 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -100,6 +100,8 @@  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_initialize(bd_t *bis, unsigned long base_addr,
+						int mode, unsigned long ctrl);
 
 /* Boards with PCI network controllers can call this from their board_eth_init()
  * function to initialize whatever's on board.