[U-Boot] [patch V3] [2/3] ip3912 network driver
Jürgen Schöw
juergen at Schoew.net
Sun Jan 4 22:56:16 CET 2009
drivers/net/Makefile | 1 +
drivers/net/ip3912.c | 659 ++++++++++++++++++++++++++++++++++++
drivers/net/ip3912.h | 174 ++++++++++
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 631336a..7c82880 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -69,6 +69,7 @@ COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o
COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
+COBJS-$(CONFIG_IP3912_ETHER) += ip3912.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/net/ip3912.c b/drivers/net/ip3912.c
new file mode 100644
index 0000000..399f0b7
--- /dev/null
+++ b/drivers/net/ip3912.c
@@ -0,0 +1,659 @@
+/*
+ * ip3912 ethernet driver (PNX8181 / firetux)
+ *
+ * (C) Copyright 2007-2009, emlix GmbH, Germany
+ * Juergen Schoew <js at emlix.com>
+ *
+ * (C) Copyright 2008, DSPG Technologies GmbH, Germany
+ * (C) Copyright 2007, NXP Semiconductors Germany GmbH
+ * Matthias Wenzel, <nxp at mazzoo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+
+#include <asm/io.h>
+
+#include "ip3912.h"
+#include <miiphy.h>
+
+#define ALIGN8 __attribute__ ((aligned(8)))
+#define ALIGN4 __attribute__ ((aligned(4)))
+
+/* globals */
+/* ETN rx */
+ALIGN8 rx_descriptor_t etn_rxdescriptor[CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER];
+ALIGN8 rx_status_t etn_rxstatus[CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER];
+
+/* ETN tx */
+ALIGN8 tx_descriptor_t etn_txdescriptor[CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER];
+ALIGN4 tx_status_t etn_txstatus[CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER];
+
+struct ip3912_device {
+ unsigned int etn_base;
+ unsigned int phy_base;
+ unsigned char nr;
+ unsigned char phy_addr;
+ unsigned char autonegotiate;
+ unsigned char speed;
+ unsigned char duplex;
+ unsigned char rmii;
+
+ const struct device *dev;
+ struct eth_device *netdev;
+};
+
+int ip3912_miiphy_write(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ int status = 1;
+ int i = 0;
+ struct eth_device *netdev;
+ struct ip3912_device *ip3912;
+
+ netdev = eth_get_dev();
+ ip3912 = netdev->priv;
+
+ reg &= 0x001f; /* 5 bit PHY register address */
+
+ writel(PHYADDR_TO_REG(addr) | reg, (void *)(ip3912->phy_base
+ + ETN_MADR));
+ writel(value, (void *)(ip3912->phy_base + ETN_MWTD));
+
+ /* poll for done, max 100ms */
+ while (status && i < 100000) {
+ status = readl((void *)(ip3912->phy_base + ETN_MIND)) & 0x7;
+ udelay(1);
+ i++;
+ }
+
+ if (status) {
+ printf("ERROR: ip3912_miiphy_write(%d) = "
+ "0x%x [phy_addr=%x]\n", reg, status, addr);
+ return -1;
+ } else {
+ debug("### ip3912_miiphy_write(%2.d, 0x%4.4x) success after"
+ " %d cycles [phy_addr=%x]###\n", reg, value, i, addr);
+ }
+
+ return 0;
+}
+
+int ip3912_miiphy_read(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ int i = 0, status = 1;
+ struct eth_device *netdev;
+ struct ip3912_device *ip3912;
+
+ netdev = eth_get_dev();
+ ip3912 = netdev->priv;
+
+ reg &= 0x001f; /* 5 bit PHY register address */
+ writel(PHYADDR_TO_REG(addr) | reg, (void *)(ip3912->phy_base
+ + ETN_MADR));
+ writel(0x00000001, (void *)(ip3912->phy_base + ETN_MCMD));
+
+ /* poll for done, max 100ms */
+ while (status && i < 100000) {
+ status = readl((void *)(ip3912->phy_base + ETN_MIND)) & 0x7;
+ udelay(1);
+ i++;
+ }
+
+ *value = (unsigned short)readl((void *)(ip3912->phy_base + ETN_MRDD));
+
+ writel(0, (void *)(ip3912->phy_base + ETN_MCMD)); /* stop MII */
+
+ if (status) {
+ printf("ERROR: ip3912_miiphy_read(%d) = 0x%x after %d cycles "
+ "[phy_addr=%x]\n", reg, *value, i, ip3912->phy_addr);
+ return -1;
+ } else {
+ debug("### ip3912_phy_read(%2.d)=0x%4.4x success after %d "
+ "cycles [phy_addr=%x]###\n",
+ reg, *value, i, ip3912->phy_addr);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+int ip3912_mii_negotiate_phy(void)
+{
+ char *mode;
+ int i;
+ unsigned short value;
+ struct eth_device *netdev;
+ struct ip3912_device *ip3912;
+
+ netdev = eth_get_dev();
+ ip3912 = netdev->priv;
+
+ /* only set phy if exists */
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
+ PHY_PHYIDR1, &value);
+ if (value == 0xffff)
+ return -1;
+
+ /* get mode from environment */
+ mode = getenv("phymode");
+ if (mode != NULL) {
+ if (0 == strcmp(mode, "auto")) {
+ ip3912->autonegotiate = 1;
+ ip3912->speed = 100;
+ ip3912->duplex = 1;
+ } else {
+ if (0 == strcmp(mode, "100FD")) {
+ ip3912->speed = 100;
+ ip3912->duplex = 1;
+ }
+ if (0 == strcmp(mode, "100HD")) {
+ ip3912->speed = 100;
+ ip3912->duplex = 0;
+ }
+ if (0 == strcmp(mode, "10FD")) {
+ ip3912->speed = 10;
+ ip3912->duplex = 1;
+ }
+ if (0 == strcmp(mode, "10HD")) {
+ ip3912->speed = 10;
+ ip3912->duplex = 0;
+ }
+ ip3912->autonegotiate = 0;
+ }
+ } else {
+ /* we use 10Mbit FD as fallback */
+ ip3912->autonegotiate = 0;
+ ip3912->speed = 10;
+ ip3912->duplex = 1;
+ }
+
+ /* do autonegotiation */
+ if (ip3912->autonegotiate) {
+ /* 10/100 and FD/HD mode supported, ieee802.3 */
+ ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
+ ETN_PHY_AUTONEG_ADV, ((0xf << 5) | 1));
+ /* force autorenegotiation */
+ ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
+ ETN_PHY_BASIC_CONTROL, ((1 << 13) | (1 << 12) |
+ (1 << 9) | (1 << 8)));
+ } else {
+ /* only advertise the selected mode */
+ i = 0x1e0;
+ if (ip3912->speed == 100)
+ i &= 0x180;
+ else
+ i &= 0x060;
+ if (ip3912->duplex)
+ i &= 0x140;
+ else
+ i &= 0x0a0;
+ /* set advertise mode */
+ ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
+ ETN_PHY_AUTONEG_ADV, (i|1));
+ /* we set the phy parameter */
+ ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
+ ETN_PHY_BASIC_CONTROL, ((ip3912->duplex ? (1<<8) : 0)
+ | (1 << 9) | ((ip3912->speed == 100) ? (1 << 13) : 0)));
+ }
+
+ /* wait for negotiation finished (max 3.5s) */
+ i = 0;
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr, ETN_PHY_BASIC_STATUS,
+ &value);
+ while (((value & (1 << 5)) == 0) && (i < 350)) {
+ udelay(10000);
+ i++;
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
+ ETN_PHY_BASIC_STATUS, &value);
+ }
+ if (i == 350)
+ puts("link negotiation timed out\n");
+
+
+ /* check for link */
+ if (value & (1 << 2)) {
+ /* OK link present */
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
+ ETN_PHY_SPECIAL_MODE_CONTROL_STATUS, &value);
+ ip3912->speed = (value & (1 << 2)) ? 10 : 100;
+ ip3912->duplex = (value & (1 << 4)) ? 1 : 0;
+ }
+
+ /* program the mac */
+ writel((readl((void *)(ip3912->etn_base + ETN_SUPP)) & 0x000018fb) |
+ ((ip3912->speed == 100) ? (1 << 8) : 0),
+ (void *)(ip3912->etn_base + ETN_SUPP));
+ writel((readl((void *)(ip3912->etn_base + ETN_MAC2)) & 0x000073fe) |
+ ip3912->duplex, (void *)(ip3912->etn_base + ETN_MAC2));
+ /*
+ * release rx-path, tx-path, host registers reset
+ * set Duplex, enable RMII, enable rx+tx
+ * no flow control, no frames<64b
+ */
+ writel(0x00000283 | (ip3912->duplex ? (1 << 10) : 0),
+ (void *)(ip3912->etn_base + ETN_COMMAND));
+
+ udelay(100000); /* the mac still needs some time to settle 100ms */
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
+ ETN_PHY_SPECIAL_MODE_CONTROL_STATUS, &value);
+ printf(" %s %s negotiation", netdev->name,
+ (value & (1 << 12)) ? "Auto" : "Manual");
+ printf(" (10%s Mbit", (value & (1 << 3)) ? "0" : "");
+ printf(" %sD", (value & (1 << 4)) ? "F" : "H");
+ ip3912_miiphy_read(netdev->name, ip3912->phy_addr, ETN_PHY_BASIC_STATUS,
+ &value);
+ printf(" (%s)\n", (value & 1<<2)
+ ? "Link detected" : "No Link detected, trying anyway");
+
+ return 0;
+}
+
+#if defined(CONFIG_DISCOVER_PHY)
+int mii_discover_phy(void)
+{
+ unsigned short id1, id2;
+ int phytype, phyno;
+ struct eth_device *netdev;
+ struct ip3912_device *ip3912;
+
+ netdev = eth_get_dev();
+ ip3912 = netdev->priv;
+
+ for (phyno = 0; phyno <= 31 ; ++phyno) {
+ ip3912_miiphy_read(netdev->name, phyno, PHY_PHYIDR1, &id1);
+ if (id1 != 0xffff) {
+ ip3912_miiphy_read(netdev->name, phyno, PHY_PHYIDR2,
+ &id2);
+ phytype = ((id1 << 16) | id2);
+ puts("Using Transceiver: ");
+ switch (phytype & 0xfffffff0) {
+ case PHY_ID_LXT970:
+ puts("LXT970");
+ break;
+ case PHY_ID_LXT971:
+ puts("LXT971");
+ break;
+ case PHY_ID_82555:
+ puts("82555");
+ break;
+ case PHY_ID_QS6612:
+ puts("QS6612");
+ break;
+ case PHY_ID_AMD79C784:
+ puts("AMD79C784");
+ break;
+ case PHY_ID_LSI80225:
+ puts("LSI L80225");
+ break;
+ case PHY_ID_LSI80225B:
+ puts("LSI L80225/B");
+ break;
+ case PHY_ID_DM9161:
+ puts("Davicom DM9161");
+ break;
+ case PHY_ID_KSM8995M:
+ puts("MICREL KS8995M");
+ break;
+ case PHY_ID_SMSC8700:
+ puts("SMSC Lan 8700");
+ break;
+ default:
+ printf("0x%08x", phytype);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_DISCOVER_PHY */
+
+#endif /* defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ip3912_miiphy_initialize(bd_t *bis)
+{
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register("ip3912", ip3912_miiphy_read, ip3912_miiphy_write);
+#endif
+ return 0;
+}
+
+static int ip3912_init_descriptors(struct eth_device *netdev)
+{
+ struct ip3912_device *ip3912;
+ static void *rxbuf;
+ int i;
+
+ ip3912 = netdev->priv;
+
+ /* fill in pointer in regs */
+ writel((unsigned long)etn_rxdescriptor, (void *)(ip3912->etn_base
+ + ETN_RXDESCRIPTOR));
+ writel((unsigned long)etn_rxstatus, (void *)(ip3912->etn_base
+ + ETN_RXSTATUS));
+ writel(0x00000000, (void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));
+ writel(CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER - 1,
+ (void *)(ip3912->etn_base
+ + ETN_RXDESCRIPTORNUMBER));
+
+ writel((unsigned long)etn_txdescriptor, (void *)(ip3912->etn_base
+ + ETN_TXDESCRIPTOR));
+ writel((unsigned long)etn_txstatus, (void *)(ip3912->etn_base
+ + ETN_TXSTATUS));
+ writel(0x00000000, (void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
+ writel(CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1,
+ (void *)(ip3912->etn_base + ETN_TXDESCRIPTORNUMBER));
+
+ /* allocate rx-buffers, but only once, we're called multiple times! */
+ if (!rxbuf)
+ rxbuf = malloc(MAX_ETH_FRAME_SIZE
+ * CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER);
+ if (!rxbuf) {
+ puts("ERROR: couldn't allocate rx buffers!\n");
+ return -1;
+ }
+
+ for (i = 0; i < CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER; i++) {
+ etn_rxdescriptor[i].packet = rxbuf + i * MAX_ETH_FRAME_SIZE;
+ etn_rxdescriptor[i].control = MAX_ETH_FRAME_SIZE
+ - sizeof(unsigned long);
+ etn_rxstatus[i].info = 0;
+ etn_rxstatus[i].hashCRC = 0;
+ }
+
+ for (i = 0; i < CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER; i++) {
+ etn_txdescriptor[i].packet = 0;
+ etn_txdescriptor[i].control = 0;
+ etn_txstatus[i].info = 0;
+ }
+ return 0;
+}
+
+void ip3912_setmac(struct eth_device *netdev)
+{
+ struct ip3912_device *ip3912;
+ unsigned char i, use_etn1addr = 0;
+ char *mac_string, *pmac, *end;
+ char tmp[18];
+
+ ip3912 = netdev->priv;
+
+ mac_string = getenv("ethaddr");
+
+ if (ip3912->nr) {
+ /* we use ETN2 */
+ mac_string = getenv("eth1addr");
+ if (!mac_string) {
+ mac_string = getenv("ethaddr");
+ use_etn1addr = 1;
+ }
+ }
+
+ pmac = mac_string;
+ for (i = 0; i < 6; i++) {
+ netdev->enetaddr[i] = pmac ? simple_strtoul(pmac, &end, 16) : 0;
+ if (pmac)
+ pmac = (*end) ? end + 1 : end;
+ }
+
+ if (use_etn1addr) {
+ /* flip last bit of mac address */
+ debug("ip3912_setmac %s flipping last bit\n", netdev->name);
+ if (netdev->enetaddr[5] & 1)
+ netdev->enetaddr[5] &= 0xfe;
+ else
+ netdev->enetaddr[5] |= 0x01;
+ sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X",
+ netdev->enetaddr[0], netdev->enetaddr[1],
+ netdev->enetaddr[2], netdev->enetaddr[3],
+ netdev->enetaddr[4], netdev->enetaddr[5]);
+ setenv("eth1addr", tmp);
+ mac_string = tmp;
+ }
+
+ debug("ip3912_setmac set %s to address %s\n", netdev->name, mac_string);
+
+ writel((netdev->enetaddr[5] << 8) | netdev->enetaddr[4],
+ (void *)(ip3912->etn_base + ETN_SA0));
+ writel((netdev->enetaddr[3] << 8) | netdev->enetaddr[2],
+ (void *)(ip3912->etn_base + ETN_SA1));
+ writel((netdev->enetaddr[1] << 8) | netdev->enetaddr[0],
+ (void *)(ip3912->etn_base + ETN_SA2));
+}
+
+int ip3912_macreset(void)
+{
+ struct eth_device *netdev;
+ struct ip3912_device *ip3912;
+
+ netdev = eth_get_dev();
+ ip3912 = netdev->priv;
+
+ debug("ip3912_macreset resetting %s\n", netdev->name);
+
+ /* reset MAC layer */
+ writel(0x0000cf00, (void *)(ip3912->etn_base + ETN_MAC1));
+ /* release MAC soft reset */
+ writel(0x00000000, (void *)(ip3912->etn_base + ETN_MAC1));
+ /* reset rx-path, tx-path, host registers */
+ writel(0x00000038, (void *)(ip3912->etn_base + ETN_COMMAND));
+ /* reset RMII, 100Mbps MAC, 10Mbps MAC */
+ writel(0x1888, (void *)(ip3912->etn_base + ETN_SUPP));
+ writel(0x1000, (void *)(ip3912->etn_base + ETN_SUPP));
+
+ return 0;
+}
+
+static int ip3912_init(struct eth_device *netdev, bd_t *bd)
+{
+ unsigned char i;
+ struct ip3912_device *ip3912 = netdev->priv;
+
+ /* update mac address in boardinfo */
+ ip3912_setmac(netdev);
+ for (i = 0; i < 6 ; i++)
+ bd->bi_enetaddr[i] = netdev->enetaddr[i];
+
+ /* before enabling the rx-path we need to set up rx-descriptors */
+ if (ip3912_init_descriptors(netdev))
+ return -1;
+
+ /* set max packet length to 1536 bytes */
+ writel(MAX_ETH_FRAME_SIZE, (void *)(ip3912->etn_base + ETN_MAXF));
+ /* full duplex */
+ writel(0x00000023, (void *)(ip3912->etn_base + ETN_MAC2));
+ /* inter packet gap register */
+ writel(0x15, (void *)(ip3912->etn_base + ETN_IPGT));
+ writel(0x12, (void *)(ip3912->etn_base + ETN_IPGR));
+ /* enable rx, receive all frames */
+ writel(0x00000003, (void *)(ip3912->etn_base + ETN_MAC1));
+ /* accept all multicast, broadcast and station packets */
+ writel(0x00000026, (void *)(ip3912->etn_base + ETN_RXFILTERCTRL));
+
+ /* reset MII mgmt, set MII clock */
+ writel(0x0000801c, (void *)(ip3912->etn_base + ETN_MCFG));
+ writel(0x0000001c, (void *)(ip3912->etn_base + ETN_MCFG));
+
+ /* release rx-path, tx-path, host registers reset
+ * set FullDuplex, enable RMMI, enable rx+tx
+ * no flow control, no frames<64b
+ */
+ writel(0x00000683, (void *)(ip3912->etn_base + ETN_COMMAND));
+ ip3912_init_descriptors(netdev);
+
+#ifdef CONFIG_DISCOVER_PHY
+ mii_discover_phy();
+#endif
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ /* check autonegotiation */
+ ip3912_mii_negotiate_phy();
+#endif
+ return 0;
+}
+
+/* Send a packet */
+static int ip3912_send(struct eth_device *netdev, volatile void *packet,
+ int length)
+{
+ struct ip3912_device *ip3912 = netdev->priv;
+ uint32_t next_packet;
+ uint32_t this_packet;
+ uint32_t last_packet;
+
+ if ((length > MAX_ETH_FRAME_SIZE) || (length <= 0)) {
+ printf("ERROR: cannot transmit a %d bytes frame!\n", length);
+ return -1;
+ }
+
+ this_packet = readl((void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
+ next_packet = (this_packet + 1) % CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER;
+ last_packet = readl((void *)(ip3912->etn_base + ETN_TXCONSUMEINDEX));
+
+#define ETN_TX_MAX_RETRY 1000000
+ int i = 0;
+ /* wait until the FIFO is ready to accept a new packet */
+
+ while ((this_packet == ((last_packet +
+ CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1)
+ % CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER))
+ && (i < ETN_TX_MAX_RETRY)) {
+#ifdef ET_DEBUG
+ /* debug print when FIFO full*/
+ if ((i > 50000) && (!(i % 50000))) {
+ this_packet =
+ readl((void *)(ip3912->etn_base
+ + ETN_TXPRODUCEINDEX));
+ last_packet =
+ readl((void *)(ip3912->etn_base
+ + ETN_TXCONSUMEINDEX));
+ printf("this=%3.d, last=%3.d, i=%d\n",
+ this_packet, last_packet, i);
+ }
+#endif
+ i++;
+ last_packet = readl((void *)(ip3912->etn_base
+ + ETN_TXCONSUMEINDEX));
+ }
+ if (i == ETN_TX_MAX_RETRY) {
+ printf("tx FAILED after %d cycles\n", i);
+ return -1;
+ }
+ if (i)
+ printf("tx after %d cycles\n", i);
+
+ etn_txdescriptor[this_packet].packet = packet;
+ etn_txdescriptor[this_packet].control = (length - 1) |
+ ETN_CONTROL_INTERRUPT | ETN_CONTROL_LAST;
+
+ /* let the HW know a new packet is ready */
+ writel(next_packet, (void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
+
+ return 0;
+}
+
+/* Check for received packets */
+static int ip3912_recv(struct eth_device *netdev)
+{
+ struct ip3912_device *ip3912 = netdev->priv;
+
+ unsigned short rxconsume = (unsigned short)
+ (readl((void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX)));
+ unsigned short rxproduce = (unsigned short)
+ (readl((void *)(ip3912->etn_base + ETN_RXPRODUCEINDEX)));
+ unsigned short psize = 0;
+
+ debug("eth_rx: receive_rsv 0x%08x\n",
+ readl((void *)(ip3912->etn_base + ETN_RSV)));
+ debug("eth_rx: consume 0x%04x produce 0x%04x\n",
+ rxconsume, rxproduce);
+ while (rxconsume != rxproduce) {
+ rxproduce = (unsigned short)(readl((void *)
+ (ip3912->etn_base + ETN_RXPRODUCEINDEX)));
+ psize = (etn_rxstatus[rxconsume].info & 0x07ff) + 1;
+ if (psize > MAX_ETH_FRAME_SIZE) {
+ printf("dropping %d bytes frame (too large)!\n",
+ psize);
+ } else {
+ NetReceive(etn_rxdescriptor[rxconsume].packet, psize);
+ }
+ rxconsume = (rxconsume + 1)
+ % CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER;
+ writel(rxconsume,
+ (void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));
+ }
+ return psize;
+}
+
+static void ip3912_halt(struct eth_device *netdev)
+{
+ struct ip3912_device *ip3912 = netdev->priv;
+
+ /* disable rx-path, tx-path, host registers reset
+ * set FullDuplex, enable RMMI, disable rx+tx
+ * no flow control, no frames<64b
+ */
+ writel(0x000006b8, (void *)(ip3912->etn_base + ETN_COMMAND));
+}
+
+int ip3912_eth_initialize(unsigned char nr, unsigned int etn_base,
+ unsigned int phy_base, unsigned char phy_addr, unsigned char rmii)
+{
+ struct ip3912_device *ip3912;
+ struct eth_device *netdev;
+
+ netdev = malloc(sizeof(struct eth_device));
+ ip3912 = malloc(sizeof(struct ip3912_device));
+ if ((!ip3912) || (!netdev)) {
+ printf("Error: Failed to allocate memory for ETN%d\n", nr + 1);
+ return -1;
+ }
+
+ memset(ip3912, 0, sizeof(struct ip3912_device));
+ memset(netdev, 0, sizeof(struct eth_device));
+
+ ip3912->nr = nr;
+ ip3912->etn_base = etn_base;
+ ip3912->phy_base = phy_base;
+ ip3912->phy_addr = phy_addr;
+ ip3912->autonegotiate = 0;
+ ip3912->rmii = rmii;
+ ip3912->speed = 0;
+ ip3912->duplex = 0;
+ ip3912->netdev = netdev;
+
+ sprintf(netdev->name, "ETN%d", nr + 1);
+ netdev->init = ip3912_init;
+ netdev->send = ip3912_send;
+ netdev->recv = ip3912_recv;
+ netdev->halt = ip3912_halt;
+ netdev->priv = (void *)ip3912;
+
+
+ eth_register(netdev);
+ ip3912_macreset();
+ /* we have to set the mac address, because we have no SROM */
+ ip3912_setmac(netdev);
+
+ return 0;
+}
diff --git a/drivers/net/ip3912.h b/drivers/net/ip3912.h
new file mode 100644
index 0000000..f6343a0
--- /dev/null
+++ b/drivers/net/ip3912.h
@@ -0,0 +1,174 @@
+/*
+ * ip3912 ethernet driver interface (PNX8181 / firetux)
+ *
+ * (C) Copyright 2007-2009, emlix GmbH, Germany
+ * Juergen Schoew <js at emlix.com>
+ *
+ * (C) Copyright 2008, DSPG Technologies GmbH, Germany
+ * (C) Copyright 2007, NXP Semiconductors Germany GmbH
+ * Matthias Wenzel, <nxp at mazzoo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* exported ethernet functions */
+int mii_discover_phy(void);
+
+#define PHYADDR_TO_REG(x) (x << 8)
+
+/* data types */
+
+/* rx */
+typedef struct{
+ volatile void *packet;
+ volatile unsigned long control;
+} rx_descriptor_t;
+
+typedef struct{
+ volatile unsigned long info; /* RO */
+ volatile unsigned long hashCRC; /* RO */
+} rx_status_t;
+
+/* tx */
+typedef struct{
+ volatile void *packet;
+ volatile unsigned long control;
+} tx_descriptor_t;
+
+typedef struct{
+ volatile unsigned long info; /* RO */
+} tx_status_t;
+
+/* NXP's OUI registered @ IEEE */
+#define NXP_ETN_OUI 0x006037
+
+/* ip3912 ETN registers */
+#define ETN1_BASE CONFIG_IP3912_ETN1_BASE
+#define ETN2_BASE CONFIG_IP3912_ETN2_BASE
+
+/* offsets to base address */
+#define ETN_MAC1 0x0000
+#define ETN_MAC2 0x0004
+#define ETN_IPGT 0x0008
+#define ETN_IPGR 0x000c
+#define ETN_CLRT 0x0010
+#define ETN_MAXF 0x0014
+#define ETN_SUPP 0x0018
+#define ETN_TEST 0x001c
+#define ETN_MCFG 0x0020
+#define ETN_MCMD 0x0024
+#define ETN_MADR 0x0028
+#define ETN_MWTD 0x002c
+#define ETN_MRDD 0x0030
+#define ETN_MIND 0x0034
+#define ETN_SA0 0x0040
+#define ETN_SA1 0x0044
+#define ETN_SA2 0x0048
+#define ETN_COMMAND 0x0100
+#define ETN_STATUS 0x0104
+#define ETN_RXDESCRIPTOR 0x0108
+#define ETN_RXSTATUS 0x010c
+#define ETN_RXDESCRIPTORNUMBER 0x0110
+#define ETN_RXPRODUCEINDEX 0x0114
+#define ETN_RXCONSUMEINDEX 0x0118
+#define ETN_TXDESCRIPTOR 0x011c
+#define ETN_TXSTATUS 0x0120
+#define ETN_TXDESCRIPTORNUMBER 0x0124
+#define ETN_TXPRODUCEINDEX 0x0128
+#define ETN_TXCONSUMEINDEX 0x012c
+#define ETN_TXRTDESCRIPTOR 0x0130
+#define ETN_TXRTSTATUS 0x0134
+#define ETN_TXRTDESCRIPTORNUMBER 0x0138
+#define ETN_TXRTPRODUCEINDEX 0x013c
+#define ETN_TXRTCONSUMEINDEX 0x0140
+#define ETN_QOSTIMEOUT 0x0148
+#define ETN_TSV0 0x0158
+#define ETN_TSV1 0x015c
+#define ETN_RSV 0x0160
+#define ETN_FLOWCONTROLCOUNTER 0x0170
+#define ETN_FLOWCONTROLSTATUS 0x0174
+#define ETN_RXFILTERCTRL 0x0200
+#define ETN_RXFILTERWOLSTATUS 0x0204
+#define ETN_RXFILTERWOLCLEAR 0x0208
+#define ETN_HASHFILTERL 0x0210
+#define ETN_HASHFILTERH 0x0214
+#define ETN_INTSTATUS 0x0fe0
+#define ETN_INTENABLE 0x0fe4
+#define ETN_INTCLEAR 0x0fe8
+#define ETN_INTSET 0x0fec
+#define ETN_POWERDOWN 0x0ff4
+#define ETN_MODULEID 0x0ffc
+
+/* values for control */
+#define ETN_CONTROL_INTERRUPT 0x80000000
+#define ETN_CONTROL_LAST 0x40000000
+#define ETN_CONTROL_CRC 0x20000000
+#define ETN_CONTROL_PAD 0x10000000
+#define ETN_CONTROL_HUGE 0x08000000
+#define ETN_CONTROL_OVERRIDE 0x04000000
+
+/* registers in the SMSC LAN8700 PHY */
+/*
+00 Basic Control Register Basic
+01 Basic Status Register Basic
+02 PHY Identifier 1 Extended
+03 PHY Identifier 2 Extended
+04 Auto-Negotiation Advertisement Register Extended
+05 Auto-Negotiation Link Partner Ability Register Extended
+06 Auto-Negotiation Expansion Register Extended
+16 Silicon Revision Register Vendor-specific
+17 Mode Control/Status Register Vendor-specific
+18 Special Modes Vendor-specific
+20 Reserved Vendor-specific
+21 Reserved Vendor-specific
+22 Reserved Vendor-specific
+23 Reserved Vendor-specific
+27 Control / Status Indication Register Vendor-specific
+28 Special internal testability controls Vendor-specific
+29 Interrupt Source Register Vendor-specific
+30 Interrupt Mask Register Vendor-specific
+31 PHY Special Control/Status Register Vendor-specific
+*/
+#define ETN_PHY_BASIC_CONTROL 0x00
+#define ETN_PHY_BASIC_STATUS 0x01
+#define ETN_PHY_ID1 0x02
+#define ETN_PHY_ID2 0x03
+#define ETN_PHY_AUTONEG_ADV 0x04
+#define ETN_PHY_AUTONEG_LINK 0x05
+#define ETN_PHY_AUTONEG_EXP 0x06
+#define ETN_PHY_SILICON 0x10
+#define ETN_PHY_MODE_CONTROL_STATUS 0x11
+#define ETN_PHY_SPECIAL_MODES 0x12
+#define ETN_PHY_CONTROL_STATUS_INDICATION 0x1b
+#define ETN_PHY_INTERNAL_TESTABILITY 0x1c
+#define ETN_PHY_INTERRUPT_SOURCE 0x1d
+#define ETN_PHY_INTERRUPT_MASK 0x1e
+#define ETN_PHY_SPECIAL_MODE_CONTROL_STATUS 0x1f
+
+/* PHY identification */
+#define PHY_ID_LXT970 0x78100000 /* LXT970 */
+#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */
+#define PHY_ID_82555 0x02a80150 /* Intel 82555 */
+#define PHY_ID_QS6612 0x01814400 /* QS6612 */
+#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */
+#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */
+#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */
+#define PHY_ID_DM9161 0x0181B880 /* Davicom DM9161 */
+#define PHY_ID_KSM8995M 0x00221450 /* MICREL KS8995MA */
+#define PHY_ID_SMSC8700 0x0007C0C0 /* SMSC LAN 8700 */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
Url : http://lists.denx.de/pipermail/u-boot/attachments/20090104/f3d5d232/attachment-0001.pgp
More information about the U-Boot
mailing list