288 lines
7.9 KiB
C
288 lines
7.9 KiB
C
#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 <miidev.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", __FUNCTION__,
|
|
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",__FUNCTION__,
|
|
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", __FUNCTION__);
|
|
|
|
/* 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);
|
|
|