blob: fd40f6271a467b92e14519efc2116a63afd0f470 [file] [log] [blame]
#include <common.h>
#include <command.h>
#include <net.h>
#include <asm/io.h>
#include <miidev.h>
#include <mach/netx-xc.h>
#include <mach/netx-eth.h>
#include <mach/netx-regs.h>
#include <xfuncs.h>
#include <init.h>
#include <driver.h>
#define ETH_MAC_LOCAL_CONFIG 0x1560
#define ETH_MAC_4321 0x1564
#define ETH_MAC_65 0x1568
#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16
#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT)
#define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK)
#define FIFO_PTR_FRAMELEN_SHIFT 0
#define FIFO_PTR_FRAMELEN_MASK (0x7ff << 0)
#define FIFO_PTR_FRAMELEN(len) (((len) << 0) & FIFO_PTR_FRAMELEN_MASK)
#define FIFO_PTR_TIMETRIG (1<<11)
#define FIFO_PTR_MULTI_REQ
#define FIFO_PTR_ORIGIN (1<<14)
#define FIFO_PTR_VLAN (1<<15)
#define FIFO_PTR_FRAMENO_SHIFT 16
#define FIFO_PTR_FRAMENO_MASK (0x3f << 16)
#define FIFO_PTR_FRAMENO(no) ( ((no) << 16) & FIFO_PTR_FRAMENO_MASK)
#define FIFO_PTR_SEGMENT_SHIFT 22
#define FIFO_PTR_SEGMENT_MASK (0xf << 22)
#define FIFO_PTR_SEGMENT(seg) (((seg) & 0xf) << 22)
#define FIFO_PTR_ERROR_SHIFT 28
#define FIFO_PTR_ERROR_MASK (0xf << 28)
/* use sram 0 for now */
#define SRAM_BASE(xcno) (0x8000 * (xcno))
/* XC Fifo Offsets */
#define EMPTY_PTR_FIFO(xcno) (0 + ((xcno) << 3)) /* Index of the empty pointer FIFO */
#define IND_FIFO_PORT_HI(xcno) (1 + ((xcno) << 3)) /* Index of the FIFO where received Data packages are indicated by XC */
#define IND_FIFO_PORT_LO(xcno) (2 + ((xcno) << 3)) /* Index of the FIFO where received Data packages are indicated by XC */
#define REQ_FIFO_PORT_HI(xcno) (3 + ((xcno) << 3)) /* Index of the FIFO where Data packages have to be indicated by ARM which shall be sent */
#define REQ_FIFO_PORT_LO(xcno) (4 + ((xcno) << 3)) /* Index of the FIFO where Data packages have to be indicated by ARM which shall be sent */
#define CON_FIFO_PORT_HI(xcno) (5 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages are confirmed */
#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages are confirmed */
struct netx_eth_priv {
struct mii_device miidev;
int xcno;
};
static int netx_eth_send (struct eth_device *edev,
void *packet, int length)
{
struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
int xcno = priv->xcno;
unsigned int val;
int timeout = 500;
unsigned char *dst = (unsigned char *)(SRAM_BASE(xcno) + 1560);
memcpy(dst, (void *)packet, length);
if( length < 60 ) {
memset(dst + length, 0, 60 - length);
length = 60;
}
PFIFO_REG(PFIFO_BASE(REQ_FIFO_PORT_LO(xcno))) =
FIFO_PTR_SEGMENT(xcno) |
FIFO_PTR_FRAMENO(1) |
FIFO_PTR_FRAMELEN(length);
while (!PFIFO_REG( PFIFO_FILL_LEVEL(CON_FIFO_PORT_LO(xcno))) && timeout) {
timeout--;
udelay(100);
}
#if 0
if (!timeout) {
loadxc(0);
loadxc(1);
eth_init(gd->bd);
return -1;
}
#endif
val = PFIFO_REG( PFIFO_BASE(CON_FIFO_PORT_LO(xcno)) );
if((val & FIFO_PTR_ERROR_MASK) & 0x8)
printf("error sending frame: %d\n",val);
return 0;
}
static int netx_eth_rx (struct eth_device *edev)
{
struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
int xcno = priv->xcno;
unsigned int val, frameno, seg, len;
if(!PFIFO_REG( PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(xcno)))) {
return 0;
}
val = PFIFO_REG( PFIFO_BASE(IND_FIFO_PORT_LO(xcno)) );
frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT;
seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT;
len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT;
/* get data */
memcpy((void*)NetRxPackets[0], (void *)(SRAM_BASE(seg) + frameno * 1560), len);
/* pass to barebox */
net_receive(NetRxPackets[0], len);
PFIFO_REG(PFIFO_BASE(EMPTY_PTR_FIFO(xcno))) =
FIFO_PTR_SEGMENT(seg) |
FIFO_PTR_FRAMENO(frameno);
return 0;
}
static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
{
int value;
MIIMU_REG = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_addr) |
MIIMU_REGADDR(reg) | MIIMU_PHY_NRES;
while(MIIMU_REG & MIIMU_SNRDY);
value = MIIMU_REG >> 16;
debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n", __func__,
addr, reg, value);
return value;
}
static int netx_miidev_write(struct mii_device *mdev, int phy_addr,
int reg, int val)
{
debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__func__,
addr, reg, val);
MIIMU_REG = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_addr) |
MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE |
MIIMU_DATA(val);
while(MIIMU_REG & MIIMU_SNRDY);
return 0;
}
static int netx_eth_init_phy(void)
{
unsigned int phy_control;
phy_control = PHY_CONTROL_PHY_ADDRESS(0xe) |
PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) |
PHY_CONTROL_PHY1_AUTOMDIX |
PHY_CONTROL_PHY1_EN |
PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) |
PHY_CONTROL_PHY0_AUTOMDIX |
PHY_CONTROL_PHY0_EN |
PHY_CONTROL_CLK_XLATIN;
/* enable asic control */
SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY) = SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY);
SYSTEM_REG(SYSTEM_PHY_CONTROL) = phy_control | PHY_CONTROL_RESET;
udelay(100);
/* enable asic control */
SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY) = SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY);
SYSTEM_REG(SYSTEM_PHY_CONTROL) = phy_control;
return 0;
}
static int netx_eth_init_dev(struct eth_device *edev)
{
struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
int xcno = priv->xcno;
int i;
loadxc(xcno);
/* Fill empty pointer fifo */
for (i = 2; i <= 18; i++)
PFIFO_REG( PFIFO_BASE(EMPTY_PTR_FIFO(xcno)) ) = FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(xcno);
miidev_restart_aneg(&priv->miidev);
return 0;
}
static int netx_eth_open(struct eth_device *edev)
{
return 0;
}
static void netx_eth_halt (struct eth_device *edev)
{
}
static int netx_eth_get_ethaddr(struct eth_device *edev, unsigned char *adr)
{
/* FIXME: get from crypto flash */
return -1;
}
static int netx_eth_set_ethaddr(struct eth_device *edev, unsigned char *adr)
{
struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
int xcno = priv->xcno;
debug("%s\n", __func__);
/* set MAC address */
XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = RPU_HOLD_PC;
XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = TPU_HOLD_PC;
XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = XPU_HOLD_PC;
XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_4321) = adr[0] | adr[1]<<8 | adr[2]<<16 | adr[3]<<24;
XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_65) = adr[4] | adr[5]<<8;
XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_LOCAL_CONFIG) = MAC_TRAFFIC_CLASS_ARRANGEMENT(8);
XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = 0;
XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = 0;
XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = 0;
#if 0
for (i = 0; i < 5; i++)
printf ("%02x:", adr[i]);
printf ("%02x\n", adr[5]);
#endif
return -0;
}
static int netx_eth_probe(struct device_d *dev)
{
struct eth_device *edev;
struct netx_eth_priv *priv;
struct netx_eth_platform_data *pdata;
debug("netx_eth_probe()\n");
pdata = dev->platform_data;
edev = xzalloc(sizeof(struct eth_device) + sizeof(struct netx_eth_priv));
dev->type_data = edev;
edev->priv = (struct netx_priv *)(edev + 1);
priv = edev->priv;
priv->xcno = pdata->xcno;
edev->init = netx_eth_init_dev;
edev->open = netx_eth_open;
edev->send = netx_eth_send;
edev->recv = netx_eth_rx;
edev->halt = netx_eth_halt;
edev->get_ethaddr = netx_eth_get_ethaddr;
edev->set_ethaddr = netx_eth_set_ethaddr;
priv->miidev.read = netx_miidev_read;
priv->miidev.write = netx_miidev_write;
priv->miidev.address = 0;
priv->miidev.flags = 0;
netx_eth_init_phy();
mii_register(&priv->miidev);
eth_register(edev);
return 0;
}
static struct driver_d netx_eth_driver = {
.name = "netx-eth",
.probe = netx_eth_probe,
};
static int netx_eth_init(void)
{
register_driver(&netx_eth_driver);
return 0;
}
device_initcall(netx_eth_init);