[U-Boot] [PATCH v2] net: ll_temac: Add LL TEMAC driver to u-boot

Marek Vasut marek.vasut at gmail.com
Wed Aug 31 23:52:46 CEST 2011


On Tuesday, August 30, 2011 02:05:18 PM Michal Simek wrote:
> LL Temac driver can be used by microblaze, xilinx ppc405/440
> in sdma and fifo mode. DCR or XPS bus can be used.
> 
> The driver uses and requires PHYLIB.
> 
> Signed-off-by: Michal Simek <monstr at monstr.eu>
> 
> ---
> 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          |    1 +
>  drivers/net/xilinx_ll_temac.c |  665
> +++++++++++++++++++++++++++++++++++++++++ include/netdev.h              | 
>   2 +
>  3 files changed, 668 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/xilinx_ll_temac.c
> 
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 819b197..4541eaf 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -84,6 +84,7 @@ COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o
>  COBJS-$(CONFIG_ULI526X) += uli526x.o
>  COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
>  COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
> +COBJS-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.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..878cdf2
> --- /dev/null
> +++ b/drivers/net/xilinx_ll_temac.c
> @@ -0,0 +1,665 @@
> +/*
> + * Xilinx xps_ll_temac ethernet driver for u-boot
> + *
> + * Copyright (C) 2008 - 2011 Michal Simek <monstr at monstr.eu>
> + * Copyright (C) 2008 - 2011 PetaLogix
> + *
> + * Based on Yoshio Kashiwagi kashiwagi at 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/processor.h>
> +#include <asm/io.h>
> +#include <phy.h>
> +#include <miiphy.h>
> +
> +#undef ETH_HALTING
> +
> +#define XTE_EMMC_LINKSPEED_MASK	0xC0000000 /* Link speed */
> +/* XTE_EMCFG_LINKSPD_MASK */
> +#define XTE_EMMC_LINKSPD_10	0x00000000 /* for 10 Mbit */
> +#define XTE_EMMC_LINKSPD_100	0x40000000 /* for 100 Mbit */
> +#define XTE_EMMC_LINKSPD_1000	0x80000000 /* forr 1000 Mbit */
> +

Hi,

ok, this is the usual stuff -- use (1 << n) and struct temac_regs {...};

> +#define XTE_RSE_MIIM_RR_MASK	0x0002
> +#define XTE_RSE_MIIM_WR_MASK	0x0004
> +#define XTE_RSE_CFG_RR_MASK	0x0020
> +#define XTE_RSE_CFG_WR_MASK	0x0040
> +
> +/* XPS_LL_TEMAC indirect registers offset definition */
> +#define RCW1	0x240
> +#define TC	0x280
> +#define EMMC	0x300
> +#define MC	0x340
> +#define UAW0	0x380
> +#define UAW1	0x384
> +#define AFM	0x390
> +#define MIIMWD	0x3b0
> +#define MIIMAI	0x3b4
> +
> +#define CNTLREG_WRITE_ENABLE_MASK	0x8000
> +
> +#define MDIO_ENABLE_MASK	0x40
> +#define MDIO_CLOCK_DIV_100MHz	0x28
> +
> +/* XPS_LL_TEMAC SDMA registers definition */
> +# define TX_CURDESC_PTR		0x03
> +# define TX_TAILDESC_PTR	0x04
> +# define TX_CHNL_CTRL		0x05
> +# define TX_IRQ_REG		0x06
> +# define TX_CHNL_STS		0x07
> +# define RX_NXTDESC_PTR		0x08
> +# define RX_CURDESC_PTR		0x0b
> +# define RX_TAILDESC_PTR	0x0c
> +# define RX_CHNL_CTRL		0x0d
> +# define RX_IRQ_REG		0x0e
> +# define RX_CHNL_STS		0x0f
> +
> +# define DMA_CONTROL_REG	0x10
> +
> +/* CDMAC descriptor status bit definitions */
> +# define BDSTAT_STOP_ON_END_MASK	0x20
> +# define BDSTAT_COMPLETED_MASK		0x10
> +# define BDSTAT_SOP_MASK		0x08
> +# define BDSTAT_EOP_MASK		0x04
> +
> +# define CHNL_STS_ERROR_MASK		0x80
> +
> +/* All interrupt enable bits */
> +#define XLLDMA_CR_IRQ_ALL_EN_MASK	0x00000087
> +/* All interrupt bits */
> +#define XLLDMA_IRQ_ALL_MASK		0x0000001F
> +/* Disable error when 2 or 4 bit coalesce counter overflows */
> +#define XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK	0x00000010
> +/* Disable error when 2 or 4 bit coalesce counter overflows */
> +#define XLLDMA_DMACR_TX_OVERFLOW_ERR_DIS_MASK	0x00000008
> +/* Enable use of tail pointer register */
> +#define XLLDMA_DMACR_TAIL_PTR_EN_MASK	0x00000004
> +
> +#define SDMA_BIT	1
> +#define DCR_BIT		2
> +
> +#define DMAALIGN	32
> +
> +/* SDMA Buffer Descriptor */
> +struct cdmac_bd_t {
> +	struct cdmac_bd_t *next_p;
> +	unsigned char *phys_buf_p;
> +	unsigned long buf_len;
> +	unsigned char stat;
> +	unsigned char app1_1;
> +	unsigned short app1_2;
> +	unsigned long app2;
> +	unsigned long app3;
> +	unsigned long app4;
> +	unsigned long app5;

maybe app[4] ?

> +};
> +
> +static struct cdmac_bd_t tx_bd __attribute((aligned(DMAALIGN)));
> +static struct cdmac_bd_t rx_bd __attribute((aligned(DMAALIGN)));
> +
> +struct ll_fifo_s {
> +	int isr; /* Interrupt Status Register 0x0 */
> +	int ier; /* Interrupt Enable Register 0x4 */
> +	int tdfr; /* Transmit data FIFO reset 0x8 */
> +	int tdfv; /* Transmit data FIFO Vacancy 0xC */
> +	int tdfd; /* Transmit data FIFO 32bit wide data write port 0x10 */
> +	int tlf; /* Write Transmit Length FIFO 0x14 */
> +	int rdfr; /* Read Receive data FIFO reset 0x18 */
> +	int rdfo; /* Receive data FIFO Occupancy 0x1C */
> +	int rdfd; /* Read Receive data FIFO 32bit wide data read port 0x20 */
> +	int rlf; /* Read Receive Length FIFO 0x24 */
> +	int llr; /* Read LocalLink reset 0x28 */
> +};
> +
> +static unsigned char tx_buffer[PKTSIZE_ALIGN]
> __attribute((aligned(DMAALIGN))); +static unsigned char
> rx_buffer[PKTSIZE_ALIGN] __attribute((aligned(DMAALIGN))); +
> +struct temac_reg {
> +	unsigned long msw; /* Hard TEMAC MSW Data Register */
> +	unsigned long lsw; /* Hard TEMAC LSW Data Register */
> +	unsigned long ctl; /* Hard TEMAC Control Register */
> +	unsigned long rdy; /* Hard TEMAC Ready Status */
> +};
> +
> +struct ll_priv {
> +	unsigned int ctrl;
> +	struct temac_reg *regs;
> +	unsigned int mode;
> +	int phyaddr;
> +
> +	struct phy_device *phydev;
> +	struct mii_dev *bus;
> +};
> +
> +static void mtdcr_local(u32 reg, u32 val)
> +{
> +#if defined(CONFIG_PPC)
> +	mtdcr(0x00, reg);
> +	mtdcr(0x01, val);
> +#endif

What are these magic values with no description ?

> +}
> +
> +static u32 mfdcr_local(u32 reg)
> +{
> +	u32 val = 0;
> +#if defined(CONFIG_PPC)
> +	mtdcr(0x00, reg);
> +	val = mfdcr(0x01);
> +#endif

dtto

> +	return val;
> +}
> +
> +static void sdma_out_be32(struct ll_priv *priv, u32 offset, u32 val)
> +{
> +	if (priv->mode & DCR_BIT)
> +		mtdcr_local(priv->ctrl + offset, val);
> +	else
> +		out_be32((u32 *)(priv->ctrl + offset * 4), val);

If priv->ctrl was well defined structure, you won't need this cast, offset etc. 
Besides I see you have it defined as unsigned int ... make it u32 if you want to 
define registers that way. Still, struct is way to go.

> +}
> +
> +static u32 sdma_in_be32(struct ll_priv *priv, u32 offset)
> +{
> +	if (priv->mode & DCR_BIT)
> +		return mfdcr_local(priv->ctrl + offset);
> +
> +	return in_be32((u32 *)(priv->ctrl + offset * 4));

DITTO, besides, in the previous code, you only do out_be32() in else branch, 
here you do it unconditionally. Maybe you can make them look similar.

> +}
> +
> +#if defined(DEBUG) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
> +/* undirect hostif write to ll_temac */
> +static void xps_ll_temac_hostif_set(struct eth_device *dev, int emac,
> +			int phy_addr, int reg_addr, int phy_data)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	volatile struct temac_reg *regs = priv->regs;
> +
> +	regs->lsw = phy_data;
> +	regs->ctl = CNTLREG_WRITE_ENABLE_MASK | MIIMWD;
> +	regs->lsw = (phy_addr << 5) | reg_addr;
> +	regs->ctl = CNTLREG_WRITE_ENABLE_MASK | MIIMAI | (emac << 10);

writel() or out_be32()

> +	while (!(regs->rdy & XTE_RSE_MIIM_WR_MASK))
> +		;

No endless loops

> +}
> +#endif
> +
> +/* undirect hostif read from ll_temac */
> +static unsigned int xps_ll_temac_hostif_get(struct eth_device *dev,
> +			int emac, int phy_addr, int reg_addr)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	volatile struct temac_reg *regs = priv->regs;
> +
> +	regs->lsw = (phy_addr << 5) | reg_addr;
> +	regs->ctl = MIIMAI | (emac << 10);

writel() or out_be32(), please fix globally.

> +	while (!(regs->rdy & XTE_RSE_MIIM_RR_MASK))
> +		;

no endless loops, please fix globally

> +	return regs->lsw;

return readl() I guess ... 

> +}
> +
> +/* undirect write to ll_temac */
> +static void xps_ll_temac_indirect_set(struct eth_device *dev,
> +				int emac, int reg_offset, int reg_data)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	volatile struct temac_reg *regs = priv->regs;

No volatiles please.

> +
> +	regs->lsw = reg_data;
> +	regs->ctl = CNTLREG_WRITE_ENABLE_MASK | (emac << 10) | reg_offset;
> +	while (!(regs->rdy & XTE_RSE_CFG_WR_MASK))
> +		;
> +}
> +
> +/* undirect read from ll_temac */
> +static int xps_ll_temac_indirect_get(struct eth_device *dev,
> +			int emac, int reg_offset)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	volatile struct temac_reg *regs = priv->regs;
> +
> +	regs->ctl = (emac << 10) | reg_offset;
> +	while (!(regs->rdy & XTE_RSE_CFG_RR_MASK))
> +		;
> +	return regs->lsw;
> +}
> +
> +#ifdef DEBUG
> +/* read from phy */
> +static void read_phy_reg(struct eth_device *dev, int phy_addr)
> +{
> +	int j, result;
> +	debug("phy%d ", phy_addr);
> +	for (j = 0; j < 32; j++) {
> +		result = xps_ll_temac_hostif_get(dev, 0, 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)
> +{
> +#ifdef CONFIG_PHYLIB
> +	int i;
> +	unsigned int temp, speed;
> +	struct ll_priv *priv = 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 (priv->phyaddr == -1) {
> +		for (i = 31; i >= 0; i--) {
> +			temp = xps_ll_temac_hostif_get(dev, 0, i, 1);
> +			if ((temp & 0x0ffff) != 0x0ffff) {
> +				debug("phy %x result %x\n", i, temp);
> +				priv->phyaddr = i;
> +				break;
> +			}
> +		}
> +	}
> +
> +	/* interface - look at tsec */
> +	phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
> +
> +	phydev->supported &= supported;
> +	phydev->advertising = phydev->supported;
> +	priv->phydev = phydev;
> +	phy_config(phydev);
> +	phy_startup(phydev);
> +
> +	switch (phydev->speed) {
> +	case 1000:
> +		speed = XTE_EMMC_LINKSPD_1000;
> +		break;
> +	case 100:
> +		speed = XTE_EMMC_LINKSPD_100;
> +		break;
> +	case 10:
> +		speed = XTE_EMMC_LINKSPD_10;
> +		break;
> +	default:
> +		return 0;
> +	}
> +	temp = xps_ll_temac_indirect_get(dev, 0, EMMC) &
> +						(~XTE_EMMC_LINKSPEED_MASK);

Do you need those parenthesis ? Maybe you can divide this into ...

temp = xps_ll...();
temp &= ~XTE...;
temp |= speed;
xps_ll...();

Might be a bit more readable.

> +	temp |= speed;
> +	xps_ll_temac_indirect_set(dev, 0, EMMC, temp);
> +
> +	return 1;
> +#else
> +	puts("Enable PHYLIB support!\n");
> +	return 0;
> +#endif

Please move this #ifdef CONFIG_PHYLIB at the begining of the file and emit a 
compile-time warning.

> +}
> +
> +static inline int xps_ll_temac_dma_error(struct eth_device *dev)
> +{
> +	int err;
> +	struct ll_priv *priv = dev->priv;
> +
> +	/* Check for TX and RX channel errrors.  */
> +	err = sdma_in_be32(priv, TX_CHNL_STS) & CHNL_STS_ERROR_MASK;
> +	err |= sdma_in_be32(priv, RX_CHNL_STS) & CHNL_STS_ERROR_MASK;
> +	return err;
> +}
> +
> +static void xps_ll_temac_reset_dma(struct eth_device *dev)
> +{
> +	u32 r;
> +	struct ll_priv *priv = dev->priv;
> +
> +	/* Soft reset the DMA.  */
> +	sdma_out_be32(priv, DMA_CONTROL_REG, 0x00000001);
> +	while (sdma_in_be32(priv, DMA_CONTROL_REG) & 1)
> +		;

Ok, maybe #define SDMA_RESET 0x1 won't hurt here.

> +
> +	/* Now clear the interrupts.  */
> +	r = sdma_in_be32(priv, TX_CHNL_CTRL);
> +	r &= ~XLLDMA_CR_IRQ_ALL_EN_MASK;
> +	sdma_out_be32(priv, TX_CHNL_CTRL, r);
> +
> +	r = sdma_in_be32(priv, RX_CHNL_CTRL);
> +	r &= ~XLLDMA_CR_IRQ_ALL_EN_MASK;
> +	sdma_out_be32(priv, RX_CHNL_CTRL, r);
> +
> +	/* Now ACK pending IRQs.  */
> +	sdma_out_be32(priv, TX_IRQ_REG, XLLDMA_IRQ_ALL_MASK);
> +	sdma_out_be32(priv, RX_IRQ_REG, XLLDMA_IRQ_ALL_MASK);
> +
> +	/* Set tail-ptr mode, disable errors for both channels.  */
> +	sdma_out_be32(priv, DMA_CONTROL_REG,
> +			XLLDMA_DMACR_TAIL_PTR_EN_MASK |
> +			XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK |
> +			XLLDMA_DMACR_TX_OVERFLOW_ERR_DIS_MASK);
> +}
> +
> +/* bd init */
> +static void xps_ll_temac_bd_init(struct eth_device *dev)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	memset((void *)&tx_bd, 0, sizeof(tx_bd));
> +	memset((void *)&rx_bd, 0, sizeof(rx_bd));

Do you need the cast?

> +
> +	rx_bd.phys_buf_p = &rx_buffer[0];

rx_buffer would be sufficient here.

> +
> +	rx_bd.next_p = &rx_bd;
> +	rx_bd.buf_len = PKTSIZE_ALIGN;
> +	flush_cache((u32)&rx_bd, sizeof(tx_bd));
> +	flush_cache((u32)rx_bd.phys_buf_p, PKTSIZE_ALIGN);
> +
> +	sdma_out_be32(priv, RX_CURDESC_PTR, (u32)&rx_bd);
> +	sdma_out_be32(priv, RX_TAILDESC_PTR, (u32)&rx_bd);
> +	sdma_out_be32(priv, RX_NXTDESC_PTR, (u32)&rx_bd); /* setup first fd */
> +
> +	tx_bd.phys_buf_p = &tx_buffer[0];
> +	tx_bd.next_p = &tx_bd;
> +
> +	flush_cache((u32)&tx_bd, sizeof(tx_bd));
> +	sdma_out_be32(priv, TX_CURDESC_PTR, (u32)&tx_bd);
> +}
> +
> +static int ll_temac_send_sdma(struct eth_device *dev,
> +				volatile void *buffer, int length)
> +{
> +	struct ll_priv *priv = dev->priv;
> +
> +	if (xps_ll_temac_dma_error(dev)) {
> +		xps_ll_temac_reset_dma(dev);
> +		xps_ll_temac_bd_init(dev);
> +	}
> +
> +	memcpy(tx_buffer, (void *)buffer, length);
> +	flush_cache((u32)tx_buffer, length);
> +
> +	tx_bd.stat = BDSTAT_SOP_MASK | BDSTAT_EOP_MASK |
> +			BDSTAT_STOP_ON_END_MASK;
> +	tx_bd.buf_len = length;
> +	flush_cache((u32)&tx_bd, sizeof(tx_bd));
> +
> +	sdma_out_be32(priv, TX_CURDESC_PTR, (u32)&tx_bd);
> +	sdma_out_be32(priv, TX_TAILDESC_PTR, (u32)&tx_bd); /* DMA start */
> +
> +	do {
> +		flush_cache((u32)&tx_bd, sizeof(tx_bd));
> +	} while (!(((volatile int)tx_bd.stat) & BDSTAT_COMPLETED_MASK));

Whoa ... volatile int is really dangerous. And please add timeout.
> +
> +	return 0;
> +}
> +
> +static int ll_temac_recv_sdma(struct eth_device *dev)
> +{
> +	int length;
> +	struct ll_priv *priv = dev->priv;
> +
> +	if (xps_ll_temac_dma_error(dev)) {
> +		xps_ll_temac_reset_dma(dev);
> +		xps_ll_temac_bd_init(dev);
> +	}
> +
> +	flush_cache((u32)&rx_bd, sizeof(rx_bd));
> +
> +	if (!(rx_bd.stat & BDSTAT_COMPLETED_MASK))
> +		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_bd.app5 & 0x3FFF;

0x3fff should be explained here.

> +	if (length > 0)
> +		NetReceive(rx_bd.phys_buf_p, length);
> +
> +	/* flip the buffer and re-enable the DMA.  */
> +	flush_cache((u32)rx_bd.phys_buf_p, length);
> +
> +	rx_bd.buf_len = PKTSIZE_ALIGN;
> +	rx_bd.stat = 0;
> +	rx_bd.app5 = 0;
> +
> +	flush_cache((u32)&rx_bd, sizeof(rx_bd));
> +	sdma_out_be32(priv, RX_TAILDESC_PTR, (u32)&rx_bd);
> +
> +	return length;
> +}
> +
> +#ifdef DEBUG
> +static void debugll(struct eth_device *dev, int count)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	struct ll_fifo_s *ll_fifo = (void *)priv->ctrl;
> +	printf("%d fifo isr 0x%08x, fifo_ier 0x%08x, fifo_rdfr 0x%08x, "
> +		"fifo_rdfo 0x%08x fifo_rlr 0x%08x\n", count, ll_fifo->isr,
> +		ll_fifo->ier, ll_fifo->rdfr, ll_fifo->rdfo, ll_fifo->rlf);
> +}
> +#endif
> +
> +static int ll_temac_send_fifo(struct eth_device *dev,
> +					volatile void *buffer, int length)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	struct ll_fifo_s *ll_fifo = (void *)priv->ctrl;
> +	u32 *buf = (u32 *)buffer;
> +	u32 len, i, val;
> +
> +	len = (length / 4) + 1;
> +

Do you need the len at all ?

for (i = 0; i < length; i +=4 )
	writel(*buf++, ll_fifo->tdfd);

> +	for (i = 0; i < len; i++) {
> +		val = *buf++;
> +		ll_fifo->tdfd = val;
> +	}
> +
> +	ll_fifo->tlf = length;
> +
> +	return 0;
> +}
> +
> +static int ll_temac_recv_fifo(struct eth_device *dev)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	struct ll_fifo_s *ll_fifo = (void *)priv->ctrl;
> +	u32 len = 0;
> +	u32 len2, i, val;
> +	u32 *buf = (u32 *)&rx_buffer;
> +
> +	if (ll_fifo->isr & 0x04000000) {

Another magic value, please fix globally.

> +		ll_fifo->isr = 0xffffffff; /* reset isr */
> +
> +		/* while (ll_fifo->isr); */
> +		len = ll_fifo->rlf & 0x7FF;
> +		len2 = (len / 4) + 1;
> +
> +		for (i = 0; i < len2; i++) {
> +			val = ll_fifo->rdfd;
> +			*buf++ = val ;
> +		}
> +#ifdef DEBUG
> +		debugll(dev, 1);
> +#endif
> +		NetReceive((uchar *)&rx_buffer, len);
> +	}
> +	return len;
> +}
> +
> +/* setup mac addr */
> +static int ll_temac_addr_setup(struct eth_device *dev)
> +{
> +	int val;
> +
> +	/* set up unicast MAC address filter */
> +	val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) |
> +		(dev->enetaddr[1] << 8) | (dev->enetaddr[0]));
> +	xps_ll_temac_indirect_set(dev, 0, UAW0, val);
> +	val = (dev->enetaddr[5] << 8) | dev->enetaddr[4] ;
> +	xps_ll_temac_indirect_set(dev, 0, UAW1, val);
> +
> +	return 0;
> +}
> +
> +static int xps_ll_temac_init(struct eth_device *dev, bd_t *bis)
> +{
> +	struct ll_priv *priv = dev->priv;
> +	struct ll_fifo_s *ll_fifo = (void *)priv->ctrl;
> +
> +	if (priv->mode & SDMA_BIT) {
> +		xps_ll_temac_reset_dma(dev);
> +		xps_ll_temac_bd_init(dev);
> +	} else {
> +		ll_fifo->tdfr = 0x000000a5; /* set fifo length */
> +		ll_fifo->rdfr = 0x000000a5;
> +		/* ll_fifo->isr = 0x0; */
> +		/* ll_fifo->ier = 0x0; */

Why do you have this dead code here?

> +	}
> +
> +	xps_ll_temac_indirect_set(dev, 0, MC,
> +				MDIO_ENABLE_MASK | MDIO_CLOCK_DIV_100MHz);
> +
> +	/* Promiscuous mode disable */
> +	xps_ll_temac_indirect_set(dev, 0, AFM, 0x00000000);
> +	/* Enable Receiver */
> +	xps_ll_temac_indirect_set(dev, 0, RCW1, 0x10000000);
> +	/* Enable Transmitter */
> +	xps_ll_temac_indirect_set(dev, 0, TC, 0x10000000);

Magic values.

> +	return 0;
> +}
> +
> +/* halt device */
> +static void ll_temac_halt(struct eth_device *dev)
> +{
> +#ifdef ETH_HALTING
> +	struct ll_priv *priv = dev->priv;
> +	/* Disable Receiver */
> +	xps_ll_temac_indirect_set(dev, 0, RCW1, 0x00000000);
> +	/* Disable Transmitter */

Magic.

> +	xps_ll_temac_indirect_set(dev, 0, TC, 0x00000000);
> +
> +	if (priv->mode & SDMA_BIT) {
> +		sdma_out_be32(priv->ctrl, DMA_CONTROL_REG, 0x00000001);
> +		while (sdma_in_be32(priv->ctrl, DMA_CONTROL_REG) & 1)
> +			;
> +	}
> +	/* reset fifos */

Dead comment?

> +#endif
> +}
> +
> +static int ll_temac_init(struct eth_device *dev, bd_t *bis)
> +{
> +	struct ll_priv *priv = dev->priv;
> +#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, uchar addr,
> +							uchar reg, ushort *val)
> +{
> +	struct eth_device *dev = eth_get_dev();
> +
> +	*val = xps_ll_temac_hostif_get(dev, 0, addr, reg); /* emac = 0 */
> +
> +	debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *val);
> +	return 0;
> +}
> +
> +static int ll_temac_miiphy_write(const char *devname, uchar addr,
> +							uchar reg, ushort val)
> +{
> +	struct eth_device *dev = eth_get_dev();
> +	debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val);
> +
> +	xps_ll_temac_hostif_set(dev, 0, addr, reg, val);
> +
> +	return 0;
> +}
> +
> +static int ll_temac_bus_reset(struct mii_dev *bus)
> +{
> +	debug("Just bus reset\n");
> +	return 0;
> +}
> +
> +/* mode bits: 0bit - fifo(0)/sdma(1):SDMA_BIT, 1bit - no
> dcr(0)/dcr(1):DCR_BIT + * ctrl - control address for file/sdma */
> +int xilinx_ll_temac_initialize(bd_t *bis, unsigned long base_addr,
> +							int mode, int ctrl)
> +{
> +	struct eth_device *dev;
> +	struct ll_priv *priv;
> +
> +	dev = calloc(1, sizeof(*dev));
> +	if (dev == NULL)
> +		return -1;
> +
> +	dev->priv = calloc(1, sizeof(struct ll_priv));
> +	if (dev->priv == NULL) {
> +		free(dev);
> +		return -1;
> +	}
> +
> +	priv = dev->priv;
> +
> +	sprintf(dev->name, "Xlltem.%lx", base_addr);
> +
> +	dev->iobase = base_addr;
> +	priv->regs = (void *) (base_addr + 0x20);

Here you'd just load the struct :)

> +	priv->ctrl = ctrl;
> +	priv->mode = mode;
> +
> +#ifdef CONFIG_PHY_ADDR
> +	priv->phyaddr = CONFIG_PHY_ADDR;
> +#else
> +	priv->phyaddr = -1;
> +#endif
> +
> +	dev->init = ll_temac_init;
> +	dev->halt = ll_temac_halt;
> +	dev->write_hwaddr = ll_temac_addr_setup;
> +
> +	if (priv->mode & SDMA_BIT) {
> +		dev->send = ll_temac_send_sdma;
> +		dev->recv = ll_temac_recv_sdma;
> +	} else {
> +		dev->send = ll_temac_send_fifo;
> +		dev->recv = ll_temac_recv_fifo;
> +	}
> +
> +	eth_register(dev);
> +
> +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) ||
> defined(CONFIG_PHYLIB) +	miiphy_register(dev->name, ll_temac_miiphy_read,
> ll_temac_miiphy_write); +	priv->bus = miiphy_get_dev_by_name(dev->name);
> +	priv->bus->reset = ll_temac_bus_reset;
> +#endif
> +	return 1;
> +}
> diff --git a/include/netdev.h b/include/netdev.h
> index 26ce13d..cebae3b 100644
> --- a/include/netdev.h
> +++ b/include/netdev.h
> @@ -92,6 +92,8 @@ int uec_standard_init(bd_t *bis);
>  int uli526x_initialize(bd_t *bis);
>  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, int ctrl);
>  int sh_eth_initialize(bd_t *bis);
>  int dm9000_initialize(bd_t *bis);
>  int fecmxc_initialize(bd_t *bis);

The driver has some way to go, but it's mostly coding style. One or two more 
rounds and it's ready.

Cheers!


More information about the U-Boot mailing list