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

* 'master' of git://git.denx.de/u-boot-net:
  net/designware: Change timeout loop implementation
  net/designware: Set ANAR to 0x1e1
  net/designware: Program phy registers when auto-negotiation is ON
  net/designware: Try configuring phy on each dw_eth_init
  net/designware: Consecutive writes must have delay
  net/designware: Phy address fix
  net/designware: Fix the max frame length size
  net/designware: Fix to restore hw mac address
  microblaze: Wire up LL_TEMAC driver initialization
  microblaze: Add faked LL_TEMAC driver configuration
  microblaze: Enable several ethernet driver compilation
  net: ll_temac: Add LL TEMAC driver to u-boot
  Update net subsystem maintainer in doc/git-mailrc
  net/eth.c: fix eth_write_hwaddr() to use dev->enetaddr as fall back
  mvgbe: remove warning for unused methods
This commit is contained in:
Wolfgang Denk 2012-04-09 17:10:01 +02:00
commit 2c734cd932
19 changed files with 2025 additions and 51 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,53 @@
/*
* Xilinx xps_ll_temac ethernet driver for u-boot
*
* MDIO bus access interface
*
* Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
* Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008 - 2011 PetaLogix
*
* Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
* Copyright (C) 2008 Nissin Systems Co.,Ltd.
* March 2008 created
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* [0]: http://www.xilinx.com/support/documentation
*
* [S]: [0]/ip_documentation/xps_ll_temac.pdf
* [A]: [0]/application_notes/xapp1041.pdf
*/
#ifndef _XILINX_LL_TEMAC_MDIO_
#define _XILINX_LL_TEMAC_MDIO_
#include <net.h>
#include <miiphy.h>
#include <asm/types.h>
#include <asm/byteorder.h>
#include "xilinx_ll_temac.h"
int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
int regnum);
void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
int regnum, u16 value);
int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum);
int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
u16 value);
int ll_temac_phy_addr(struct mii_dev *bus);
struct ll_temac_mdio_info {
struct temac_reg *regs;
char *name;
};
int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info);
#endif /* _XILINX_LL_TEMAC_MDIO_ */

View file

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

View file

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

View file

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

View file

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

View file

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