From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Vasut Date: Wed, 31 Aug 2011 23:52:46 +0200 Subject: [U-Boot] [PATCH v2] net: ll_temac: Add LL TEMAC driver to u-boot In-Reply-To: <1314705919-4237-1-git-send-email-monstr@monstr.eu> References: <1314705919-4237-1-git-send-email-monstr@monstr.eu> Message-ID: <201108312352.47271.marek.vasut@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 > > --- > 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 > + * 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 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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!