diff options
Diffstat (limited to 'drivers/net/netx_eth.c')
-rw-r--r-- | drivers/net/netx_eth.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c new file mode 100644 index 0000000000..5139bdbeec --- /dev/null +++ b/drivers/net/netx_eth.c @@ -0,0 +1,288 @@ +#include <common.h> +#include <command.h> +#include <net.h> +#include <asm/io.h> +#include <miiphy.h> +#include <asm/arch/netx-xc.h> +#include <asm/arch/netx-eth.h> +#include <asm/arch/netx-regs.h> +#include <xfuncs.h> +#include <miiphy.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 ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#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 miiphy_device miiphy; + 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 u-boot */ + NetReceive(NetRxPackets[0], len); + + PFIFO_REG(PFIFO_BASE(EMPTY_PTR_FIFO(xcno))) = + FIFO_PTR_SEGMENT(seg) | + FIFO_PTR_FRAMENO(frameno); + return 0; +} + +static int netx_miiphy_read(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t reg, uint16_t * val) +{ + MIIMU_REG = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_addr) | + MIIMU_REGADDR(reg) | MIIMU_PHY_NRES; + + while(MIIMU_REG & MIIMU_SNRDY); + + *val = MIIMU_REG >> 16; + +/* printf("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__FUNCTION__,addr,reg,*value); */ + + return 0; +} + +static int netx_miiphy_write(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t reg, uint16_t val) +{ +/* printf("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__FUNCTION__,addr,reg,value); */ + + 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); + + miiphy_restart_aneg(&priv->miiphy); + 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_mac_address(struct eth_device *edev, unsigned char *adr) +{ + /* FIXME: get from crypto flash */ + return -1; +} + +static int netx_eth_set_mac_address(struct eth_device *edev, unsigned char *adr) +{ + struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv; + int xcno = priv->xcno; + + debug("netx_eth_set_mac_address\n"); + + /* 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->dev = dev; + 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_mac_address = netx_eth_get_mac_address; + edev->set_mac_address = netx_eth_set_mac_address; + + priv->miiphy.read = netx_miiphy_read; + priv->miiphy.write = netx_miiphy_write; + priv->miiphy.address = 0; + priv->miiphy.flags = 0; + + netx_eth_init_phy(); + miiphy_register(&priv->miiphy); + eth_register(edev); + + return 0; +} + +static struct driver_d netx_eth_driver = { + .name = "netx-eth", + .probe = netx_eth_probe, + .type = DEVICE_TYPE_ETHER, +}; + +static int netx_eth_init(void) +{ + register_driver(&netx_eth_driver); + return 0; +} + +device_initcall(netx_eth_init); + |