summaryrefslogtreecommitdiffstats
path: root/drivers/net/netx_eth.c
diff options
context:
space:
mode:
authorSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-09-05 12:53:50 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-09-05 12:53:50 +0200
commit4b72bf8449c6628d52b05ec7bdc5113e04e36765 (patch)
treeedbcb099c5b140ef01d5a72e6d2b8bbdd5fcf6c0 /drivers/net/netx_eth.c
parent6ef87e89d509e683fbcd0c6cad60554bb9087f8e (diff)
downloadbarebox-4b72bf8449c6628d52b05ec7bdc5113e04e36765.tar.gz
barebox-4b72bf8449c6628d52b05ec7bdc5113e04e36765.tar.xz
add hilscher netx ethernet driver
Diffstat (limited to 'drivers/net/netx_eth.c')
-rw-r--r--drivers/net/netx_eth.c288
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);
+