[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