diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Makefile | 7 | ||||
-rw-r--r-- | drivers/net/ax88180.c | 727 | ||||
-rw-r--r-- | drivers/net/ax88180.h | 412 | ||||
-rw-r--r-- | drivers/net/ax88796.c | 2 | ||||
-rw-r--r-- | drivers/net/ne2000.c | 719 | ||||
-rw-r--r-- | drivers/net/ne2000_base.c | 757 | ||||
-rw-r--r-- | drivers/net/ne2000_base.h | 36 | ||||
-rw-r--r-- | drivers/net/tsec.c | 2 |
8 files changed, 1939 insertions, 723 deletions
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a084000..439c354 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o @@ -44,10 +45,8 @@ COBJS-$(CONFIG_MCFFEC) += mcffec.o COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o COBJS-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o COBJS-$(CONFIG_NATSEMI) += natsemi.o -ifeq ($(CONFIG_DRIVER_NE2000),y) -COBJS-y += ne2000.o -COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o -endif +COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o +COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o COBJS-$(CONFIG_DRIVER_NETARMETH) += netarm_eth.o COBJS-$(CONFIG_NETCONSOLE) += netconsole.o COBJS-$(CONFIG_DRIVER_NS7520_ETHERNET) += ns7520_eth.o diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c new file mode 100644 index 0000000..d843397 --- /dev/null +++ b/drivers/net/ax88180.c @@ -0,0 +1,727 @@ +/* + * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * This program is distributed in the hope 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. + */ + +/* + * ======================================================================== + * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver + * + * The AX88180 Ethernet controller is a high performance and highly + * integrated local CPU bus Ethernet controller with embedded 40K bytes + * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any + * embedded systems. + * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet + * controller that supports both MII and RGMII interfaces and is + * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards. + * + * Please visit ASIX's web site (http://www.asix.com.tw) for more + * details. + * + * Module Name : ax88180.c + * Date : 2008-07-07 + * History + * 09/06/2006 : New release for AX88180 US2 chip. + * 07/07/2008 : Fix up the coding style and using inline functions + * instead of macros + * ======================================================================== + */ +#include <common.h> +#include <command.h> +#include <net.h> +#include <malloc.h> +#include "ax88180.h" + +/* + * =========================================================================== + * Local SubProgram Declaration + * =========================================================================== + */ +static void ax88180_rx_handler (struct eth_device *dev); +static int ax88180_phy_initial (struct eth_device *dev); +static void ax88180_meidia_config (struct eth_device *dev); +static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev); +static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev); +static unsigned short ax88180_mdio_read (struct eth_device *dev, + unsigned long regaddr); +static void ax88180_mdio_write (struct eth_device *dev, + unsigned long regaddr, unsigned short regdata); + +/* + * =========================================================================== + * Local SubProgram Bodies + * =========================================================================== + */ +static int ax88180_mdio_check_complete (struct eth_device *dev) +{ + int us_cnt = 10000; + unsigned short tmpval; + + /* MDIO read/write should not take more than 10 ms */ + while (--us_cnt) { + tmpval = INW (dev, MDIOCTRL); + if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0)) + break; + } + + return us_cnt; +} + +static unsigned short +ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmpval = 0; + + OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL); + + if (ax88180_mdio_check_complete (dev)) + tmpval = INW (dev, MDIODP); + else + printf ("Failed to read PHY register!\n"); + + return (unsigned short)(tmpval & 0xFFFF); +} + +static void +ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr, + unsigned short regdata) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + + OUTW (dev, regdata, MDIODP); + + OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL); + + if (!ax88180_mdio_check_complete (dev)) + printf ("Failed to write PHY register!\n"); +} + +static int ax88180_phy_reset (struct eth_device *dev) +{ + unsigned short delay_cnt = 500; + + ax88180_mdio_write (dev, BMCR, (PHY_RESET | AUTONEG_EN)); + + /* Wait for the reset to complete, or time out (500 ms) */ + while (ax88180_mdio_read (dev, BMCR) & PHY_RESET) { + udelay (1000); + if (--delay_cnt == 0) { + printf ("Failed to reset PHY!\n"); + return -1; + } + } + + return 0; +} + +static void ax88180_mac_reset (struct eth_device *dev) +{ + unsigned long tmpval; + unsigned char i; + + struct { + unsigned short offset, value; + } program_seq[] = { + { + MISC, MISC_NORMAL}, { + RXINDICATOR, DEFAULT_RXINDICATOR}, { + TXCMD, DEFAULT_TXCMD}, { + TXBS, DEFAULT_TXBS}, { + TXDES0, DEFAULT_TXDES0}, { + TXDES1, DEFAULT_TXDES1}, { + TXDES2, DEFAULT_TXDES2}, { + TXDES3, DEFAULT_TXDES3}, { + TXCFG, DEFAULT_TXCFG}, { + MACCFG2, DEFAULT_MACCFG2}, { + MACCFG3, DEFAULT_MACCFG3}, { + TXLEN, DEFAULT_TXLEN}, { + RXBTHD0, DEFAULT_RXBTHD0}, { + RXBTHD1, DEFAULT_RXBTHD1}, { + RXFULTHD, DEFAULT_RXFULTHD}, { + DOGTHD0, DEFAULT_DOGTHD0}, { + DOGTHD1, DEFAULT_DOGTHD1},}; + + OUTW (dev, MISC_RESET_MAC, MISC); + tmpval = INW (dev, MISC); + + for (i = 0; i < (sizeof (program_seq) / sizeof (program_seq[0])); i++) + OUTW (dev, program_seq[i].value, program_seq[i].offset); +} + +static int ax88180_poll_tx_complete (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmpval, txbs_txdp; + int TimeOutCnt = 10000; + + txbs_txdp = 1 << priv->NextTxDesc; + + while (TimeOutCnt--) { + + tmpval = INW (dev, TXBS); + + if ((tmpval & txbs_txdp) == 0) + break; + + udelay (100); + } + + if (TimeOutCnt) + return 0; + else + return -TimeOutCnt; +} + +static void ax88180_rx_handler (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long data_size; + unsigned short rxcurt_ptr, rxbound_ptr, next_ptr; + int i; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + unsigned short *rxdata = (unsigned short *)NetRxPackets[0]; +#else + unsigned long *rxdata = (unsigned long *)NetRxPackets[0]; +#endif + unsigned short count; + + rxcurt_ptr = INW (dev, RXCURT); + rxbound_ptr = INW (dev, RXBOUND); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + debug ("ax88180: RX original RXBOUND=0x%04x," + " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + + while (next_ptr != rxcurt_ptr) { + + OUTW (dev, RX_START_READ, RXINDICATOR); + + data_size = READ_RXBUF (dev) & 0xFFFF; + + if ((data_size == 0) || (data_size > MAX_RX_SIZE)) { + + OUTW (dev, RX_STOP_READ, RXINDICATOR); + + ax88180_mac_reset (dev); + printf ("ax88180: Invalid Rx packet length!" + " (len=0x%04lx)\n", data_size); + + debug ("ax88180: RX RXBOUND=0x%04x," + "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + return; + } + + rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1; + rxbound_ptr &= RX_PAGE_NUM_MASK; + + /* Comput access times */ + count = (data_size + priv->PadSize) >> priv->BusWidth; + + for (i = 0; i < count; i++) { + *(rxdata + i) = READ_RXBUF (dev); + } + + OUTW (dev, RX_STOP_READ, RXINDICATOR); + + /* Pass the packet up to the protocol layers. */ + NetReceive (NetRxPackets[0], data_size); + + OUTW (dev, rxbound_ptr, RXBOUND); + + rxcurt_ptr = INW (dev, RXCURT); + rxbound_ptr = INW (dev, RXBOUND); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + debug ("ax88180: RX updated RXBOUND=0x%04x," + "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + } + + return; +} + +static int ax88180_phy_initial (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmp_regval; + + /* Check avaliable PHY chipset */ + priv->PhyAddr = MARVELL_88E1111_PHYADDR; + priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0); + + if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) { + + debug ("ax88180: Found Marvell 88E1111 PHY." + " (PHY Addr=0x%x)\n", priv->PhyAddr); + + tmp_regval = ax88180_mdio_read (dev, M88_EXT_SSR); + if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) { + + ax88180_mdio_write (dev, M88_EXT_SCR, DEFAULT_EXT_SCR); + if (ax88180_phy_reset (dev) < 0) + return 0; + ax88180_mdio_write (dev, M88_IER, LINK_CHANGE_INT); + } + } else { + + priv->PhyAddr = CICADA_CIS8201_PHYADDR; + priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0); + + if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) { + + debug ("ax88180: Found CICADA CIS8201 PHY" + " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr); + ax88180_mdio_write (dev, CIS_IMR, + (CIS_INT_ENABLE | LINK_CHANGE_INT)); + + /* Set CIS_SMI_PRIORITY bit before force the media mode */ + tmp_regval = + ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS); + tmp_regval &= ~CIS_SMI_PRIORITY; + ax88180_mdio_write (dev, CIS_AUX_CTRL_STATUS, + tmp_regval); + } else { + printf ("ax88180: Unknown PHY chipset!!\n"); + return 0; + } + } + + return 1; +} + +static void ax88180_meidia_config (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long bmcr_val, bmsr_val; + unsigned long rxcfg_val, maccfg0_val, maccfg1_val; + unsigned long RealMediaMode; + int i; + + /* Waiting 2 seconds for PHY link stable */ + for (i = 0; i < 20000; i++) { + bmsr_val = ax88180_mdio_read (dev, BMSR); + if (bmsr_val & LINKOK) { + break; + } + udelay (100); + } + + bmsr_val = ax88180_mdio_read (dev, BMSR); + debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val); + + if (bmsr_val & LINKOK) { + bmcr_val = ax88180_mdio_read (dev, BMCR); + + if (bmcr_val & AUTONEG_EN) { + + /* + * Waiting for Auto-negotiation completion, this may + * take up to 5 seconds. + */ + debug ("ax88180: Auto-negotiation is " + "enabled. Waiting for NWay completion..\n"); + for (i = 0; i < 50000; i++) { + bmsr_val = ax88180_mdio_read (dev, BMSR); + if (bmsr_val & AUTONEG_COMPLETE) { + break; + } + udelay (100); + } + } else + debug ("ax88180: Auto-negotiation is disabled.\n"); + + debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n", + (unsigned int)bmcr_val, (unsigned int)bmsr_val); + + /* Get real media mode here */ + if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) { + RealMediaMode = get_MarvellPHY_meida_mode (dev); + } else if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) { + RealMediaMode = get_CicadaPHY_meida_mode (dev); + } else { + RealMediaMode = MEDIA_1000FULL; + } + + priv->LinkState = INS_LINK_UP; + + switch (RealMediaMode) { + case MEDIA_1000FULL: + debug ("ax88180: 1000Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | RXFLOW_EN | + FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_1000HALF: + debug ("ax88180: 1000Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1; + break; + + case MEDIA_100FULL: + debug ("ax88180: 100Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = SPEED100 | TXFLOW_ENABLE + | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_100HALF: + debug ("ax88180: 100Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = SPEED100 | DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + + case MEDIA_10FULL: + debug ("ax88180: 10Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_10HALF: + debug ("ax88180: 10Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + default: + debug ("ax88180: Unknow media mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + + priv->LinkState = INS_LINK_DOWN; + break; + } + + } else { + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + + priv->LinkState = INS_LINK_DOWN; + } + + OUTW (dev, rxcfg_val, RXCFG); + OUTW (dev, maccfg0_val, MACCFG0); + OUTW (dev, maccfg1_val, MACCFG1); + + return; +} + +static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev) +{ + unsigned long m88_ssr; + unsigned long MediaMode; + + m88_ssr = ax88180_mdio_read (dev, M88_SSR); + switch (m88_ssr & SSR_MEDIA_MASK) { + case SSR_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case SSR_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case SSR_100FULL: + MediaMode = MEDIA_100FULL; + break; + case SSR_100HALF: + MediaMode = MEDIA_100HALF; + break; + case SSR_10FULL: + MediaMode = MEDIA_10FULL; + break; + case SSR_10HALF: + MediaMode = MEDIA_10HALF; + break; + default: + MediaMode = MEDIA_UNKNOWN; + break; + } + + return MediaMode; +} + +static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev) +{ + unsigned long tmp_regval; + unsigned long MediaMode; + + tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS); + switch (tmp_regval & CIS_MEDIA_MASK) { + case CIS_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case CIS_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case CIS_100FULL: + MediaMode = MEDIA_100FULL; + break; + case CIS_100HALF: + MediaMode = MEDIA_100HALF; + break; + case CIS_10FULL: + MediaMode = MEDIA_10FULL; + break; + case CIS_10HALF: + MediaMode = MEDIA_10HALF; + break; + default: + MediaMode = MEDIA_UNKNOWN; + break; + } + + return MediaMode; +} + +static void ax88180_halt (struct eth_device *dev) +{ + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); +} + +static int ax88180_init (struct eth_device *dev, bd_t * bd) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned short tmp_regval; + + ax88180_mac_reset (dev); + + /* Disable interrupt */ + OUTW (dev, CLEAR_IMR, IMR); + + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); + + /* Fill the MAC address */ + tmp_regval = + dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8); + OUTW (dev, tmp_regval, MACID0); + + tmp_regval = + dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8); + OUTW (dev, tmp_regval, MACID1); + + tmp_regval = + dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8); + OUTW (dev, tmp_regval, MACID2); + + ax88180_meidia_config (dev); + + OUTW (dev, DEFAULT_RXFILTER, RXFILTER); + + /* Initial variables here */ + priv->FirstTxDesc = TXDP0; + priv->NextTxDesc = TXDP0; + + /* Check if there is any invalid interrupt status and clear it. */ + OUTW (dev, INW (dev, ISR), ISR); + + /* Start AX88180 TX/RX functions */ + OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD); + + return 0; +} + +/* Get a data block via Ethernet */ +static int ax88180_recv (struct eth_device *dev) +{ + unsigned short ISR_Status; + unsigned short tmp_regval; + + /* Read and check interrupt status here. */ + ISR_Status = INW (dev, ISR); + + while (ISR_Status) { + /* Clear the interrupt status */ + OUTW (dev, ISR_Status, ISR); + + debug ("\nax88180: The interrupt status = 0x%04x\n", + ISR_Status); + + if (ISR_Status & ISR_PHY) { + /* Read ISR register once to clear PHY interrupt bit */ + tmp_regval = ax88180_mdio_read (dev, M88_ISR); + ax88180_meidia_config (dev); + } + + if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) { + ax88180_rx_handler (dev); + } + + /* Read and check interrupt status again */ + ISR_Status = INW (dev, ISR); + } + + return 0; +} + +/* Send a data block via Ethernet. */ +static int +ax88180_send (struct eth_device *dev, volatile void *packet, int length) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned short TXDES_addr; + unsigned short txcmd_txdp, txbs_txdp; + unsigned short tmp_data; + int i; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + volatile unsigned short *txdata = (volatile unsigned short *)packet; +#else + volatile unsigned long *txdata = (volatile unsigned long *)packet; +#endif + unsigned short count; + + if (priv->LinkState != INS_LINK_UP) { + return 0; + } + + priv->FirstTxDesc = priv->NextTxDesc; + txbs_txdp = 1 << priv->FirstTxDesc; + + debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc); + + txcmd_txdp = priv->FirstTxDesc << 13; + TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2); + + OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD); + + /* Comput access times */ + count = (length + priv->PadSize) >> priv->BusWidth; + + for (i = 0; i < count; i++) { + WRITE_TXBUF (dev, *(txdata + i)); + } + + OUTW (dev, txcmd_txdp | length, TXCMD); + OUTW (dev, txbs_txdp, TXBS); + OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr); + + priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK; + + /* + * Check the available transmit descriptor, if we had exhausted all + * transmit descriptor ,then we have to wait for at least one free + * descriptor + */ + txbs_txdp = 1 << priv->NextTxDesc; + tmp_data = INW (dev, TXBS); + + if (tmp_data & txbs_txdp) { + if (ax88180_poll_tx_complete (dev) < 0) { + ax88180_mac_reset (dev); + priv->FirstTxDesc = TXDP0; + priv->NextTxDesc = TXDP0; + printf ("ax88180: Transmit time out occurred!\n"); + } + } + + return 0; +} + +static void ax88180_read_mac_addr (struct eth_device *dev) +{ + unsigned short macid0_val, macid1_val, macid2_val; + unsigned short tmp_regval; + unsigned short i; + + /* Reload MAC address from EEPROM */ + OUTW (dev, RELOAD_EEPROM, PROMCTRL); + + /* Waiting for reload eeprom completion */ + for (i = 0; i < 500; i++) { + tmp_regval = INW (dev, PROMCTRL); + if ((tmp_regval & RELOAD_EEPROM) == 0) + break; + udelay (1000); + } + + /* Get MAC addresses */ + macid0_val = INW (dev, MACID0); + macid1_val = INW (dev, MACID1); + macid2_val = INW (dev, MACID2); + + if (((macid0_val | macid1_val | macid2_val) != 0) && + ((macid0_val & 0x01) == 0)) { + dev->enetaddr[0] = (unsigned char)macid0_val; + dev->enetaddr[1] = (unsigned char)(macid0_val >> 8); + dev->enetaddr[2] = (unsigned char)macid1_val; + dev->enetaddr[3] = (unsigned char)(macid1_val >> 8); + dev->enetaddr[4] = (unsigned char)macid2_val; + dev->enetaddr[5] = (unsigned char)(macid2_val >> 8); + } +} + +/* +=========================================================================== +<<<<<< Exported SubProgram Bodies >>>>>> +=========================================================================== +*/ +int ax88180_initialize (bd_t * bis) +{ + struct eth_device *dev; + struct ax88180_private *priv; + + dev = (struct eth_device *)malloc (sizeof *dev); + + if (NULL == dev) + return 0; + + memset (dev, 0, sizeof *dev); + + priv = (struct ax88180_private *)malloc (sizeof (*priv)); + + if (NULL == priv) + return 0; + + memset (priv, 0, sizeof *priv); + + sprintf (dev->name, "ax88180"); + dev->iobase = AX88180_BASE; + dev->priv = priv; + dev->init = ax88180_init; + dev->halt = ax88180_halt; + dev->send = ax88180_send; + dev->recv = ax88180_recv; + + priv->BusWidth = BUS_WIDTH_32; + priv->PadSize = 3; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + OUTW (dev, (START_BASE >> 8), BASE); + OUTW (dev, DECODE_EN, DECODE); + + priv->BusWidth = BUS_WIDTH_16; + priv->PadSize = 1; +#endif + + ax88180_mac_reset (dev); + + /* Disable interrupt */ + OUTW (dev, CLEAR_IMR, IMR); + + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); + + ax88180_read_mac_addr (dev); + + eth_register (dev); + + return ax88180_phy_initial (dev); + +} diff --git a/drivers/net/ax88180.h b/drivers/net/ax88180.h new file mode 100644 index 0000000..5254e7d --- /dev/null +++ b/drivers/net/ax88180.h @@ -0,0 +1,412 @@ +/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/* + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + */ + +#ifndef _AX88180_H_ +#define _AX88180_H_ + +#include <asm/types.h> +#include <config.h> + +typedef enum _ax88180_link_state { + INS_LINK_DOWN, + INS_LINK_UP, + INS_LINK_UNKNOWN +} ax88180_link_state; + +struct ax88180_private { + unsigned char BusWidth; + unsigned char PadSize; + unsigned short PhyAddr; + unsigned short PhyID0; + unsigned short FirstTxDesc; + unsigned short NextTxDesc; + ax88180_link_state LinkState; +}; + +#define BUS_WIDTH_16 1 +#define BUS_WIDTH_32 2 + +#define ENABLE_JUMBO 1 +#define DISABLE_JUMBO 0 + +#define ENABLE_BURST 1 +#define DISABLE_BURST 0 + +#define NORMAL_RX_MODE 0 +#define RX_LOOPBACK_MODE 1 +#define RX_INIFINIT_LOOP_MODE 2 +#define TX_INIFINIT_LOOP_MODE 3 + +#define DEFAULT_ETH_MTU 1500 + +/* Jumbo packet size 4086 bytes included 4 bytes CRC*/ +#define MAX_JUMBO_MTU 4072 + +/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */ +#define MAX_TX_JUMBO_SIZE 4086 + +/* Max Rx Jumbo size is 15K Bytes */ +#define MAX_RX_SIZE 0x3C00 + +#define MARVELL_88E1111_PHYADDR 0x18 +#define MARVELL_88E1111_PHYIDR0 0x0141 + +#define CICADA_CIS8201_PHYADDR 0x01 +#define CICADA_CIS8201_PHYIDR0 0x000F + +#define MEDIA_AUTO 0 +#define MEDIA_1000FULL 1 +#define MEDIA_1000HALF 2 +#define MEDIA_100FULL 3 +#define MEDIA_100HALF 4 +#define MEDIA_10FULL 5 +#define MEDIA_10HALF 6 +#define MEDIA_UNKNOWN 7 + +#define AUTO_MEDIA 0 +#define FORCE_MEDIA 1 + +#define TXDP_MASK 3 +#define TXDP0 0 +#define TXDP1 1 +#define TXDP2 2 +#define TXDP3 3 + +#define CMD_MAP_SIZE 0x100 + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + #define AX88180_MEMORY_SIZE 0x00004000 + #define START_BASE 0x1000 + + #define RX_BUF_SIZE 0x1000 + #define TX_BUF_SIZE 0x0F00 + + #define TX_BASE START_BASE + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) + #define RX_BASE (CMD_BASE + CMD_MAP_SIZE) +#else + #define AX88180_MEMORY_SIZE 0x00010000 + + #define RX_BUF_SIZE 0x8000 + #define TX_BUF_SIZE 0x7C00 + + #define RX_BASE 0x0000 + #define TX_BASE (RX_BASE + RX_BUF_SIZE) + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) +#endif + +/* AX88180 Memory Mapping Definition */ +#define RXBUFFER_START RX_BASE + #define RX_PACKET_LEN_OFFSET 0 + #define RX_PAGE_NUM_MASK 0x7FF /* RX pages 0~7FFh */ +#define TXBUFFER_START TX_BASE + +/* AX88180 MAC Register Definition */ +#define DECODE (0) + #define DECODE_EN 0x00000001 +#define BASE (6) +#define CMD (CMD_BASE + 0x0000) + #define WAKEMOD 0x00000001 + #define TXEN 0x00000100 + #define RXEN 0x00000200 + #define DEFAULT_CMD WAKEMOD +#define IMR (CMD_BASE + 0x0004) + #define IMR_RXBUFFOVR 0x00000001 + #define IMR_WATCHDOG 0x00000002 + #define IMR_TX 0x00000008 + #define IMR_RX 0x00000010 + #define IMR_PHY 0x00000020 + #define CLEAR_IMR 0x00000000 + #define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\ + IMR_RXBUFFOVR | IMR_WATCHDOG) +#define ISR (CMD_BASE + 0x0008) + #define ISR_RXBUFFOVR 0x00000001 + #define ISR_WATCHDOG 0x00000002 + #define ISR_TX 0x00000008 + #define ISR_RX 0x00000010 + #define ISR_PHY 0x00000020 +#define TXCFG (CMD_BASE + 0x0010) + #define AUTOPAD_CRC 0x00000050 + #define DEFAULT_TXCFG AUTOPAD_CRC +#define TXCMD (CMD_BASE + 0x0014) + #define TXCMD_TXDP_MASK 0x00006000 + #define TXCMD_TXDP0 0x00000000 + #define TXCMD_TXDP1 0x00002000 + #define TXCMD_TXDP2 0x00004000 + #define TXCMD_TXDP3 0x00006000 + #define TX_START_WRITE 0x00008000 + #define TX_STOP_WRITE 0x00000000 + #define DEFAULT_TXCMD 0x00000000 +#define TXBS (CMD_BASE + 0x0018) + #define TXDP0_USED 0x00000001 + #define TXDP1_USED 0x00000002 + #define TXDP2_USED 0x00000004 + #define TXDP3_USED 0x00000008 + #define DEFAULT_TXBS 0x00000000 +#define TXDES0 (CMD_BASE + 0x0020) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES0 0x00000000 +#define TXDES1 (CMD_BASE + 0x0024) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES1 0x00000000 +#define TXDES2 (CMD_BASE + 0x0028) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES2 0x00000000 +#define TXDES3 (CMD_BASE + 0x002C) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES3 0x00000000 +#define RXCFG (CMD_BASE + 0x0030) + #define RXBUFF_PROTECT 0x00000001 + #define RXTCPCRC_CHECK 0x00000010 + #define RXFLOW_ENABLE 0x00000100 + #define DEFAULT_RXCFG RXBUFF_PROTECT +#define RXCURT (CMD_BASE + 0x0034) + #define DEFAULT_RXCURT 0x00000000 +#define RXBOUND (CMD_BASE + 0x0038) + #define DEFAULT_RXBOUND 0x7FF //RX pages 0~7FFh +#define MACCFG0 (CMD_BASE + 0x0040) + #define MACCFG0_BIT3_0 0x00000007 + #define IPGT_VAL 0x00000150 + #define TXFLOW_ENABLE 0x00001000 + #define SPEED100 0x00008000 + #define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0) +#define MACCFG1 (CMD_BASE + 0x0044) + #define RGMII_EN 0x00000002 + #define RXFLOW_EN 0x00000020 + #define FULLDUPLEX 0x00000040 + #define MAX_JUMBO_LEN 0x00000780 + #define RXJUMBO_EN 0x00000800 + #define GIGA_MODE_EN 0x00001000 + #define RXCRC_CHECK 0x00002000 + #define RXPAUSE_DA_CHECK 0x00004000 + + #define JUMBO_LEN_4K 0x00000200 + #define JUMBO_LEN_15K 0x00000780 + #define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \ + RGMII_EN) + #define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK) +#define MACCFG2 (CMD_BASE + 0x0048) + #define MACCFG2_BIT15_8 0x00000100 + #define JAM_LIMIT_MASK 0x000000FC + #define DEFAULT_JAM_LIMIT 0x00000064 + #define DEFAULT_MACCFG2 MACCFG2_BIT15_8 +#define MACCFG3 (CMD_BASE + 0x004C) + #define IPGR2_VAL 0x0000000E + #define IPGR1_VAL 0x00000600 + #define NOABORT 0x00008000 + #define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL) +#define TXPAUT (CMD_BASE + 0x0054) + #define DEFAULT_TXPAUT 0x001FE000 +#define RXBTHD0 (CMD_BASE + 0x0058) + #define DEFAULT_RXBTHD0 0x00000300 +#define RXBTHD1 (CMD_BASE + 0x005C) + #define DEFAULT_RXBTHD1 0x00000600 +#define RXFULTHD (CMD_BASE + 0x0060) + #define DEFAULT_RXFULTHD 0x00000100 +#define MISC (CMD_BASE + 0x0068) + /* Normal operation mode */ + #define MISC_NORMAL 0x00000003 + /* Clear bit 0 to reset MAC */ + #define MISC_RESET_MAC 0x00000002 + /* Clear bit 1 to reset PHY */ + #define MISC_RESET_PHY 0x00000001 + /* Clear bit 0 and 1 to reset MAC and PHY */ + #define MISC_RESET_MAC_PHY 0x00000000 + #define DEFAULT_MISC MISC_NORMAL +#define MACID0 (CMD_BASE + 0x0070) +#define MACID1 (CMD_BASE + 0x0074) +#define MACID2 (CMD_BASE + 0x0078) +#define TXLEN (CMD_BASE + 0x007C) + #define DEFAULT_TXLEN 0x000005FC +#define RXFILTER (CMD_BASE + 0x0080) + #define RX_RXANY 0x00000001 + #define RX_MULTICAST 0x00000002 + #define RX_UNICAST 0x00000004 + #define RX_BROADCAST 0x00000008 + #define RX_MULTI_HASH 0x00000010 + #define DISABLE_RXFILTER 0x00000000 + #define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST) +#define MDIOCTRL (CMD_BASE + 0x0084) + #define PHY_ADDR_MASK 0x0000001F + #define REG_ADDR_MASK 0x00001F00 + #define READ_PHY 0x00004000 + #define WRITE_PHY 0x00008000 +#define MDIODP (CMD_BASE + 0x0088) +#define GPIOCTRL (CMD_BASE + 0x008C) +#define RXINDICATOR (CMD_BASE + 0x0090) + #define RX_START_READ 0x00000001 + #define RX_STOP_READ 0x00000000 + #define DEFAULT_RXINDICATOR RX_STOP_READ +#define TXST (CMD_BASE + 0x0094) +#define MDCCLKPAT (CMD_BASE + 0x00A0) +#define RXIPCRCCNT (CMD_BASE + 0x00A4) +#define RXCRCCNT (CMD_BASE + 0x00A8) +#define TXFAILCNT (CMD_BASE + 0x00AC) +#define PROMDP (CMD_BASE + 0x00B0) +#define PROMCTRL (CMD_BASE + 0x00B4) + #define RELOAD_EEPROM 0x00000200 +#define MAXRXLEN (CMD_BASE + 0x00B8) +#define HASHTAB0 (CMD_BASE + 0x00C0) +#define HASHTAB1 (CMD_BASE + 0x00C4) +#define HASHTAB2 (CMD_BASE + 0x00C8) +#define HASHTAB3 (CMD_BASE + 0x00CC) +#define DOGTHD0 (CMD_BASE + 0x00E0) + #define DEFAULT_DOGTHD0 0x0000FFFF +#define DOGTHD1 (CMD_BASE + 0x00E4) + #define START_WATCHDOG_TIMER 0x00008000 + #define DEFAULT_DOGTHD1 0x00000FFF +#define SOFTRST (CMD_BASE + 0x00EC) + #define SOFTRST_NORMAL 0x00000003 + #define SOFTRST_RESET_MAC 0x00000002 + +/* External PHY Register Definition */ +#define BMCR 0x0000 + #define LINE_SPEED_MSB 0x0040 + #define DUPLEX_MODE 0x0100 + #define RESTART_AUTONEG 0x0200 + #define POWER_DOWN 0x0800 + #define AUTONEG_EN 0x1000 + #define LINE_SPEED_LSB 0x2000 + #define PHY_RESET 0x8000 + + #define MEDIAMODE_MASK (LINE_SPEED_MSB | LINE_SPEED_LSB |\ + DUPLEX_MODE) + #define BMCR_SPEED_1000 LINE_SPEED_MSB + #define BMCR_SPEED_100 LINE_SPEED_LSB + #define BMCR_SPEED_10 0x0000 + + #define BMCR_1000FULL (BMCR_SPEED_1000 | DUPLEX_MODE) + #define BMCR_100FULL (BMCR_SPEED_100 | DUPLEX_MODE) + #define BMCR_100HALF BMCR_SPEED_100 + #define BMCR_10FULL DUPLEX_MODE + #define BMCR_10HALF 0x0000 +#define BMSR 0x0001 + #define LINKOK 0x0004 + #define AUTONEG_ENABLE_STS 0x0008 + #define AUTONEG_COMPLETE 0x0020 +#define PHYIDR0 0x0002 +#define PHYIDR1 0x0003 +#define ANAR 0x0004 + #define ANAR_PAUSE 0x0400 + #define ANAR_100FULL 0x0100 + #define ANAR_100HALF 0x0080 + #define ANAR_10FULL 0x0040 + #define ANAR_10HALF 0x0020 + #define ANAR_8023BIT 0x0001 +#define ANLPAR 0x0005 +#define ANER 0x0006 +#define AUX_1000_CTRL 0x0009 + #define ENABLE_1000HALF 0x0100 + #define ENABLE_1000FULL 0x0200 + #define DEFAULT_AUX_1000_CTRL (ENABLE_1000HALF | ENABLE_1000FULL) +#define AUX_1000_STATUS 0x000A + #define LP_1000HALF 0x0400 + #define LP_1000FULL 0x0800 + +/* Marvell 88E1111 Gigabit PHY Register Definition */ +#define M88_SSR 0x0011 + #define SSR_SPEED_MASK 0xC000 + #define SSR_SPEED_1000 0x8000 + #define SSR_SPEED_100 0x4000 + #define SSR_SPEED_10 0x0000 + #define SSR_DUPLEX 0x2000 + #define SSR_MEDIA_RESOLVED_OK 0x0800 + + #define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX) + #define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX) + #define SSR_1000HALF SSR_SPEED_1000 + #define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX) + #define SSR_100HALF SSR_SPEED_100 + #define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX) + #define SSR_10HALF SSR_SPEED_10 +#define M88_IER 0x0012 + #define LINK_CHANGE_INT 0x0400 +#define M88_ISR 0x0013 + #define LINK_CHANGE_STATUS 0x0400 +#define M88_EXT_SCR 0x0014 + #define RGMII_RXCLK_DELAY 0x0080 + #define RGMII_TXCLK_DELAY 0x0002 + #define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY) +#define M88_EXT_SSR 0x001B + #define HWCFG_MODE_MASK 0x000F + #define RGMII_COPPER_MODE 0x000B + +/* CICADA CIS8201 Gigabit PHY Register Definition */ +#define CIS_IMR 0x0019 + #define CIS_INT_ENABLE 0x8000 + #define CIS_LINK_CHANGE_INT 0x2000 +#define CIS_ISR 0x001A + #define CIS_INT_PENDING 0x8000 + #define CIS_LINK_CHANGE_STATUS 0x2000 +#define CIS_AUX_CTRL_STATUS 0x001C + #define CIS_AUTONEG_COMPLETE 0x8000 + #define CIS_SPEED_MASK 0x0018 + #define CIS_SPEED_1000 0x0010 + #define CIS_SPEED_100 0x0008 + #define CIS_SPEED_10 0x0000 + #define CIS_DUPLEX 0x0020 + + #define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX) + #define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX) + #define CIS_1000HALF CIS_SPEED_1000 + #define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX) + #define CIS_100HALF CIS_SPEED_100 + #define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX) + #define CIS_10HALF CIS_SPEED_10 + #define CIS_SMI_PRIORITY 0x0004 + +static inline unsigned short INW (struct eth_device *dev, unsigned long addr) +{ + return le16_to_cpu (*(volatile unsigned short *) (addr + dev->iobase)); +} + +static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr) +{ + *(volatile unsigned short *) ((addr + dev->iobase)) = cpu_to_le16 (command); +} + +/* + Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer +*/ +#if defined (CONFIG_DRIVER_AX88180_16BIT) +static inline unsigned short READ_RXBUF (struct eth_device *dev) +{ + return le16_to_cpu (*(volatile unsigned short *) (RXBUFFER_START + dev->iobase)); +} + +static inline void WRITE_TXBUF (struct eth_device *dev, unsigned short data) +{ + *(volatile unsigned short *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le16 (data); +} +#else +static inline unsigned long READ_RXBUF (struct eth_device *dev) +{ + return le32_to_cpu (*(volatile unsigned long *) (RXBUFFER_START + dev->iobase)); +} + +static inline void WRITE_TXBUF (struct eth_device *dev, unsigned long data) +{ + *(volatile unsigned long *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le32 (data); +} +#endif + +#endif /* _AX88180_H_ */ diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 39cd101..2089141 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -143,7 +143,7 @@ static void ax88796_mac_read(u8 *buff) } } -int get_prom(u8* mac_addr) +int get_prom(u8* mac_addr, u8* base_addr) { u8 prom[32]; int i; diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index ec92485..ab5eec7 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -74,600 +74,11 @@ Add SNMP #include <common.h> #include <command.h> -#include <net.h> -#include <malloc.h> - -#define mdelay(n) udelay((n)*1000) -/* forward definition of function used for the uboot interface */ -void uboot_push_packet_len(int len); -void uboot_push_tx_done(int key, int val); - -/* - * Debugging details - * - * Set to perms of: - * 0 disables all debug output - * 1 for process debug output - * 2 for added data IO output: get_reg, put_reg - * 4 for packet allocation/free output - * 8 for only startup status, so we can tell we're installed OK - */ -#if 0 -#define DEBUG 0xf -#else -#define DEBUG 0 -#endif - -#if DEBUG & 1 -#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0) -#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0) -#define PRINTK(args...) printf(args) -#else -#define DEBUG_FUNCTION() do {} while(0) -#define DEBUG_LINE() do {} while(0) -#define PRINTK(args...) -#endif /* NE2000 base header file */ #include "ne2000_base.h" -#if defined(CONFIG_DRIVER_AX88796L) -/* AX88796L support */ -#include "ax88796.h" -#else -/* Basic NE2000 chip support */ -#include "ne2000.h" -#endif - -static dp83902a_priv_data_t nic; /* just one instance of the card supported */ - -static bool -dp83902a_init(void) -{ - dp83902a_priv_data_t *dp = &nic; - u8* base; -#if defined(NE2000_BASIC_INIT) - int i; -#endif - - DEBUG_FUNCTION(); - - base = dp->base; - if (!base) - return false; /* No device found */ - - DEBUG_LINE(); - -#if defined(NE2000_BASIC_INIT) - /* AX88796L doesn't need */ - /* Prepare ESA */ - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ - /* Use the address from the serial EEPROM */ - for (i = 0; i < 6; i++) - DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ - - printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", - "eeprom", - dp->esa[0], - dp->esa[1], - dp->esa[2], - dp->esa[3], - dp->esa[4], - dp->esa[5] ); - -#endif /* NE2000_BASIC_INIT */ - return true; -} - -static void -dp83902a_stop(void) -{ - dp83902a_priv_data_t *dp = &nic; - u8 *base = dp->base; - - DEBUG_FUNCTION(); - - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ - DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ - DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */ - - dp->running = false; -} - -/* - * This function is called to "start up" the interface. It may be called - * multiple times, even when the hardware is already running. It will be - * called whenever something "hardware oriented" changes and should leave - * the hardware ready to send/receive packets. - */ -static void -dp83902a_start(u8 * enaddr) -{ - dp83902a_priv_data_t *dp = &nic; - u8 *base = dp->base; - int i; - - DEBUG_FUNCTION(); - - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ - DP_OUT(base, DP_DCR, DP_DCR_INIT); - DP_OUT(base, DP_RBCH, 0); /* Remote byte count */ - DP_OUT(base, DP_RBCL, 0); - DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */ - DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */ - DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */ - dp->tx1 = dp->tx2 = 0; - dp->tx_next = dp->tx_buf1; - dp->tx_started = false; - dp->running = true; - DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */ - DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */ - DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */ - dp->rx_next = dp->rx_buf_start - 1; - dp->running = true; - DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ - DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */ - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */ - DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */ - dp->running = true; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - /* FIXME */ - /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + - * 0x1400)) = enaddr[i];*/ - DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); - } - /* Enable and start device */ - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); - DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ - DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ - dp->running = true; -} - -/* - * This routine is called to start the transmitter. It is split out from the - * data handling routine so it may be called either when data becomes first - * available or when an Tx interrupt occurs - */ - -static void -dp83902a_start_xmit(int start_page, int len) -{ - dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic; - u8 *base = dp->base; - - DEBUG_FUNCTION(); - -#if DEBUG & 1 - printf("Tx pkt %d len %d\n", start_page, len); - if (dp->tx_started) - printf("TX already started?!?\n"); -#endif - - DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); - DP_OUT(base, DP_TBCL, len & 0xFF); - DP_OUT(base, DP_TBCH, len >> 8); - DP_OUT(base, DP_TPSR, start_page); - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); - - dp->tx_started = true; -} - -/* - * This routine is called to send data to the hardware. It is known a-priori - * that there is free buffer space (dp->tx_next). - */ -static void -dp83902a_send(u8 *data, int total_len, u32 key) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - int len, start_page, pkt_len, i, isr; -#if DEBUG & 4 - int dx; -#endif - - DEBUG_FUNCTION(); - - len = pkt_len = total_len; - if (pkt_len < IEEE_8023_MIN_FRAME) - pkt_len = IEEE_8023_MIN_FRAME; - - start_page = dp->tx_next; - if (dp->tx_next == dp->tx_buf1) { - dp->tx1 = start_page; - dp->tx1_len = pkt_len; - dp->tx1_key = key; - dp->tx_next = dp->tx_buf2; - } else { - dp->tx2 = start_page; - dp->tx2_len = pkt_len; - dp->tx2_key = key; - dp->tx_next = dp->tx_buf1; - } - -#if DEBUG & 5 - printf("TX prep page %d len %d\n", start_page, pkt_len); -#endif - - DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ - { - /* - * Dummy read. The manual sez something slightly different, - * but the code is extended a bit to do what Hitachi's monitor - * does (i.e., also read data). - */ - - u16 tmp; - int len = 1; - - DP_OUT(base, DP_RSAL, 0x100 - len); - DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff); - DP_OUT(base, DP_RBCL, len); - DP_OUT(base, DP_RBCH, 0); - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); - DP_IN_DATA(dp->data, tmp); - } - -#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA - /* - * Stall for a bit before continuing to work around random data - * corruption problems on some platforms. - */ - CYGACC_CALL_IF_DELAY_US(1); -#endif - - /* Send data to device buffer(s) */ - DP_OUT(base, DP_RSAL, 0); - DP_OUT(base, DP_RSAH, start_page); - DP_OUT(base, DP_RBCL, pkt_len & 0xFF); - DP_OUT(base, DP_RBCH, pkt_len >> 8); - DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); - - /* Put data into buffer */ -#if DEBUG & 4 - printf(" sg buf %08lx len %08x\n ", (u32)data, len); - dx = 0; -#endif - while (len > 0) { -#if DEBUG & 4 - printf(" %02x", *data); - if (0 == (++dx % 16)) printf("\n "); -#endif - - DP_OUT_DATA(dp->data, *data++); - len--; - } -#if DEBUG & 4 - printf("\n"); -#endif - if (total_len < pkt_len) { -#if DEBUG & 4 - printf(" + %d bytes of padding\n", pkt_len - total_len); -#endif - /* Padding to 802.3 length was required */ - for (i = total_len; i < pkt_len;) { - i++; - DP_OUT_DATA(dp->data, 0); - } - } - -#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA - /* - * After last data write, delay for a bit before accessing the - * device again, or we may get random data corruption in the last - * datum (on some platforms). - */ - CYGACC_CALL_IF_DELAY_US(1); -#endif - - /* Wait for DMA to complete */ - do { - DP_IN(base, DP_ISR, isr); - } while ((isr & DP_ISR_RDC) == 0); - - /* Then disable DMA */ - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); - - /* Start transmit if not already going */ - if (!dp->tx_started) { - if (start_page == dp->tx1) { - dp->tx_int = 1; /* Expecting interrupt from BUF1 */ - } else { - dp->tx_int = 2; /* Expecting interrupt from BUF2 */ - } - dp83902a_start_xmit(start_page, pkt_len); - } -} - -/* - * This function is called when a packet has been received. It's job is - * to prepare to unload the packet from the hardware. Once the length of - * the packet is known, the upper layer of the driver can be told. When - * the upper layer is ready to unload the packet, the internal function - * 'dp83902a_recv' will be called to actually fetch it from the hardware. - */ -static void -dp83902a_RxEvent(void) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - u8 rsr; - u8 rcv_hdr[4]; - int i, len, pkt, cur; - - DEBUG_FUNCTION(); - - DP_IN(base, DP_RSR, rsr); - while (true) { - /* Read incoming packet header */ - DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); - DP_IN(base, DP_P1_CURP, cur); - DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); - DP_IN(base, DP_BNDRY, pkt); - - pkt += 1; - if (pkt == dp->rx_buf_end) - pkt = dp->rx_buf_start; - - if (pkt == cur) { - break; - } - DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); - DP_OUT(base, DP_RBCH, 0); - DP_OUT(base, DP_RSAL, 0); - DP_OUT(base, DP_RSAH, pkt); - if (dp->rx_next == pkt) { - if (cur == dp->rx_buf_start) - DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); - else - DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ - return; - } - dp->rx_next = pkt; - DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ - DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); -#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA - CYGACC_CALL_IF_DELAY_US(10); -#endif - - /* read header (get data size)*/ - for (i = 0; i < sizeof(rcv_hdr);) { - DP_IN_DATA(dp->data, rcv_hdr[i++]); - } - -#if DEBUG & 5 - printf("rx hdr %02x %02x %02x %02x\n", - rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); -#endif - len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); - - /* data read */ - uboot_push_packet_len(len); - - if (rcv_hdr[1] == dp->rx_buf_start) - DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); - else - DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ - } -} - -/* - * This function is called as a result of the "eth_drv_recv()" call above. - * It's job is to actually fetch data for a packet from the hardware once - * memory buffers have been allocated for the packet. Note that the buffers - * may come in pieces, using a scatter-gather list. This allows for more - * efficient processing in the upper layers of the stack. - */ -static void -dp83902a_recv(u8 *data, int len) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - int i, mlen; - u8 saved_char = 0; - bool saved; -#if DEBUG & 4 - int dx; -#endif - - DEBUG_FUNCTION(); - -#if DEBUG & 5 - printf("Rx packet %d length %d\n", dp->rx_next, len); -#endif - - /* Read incoming packet data */ - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); - DP_OUT(base, DP_RBCL, len & 0xFF); - DP_OUT(base, DP_RBCH, len >> 8); - DP_OUT(base, DP_RSAL, 4); /* Past header */ - DP_OUT(base, DP_RSAH, dp->rx_next); - DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ - DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); -#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA - CYGACC_CALL_IF_DELAY_US(10); -#endif - - saved = false; - for (i = 0; i < 1; i++) { - if (data) { - mlen = len; -#if DEBUG & 4 - printf(" sg buf %08lx len %08x \n", (u32) data, mlen); - dx = 0; -#endif - while (0 < mlen) { - /* Saved byte from previous loop? */ - if (saved) { - *data++ = saved_char; - mlen--; - saved = false; - continue; - } - - { - u8 tmp; - DP_IN_DATA(dp->data, tmp); -#if DEBUG & 4 - printf(" %02x", tmp); - if (0 == (++dx % 16)) printf("\n "); -#endif - *data++ = tmp;; - mlen--; - } - } -#if DEBUG & 4 - printf("\n"); -#endif - } - } -} - -static void -dp83902a_TxEvent(void) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - u8 tsr; - u32 key; - - DEBUG_FUNCTION(); - - DP_IN(base, DP_TSR, tsr); - if (dp->tx_int == 1) { - key = dp->tx1_key; - dp->tx1 = 0; - } else { - key = dp->tx2_key; - dp->tx2 = 0; - } - /* Start next packet if one is ready */ - dp->tx_started = false; - if (dp->tx1) { - dp83902a_start_xmit(dp->tx1, dp->tx1_len); - dp->tx_int = 1; - } else if (dp->tx2) { - dp83902a_start_xmit(dp->tx2, dp->tx2_len); - dp->tx_int = 2; - } else { - dp->tx_int = 0; - } - /* Tell higher level we sent this packet */ - uboot_push_tx_done(key, 0); -} - -/* - * Read the tally counters to clear them. Called in response to a CNT - * interrupt. - */ -static void -dp83902a_ClearCounters(void) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - u8 cnt1, cnt2, cnt3; - - DP_IN(base, DP_FER, cnt1); - DP_IN(base, DP_CER, cnt2); - DP_IN(base, DP_MISSED, cnt3); - DP_OUT(base, DP_ISR, DP_ISR_CNT); -} - -/* - * Deal with an overflow condition. This code follows the procedure set - * out in section 7.0 of the datasheet. - */ -static void -dp83902a_Overflow(void) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; - u8 *base = dp->base; - u8 isr; - - /* Issue a stop command and wait 1.6ms for it to complete. */ - DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); - CYGACC_CALL_IF_DELAY_US(1600); - - /* Clear the remote byte counter registers. */ - DP_OUT(base, DP_RBCL, 0); - DP_OUT(base, DP_RBCH, 0); - - /* Enter loopback mode while we clear the buffer. */ - DP_OUT(base, DP_TCR, DP_TCR_LOCAL); - DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); - - /* - * Read in as many packets as we can and acknowledge any and receive - * interrupts. Since the buffer has overflowed, a receive event of - * some kind will have occured. - */ - dp83902a_RxEvent(); - DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); - - /* Clear the overflow condition and leave loopback mode. */ - DP_OUT(base, DP_ISR, DP_ISR_OFLW); - DP_OUT(base, DP_TCR, DP_TCR_NORMAL); - - /* - * If a transmit command was issued, but no transmit event has occured, - * restart it here. - */ - DP_IN(base, DP_ISR, isr); - if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); - } -} - -static void -dp83902a_poll(void) -{ - struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - u8 *base = dp->base; - u8 isr; - - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); - DP_IN(base, DP_ISR, isr); - while (0 != isr) { - /* - * The CNT interrupt triggers when the MSB of one of the error - * counters is set. We don't much care about these counters, but - * we should read their values to reset them. - */ - if (isr & DP_ISR_CNT) { - dp83902a_ClearCounters(); - } - /* - * Check for overflow. It's a special case, since there's a - * particular procedure that must be followed to get back into - * a running state.a - */ - if (isr & DP_ISR_OFLW) { - dp83902a_Overflow(); - } else { - /* - * Other kinds of interrupts can be acknowledged simply by - * clearing the relevant bits of the ISR. Do that now, then - * handle the interrupts we care about. - */ - DP_OUT(base, DP_ISR, isr); /* Clear set bits */ - if (!dp->running) break; /* Is this necessary? */ - /* - * Check for tx_started on TX event since these may happen - * spuriously it seems. - */ - if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { - dp83902a_TxEvent(); - } - if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { - dp83902a_RxEvent(); - } - } - DP_IN(base, DP_ISR, isr); - } -} - +#define mdelay(n) udelay((n)*1000) /* find prom (taken from pc_net_cs.c from Linux) */ #include "8390.h" @@ -763,18 +174,16 @@ static hw_info_t hw_info[] = { #define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ #define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ -static void pcnet_reset_8390(void) +static void pcnet_reset_8390(u8* addr) { int i, r; - PRINTK("nic base is %lx\n", nic.base); - n2k_outb(E8390_NODMA + E8390_PAGE0+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD)); + PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD)); + PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD)); + PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET); @@ -791,8 +200,7 @@ static void pcnet_reset_8390(void) printf("pcnet_reset_8390() did not complete.\n"); } /* pcnet_reset_8390 */ -int get_prom(u8* mac_addr) __attribute__ ((weak, alias ("__get_prom"))); -int __get_prom(u8* mac_addr) +int get_prom(u8* mac_addr, u8* base_addr) { u8 prom[32]; int i, j; @@ -816,7 +224,7 @@ int __get_prom(u8* mac_addr) PRINTK ("trying to get MAC via prom reading\n"); - pcnet_reset_8390 (); + pcnet_reset_8390 (base_addr); mdelay (10); @@ -849,116 +257,3 @@ int __get_prom(u8* mac_addr) } return 0; } - -/* U-boot specific routines */ -static u8 *pbuf = NULL; - -static int pkey = -1; -static int initialized = 0; - -void uboot_push_packet_len(int len) { - PRINTK("pushed len = %d\n", len); - if (len >= 2000) { - printf("NE2000: packet too big\n"); - return; - } - dp83902a_recv(&pbuf[0], len); - - /*Just pass it to the upper layer*/ - NetReceive(&pbuf[0], len); -} - -void uboot_push_tx_done(int key, int val) { - PRINTK("pushed key = %d\n", key); - pkey = key; -} - -int eth_init(bd_t *bd) { - int r; - u8 dev_addr[6]; - char ethaddr[20]; - - PRINTK("### eth_init\n"); - - if (!pbuf) { - pbuf = malloc(2000); - if (!pbuf) { - printf("Cannot allocate rx buffer\n"); - return -1; - } - } - -#ifdef CONFIG_DRIVER_NE2000_CCR - { - vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; - - PRINTK("CCR before is %x\n", *p); - *p = CONFIG_DRIVER_NE2000_VAL; - PRINTK("CCR after is %x\n", *p); - } -#endif - - nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; - - r = get_prom(dev_addr); - if (!r) - return -1; - - sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", - dev_addr[0], dev_addr[1], - dev_addr[2], dev_addr[3], - dev_addr[4], dev_addr[5]) ; - PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); - setenv ("ethaddr", ethaddr); - - nic.data = nic.base + DP_DATA; - nic.tx_buf1 = START_PG; - nic.tx_buf2 = START_PG2; - nic.rx_buf_start = RX_START; - nic.rx_buf_end = RX_END; - - if (dp83902a_init() == false) - return -1; - - dp83902a_start(dev_addr); - initialized = 1; - - return 0; -} - -void eth_halt() { - - PRINTK("### eth_halt\n"); - if(initialized) - dp83902a_stop(); - initialized = 0; -} - -int eth_rx() { - dp83902a_poll(); - return 1; -} - -int eth_send(volatile void *packet, int length) { - int tmo; - - PRINTK("### eth_send\n"); - - pkey = -1; - - dp83902a_send((u8 *) packet, length, 666); - tmo = get_timer (0) + TOUT * CFG_HZ; - while(1) { - dp83902a_poll(); - if (pkey != -1) { - PRINTK("Packet sucesfully sent\n"); - return 0; - } - if (get_timer (0) >= tmo) { - printf("transmission error (timoeut)\n"); - return 0; - } - - } - return 0; -} diff --git a/drivers/net/ne2000_base.c b/drivers/net/ne2000_base.c new file mode 100644 index 0000000..4a07708 --- /dev/null +++ b/drivers/net/ne2000_base.c @@ -0,0 +1,757 @@ +/* +Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> + +Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and +eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world +are GPL, so this is, of course, GPL. + +========================================================================== + +dev/if_dp83902a.c + +Ethernet device driver for NS DP83902a ethernet controller + +========================================================================== +####ECOSGPLCOPYRIGHTBEGIN#### +------------------------------------------- +This file is part of eCos, the Embedded Configurable Operating System. +Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + +eCos 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 or (at your option) any later version. + +eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +As a special exception, if other files instantiate templates or use macros +or inline functions from this file, or you compile this file and link it +with other works to produce a work based on this file, this file does not +by itself cause the resulting work to be covered by the GNU General Public +License. However the source code for this file must still be made available +in accordance with section (3) of the GNU General Public License. + +This exception does not invalidate any other reasons why a work based on +this file might be covered by the GNU General Public License. + +Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +at http://sources.redhat.com/ecos/ecos-license/ +------------------------------------------- +####ECOSGPLCOPYRIGHTEND#### +####BSDCOPYRIGHTBEGIN#### + +------------------------------------------- + +Portions of this software may have been derived from OpenBSD or other sources, +and are covered by the appropriate copyright disclaimers included herein. + +------------------------------------------- + +####BSDCOPYRIGHTEND#### +========================================================================== +#####DESCRIPTIONBEGIN#### + +Author(s): gthomas +Contributors: gthomas, jskov, rsandifo +Date: 2001-06-13 +Purpose: +Description: + +FIXME: Will fail if pinged with large packets (1520 bytes) +Add promisc config +Add SNMP + +####DESCRIPTIONEND#### + +========================================================================== +*/ + +#include <common.h> +#include <command.h> +#include <net.h> +#include <malloc.h> + +#define mdelay(n) udelay((n)*1000) +/* forward definition of function used for the uboot interface */ +void uboot_push_packet_len(int len); +void uboot_push_tx_done(int key, int val); + +/* NE2000 base header file */ +#include "ne2000_base.h" + +#if defined(CONFIG_DRIVER_AX88796L) +/* AX88796L support */ +#include "ax88796.h" +#else +/* Basic NE2000 chip support */ +#include "ne2000.h" +#endif + +static dp83902a_priv_data_t nic; /* just one instance of the card supported */ + +static bool +dp83902a_init(void) +{ + dp83902a_priv_data_t *dp = &nic; + u8* base; +#if defined(NE2000_BASIC_INIT) + int i; +#endif + + DEBUG_FUNCTION(); + + base = dp->base; + if (!base) + return false; /* No device found */ + + DEBUG_LINE(); + +#if defined(NE2000_BASIC_INIT) + /* AX88796L doesn't need */ + /* Prepare ESA */ + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ + /* Use the address from the serial EEPROM */ + for (i = 0; i < 6; i++) + DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ + + printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", + "eeprom", + dp->esa[0], + dp->esa[1], + dp->esa[2], + dp->esa[3], + dp->esa[4], + dp->esa[5] ); + +#endif /* NE2000_BASIC_INIT */ + return true; +} + +static void +dp83902a_stop(void) +{ + dp83902a_priv_data_t *dp = &nic; + u8 *base = dp->base; + + DEBUG_FUNCTION(); + + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ + DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ + DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */ + + dp->running = false; +} + +/* + * This function is called to "start up" the interface. It may be called + * multiple times, even when the hardware is already running. It will be + * called whenever something "hardware oriented" changes and should leave + * the hardware ready to send/receive packets. + */ +static void +dp83902a_start(u8 * enaddr) +{ + dp83902a_priv_data_t *dp = &nic; + u8 *base = dp->base; + int i; + + DEBUG_FUNCTION(); + + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ + DP_OUT(base, DP_DCR, DP_DCR_INIT); + DP_OUT(base, DP_RBCH, 0); /* Remote byte count */ + DP_OUT(base, DP_RBCL, 0); + DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */ + DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */ + DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */ + dp->tx1 = dp->tx2 = 0; + dp->tx_next = dp->tx_buf1; + dp->tx_started = false; + dp->running = true; + DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */ + DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */ + DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */ + dp->rx_next = dp->rx_buf_start - 1; + dp->running = true; + DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ + DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */ + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */ + DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */ + dp->running = true; + for (i = 0; i < ETHER_ADDR_LEN; i++) { + /* FIXME */ + /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + + * 0x1400)) = enaddr[i];*/ + DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); + } + /* Enable and start device */ + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); + DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ + DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ + dp->running = true; +} + +/* + * This routine is called to start the transmitter. It is split out from the + * data handling routine so it may be called either when data becomes first + * available or when an Tx interrupt occurs + */ + +static void +dp83902a_start_xmit(int start_page, int len) +{ + dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic; + u8 *base = dp->base; + + DEBUG_FUNCTION(); + +#if DEBUG & 1 + printf("Tx pkt %d len %d\n", start_page, len); + if (dp->tx_started) + printf("TX already started?!?\n"); +#endif + + DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); + DP_OUT(base, DP_TBCL, len & 0xFF); + DP_OUT(base, DP_TBCH, len >> 8); + DP_OUT(base, DP_TPSR, start_page); + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); + + dp->tx_started = true; +} + +/* + * This routine is called to send data to the hardware. It is known a-priori + * that there is free buffer space (dp->tx_next). + */ +static void +dp83902a_send(u8 *data, int total_len, u32 key) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + int len, start_page, pkt_len, i, isr; +#if DEBUG & 4 + int dx; +#endif + + DEBUG_FUNCTION(); + + len = pkt_len = total_len; + if (pkt_len < IEEE_8023_MIN_FRAME) + pkt_len = IEEE_8023_MIN_FRAME; + + start_page = dp->tx_next; + if (dp->tx_next == dp->tx_buf1) { + dp->tx1 = start_page; + dp->tx1_len = pkt_len; + dp->tx1_key = key; + dp->tx_next = dp->tx_buf2; + } else { + dp->tx2 = start_page; + dp->tx2_len = pkt_len; + dp->tx2_key = key; + dp->tx_next = dp->tx_buf1; + } + +#if DEBUG & 5 + printf("TX prep page %d len %d\n", start_page, pkt_len); +#endif + + DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ + { + /* + * Dummy read. The manual sez something slightly different, + * but the code is extended a bit to do what Hitachi's monitor + * does (i.e., also read data). + */ + + u16 tmp; + int len = 1; + + DP_OUT(base, DP_RSAL, 0x100 - len); + DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff); + DP_OUT(base, DP_RBCL, len); + DP_OUT(base, DP_RBCH, 0); + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); + DP_IN_DATA(dp->data, tmp); + } + +#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA + /* + * Stall for a bit before continuing to work around random data + * corruption problems on some platforms. + */ + CYGACC_CALL_IF_DELAY_US(1); +#endif + + /* Send data to device buffer(s) */ + DP_OUT(base, DP_RSAL, 0); + DP_OUT(base, DP_RSAH, start_page); + DP_OUT(base, DP_RBCL, pkt_len & 0xFF); + DP_OUT(base, DP_RBCH, pkt_len >> 8); + DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); + + /* Put data into buffer */ +#if DEBUG & 4 + printf(" sg buf %08lx len %08x\n ", (u32)data, len); + dx = 0; +#endif + while (len > 0) { +#if DEBUG & 4 + printf(" %02x", *data); + if (0 == (++dx % 16)) printf("\n "); +#endif + + DP_OUT_DATA(dp->data, *data++); + len--; + } +#if DEBUG & 4 + printf("\n"); +#endif + if (total_len < pkt_len) { +#if DEBUG & 4 + printf(" + %d bytes of padding\n", pkt_len - total_len); +#endif + /* Padding to 802.3 length was required */ + for (i = total_len; i < pkt_len;) { + i++; + DP_OUT_DATA(dp->data, 0); + } + } + +#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA + /* + * After last data write, delay for a bit before accessing the + * device again, or we may get random data corruption in the last + * datum (on some platforms). + */ + CYGACC_CALL_IF_DELAY_US(1); +#endif + + /* Wait for DMA to complete */ + do { + DP_IN(base, DP_ISR, isr); + } while ((isr & DP_ISR_RDC) == 0); + + /* Then disable DMA */ + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); + + /* Start transmit if not already going */ + if (!dp->tx_started) { + if (start_page == dp->tx1) { + dp->tx_int = 1; /* Expecting interrupt from BUF1 */ + } else { + dp->tx_int = 2; /* Expecting interrupt from BUF2 */ + } + dp83902a_start_xmit(start_page, pkt_len); + } +} + +/* + * This function is called when a packet has been received. It's job is + * to prepare to unload the packet from the hardware. Once the length of + * the packet is known, the upper layer of the driver can be told. When + * the upper layer is ready to unload the packet, the internal function + * 'dp83902a_recv' will be called to actually fetch it from the hardware. + */ +static void +dp83902a_RxEvent(void) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + u8 rsr; + u8 rcv_hdr[4]; + int i, len, pkt, cur; + + DEBUG_FUNCTION(); + + DP_IN(base, DP_RSR, rsr); + while (true) { + /* Read incoming packet header */ + DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); + DP_IN(base, DP_P1_CURP, cur); + DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); + DP_IN(base, DP_BNDRY, pkt); + + pkt += 1; + if (pkt == dp->rx_buf_end) + pkt = dp->rx_buf_start; + + if (pkt == cur) { + break; + } + DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); + DP_OUT(base, DP_RBCH, 0); + DP_OUT(base, DP_RSAL, 0); + DP_OUT(base, DP_RSAH, pkt); + if (dp->rx_next == pkt) { + if (cur == dp->rx_buf_start) + DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); + else + DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ + return; + } + dp->rx_next = pkt; + DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ + DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); +#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA + CYGACC_CALL_IF_DELAY_US(10); +#endif + + /* read header (get data size)*/ + for (i = 0; i < sizeof(rcv_hdr);) { + DP_IN_DATA(dp->data, rcv_hdr[i++]); + } + +#if DEBUG & 5 + printf("rx hdr %02x %02x %02x %02x\n", + rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); +#endif + len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); + + /* data read */ + uboot_push_packet_len(len); + + if (rcv_hdr[1] == dp->rx_buf_start) + DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); + else + DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ + } +} + +/* + * This function is called as a result of the "eth_drv_recv()" call above. + * It's job is to actually fetch data for a packet from the hardware once + * memory buffers have been allocated for the packet. Note that the buffers + * may come in pieces, using a scatter-gather list. This allows for more + * efficient processing in the upper layers of the stack. + */ +static void +dp83902a_recv(u8 *data, int len) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + int i, mlen; + u8 saved_char = 0; + bool saved; +#if DEBUG & 4 + int dx; +#endif + + DEBUG_FUNCTION(); + +#if DEBUG & 5 + printf("Rx packet %d length %d\n", dp->rx_next, len); +#endif + + /* Read incoming packet data */ + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); + DP_OUT(base, DP_RBCL, len & 0xFF); + DP_OUT(base, DP_RBCH, len >> 8); + DP_OUT(base, DP_RSAL, 4); /* Past header */ + DP_OUT(base, DP_RSAH, dp->rx_next); + DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ + DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); +#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA + CYGACC_CALL_IF_DELAY_US(10); +#endif + + saved = false; + for (i = 0; i < 1; i++) { + if (data) { + mlen = len; +#if DEBUG & 4 + printf(" sg buf %08lx len %08x \n", (u32) data, mlen); + dx = 0; +#endif + while (0 < mlen) { + /* Saved byte from previous loop? */ + if (saved) { + *data++ = saved_char; + mlen--; + saved = false; + continue; + } + + { + u8 tmp; + DP_IN_DATA(dp->data, tmp); +#if DEBUG & 4 + printf(" %02x", tmp); + if (0 == (++dx % 16)) printf("\n "); +#endif + *data++ = tmp;; + mlen--; + } + } +#if DEBUG & 4 + printf("\n"); +#endif + } + } +} + +static void +dp83902a_TxEvent(void) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + u8 tsr; + u32 key; + + DEBUG_FUNCTION(); + + DP_IN(base, DP_TSR, tsr); + if (dp->tx_int == 1) { + key = dp->tx1_key; + dp->tx1 = 0; + } else { + key = dp->tx2_key; + dp->tx2 = 0; + } + /* Start next packet if one is ready */ + dp->tx_started = false; + if (dp->tx1) { + dp83902a_start_xmit(dp->tx1, dp->tx1_len); + dp->tx_int = 1; + } else if (dp->tx2) { + dp83902a_start_xmit(dp->tx2, dp->tx2_len); + dp->tx_int = 2; + } else { + dp->tx_int = 0; + } + /* Tell higher level we sent this packet */ + uboot_push_tx_done(key, 0); +} + +/* + * Read the tally counters to clear them. Called in response to a CNT + * interrupt. + */ +static void +dp83902a_ClearCounters(void) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + u8 cnt1, cnt2, cnt3; + + DP_IN(base, DP_FER, cnt1); + DP_IN(base, DP_CER, cnt2); + DP_IN(base, DP_MISSED, cnt3); + DP_OUT(base, DP_ISR, DP_ISR_CNT); +} + +/* + * Deal with an overflow condition. This code follows the procedure set + * out in section 7.0 of the datasheet. + */ +static void +dp83902a_Overflow(void) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; + u8 *base = dp->base; + u8 isr; + + /* Issue a stop command and wait 1.6ms for it to complete. */ + DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); + CYGACC_CALL_IF_DELAY_US(1600); + + /* Clear the remote byte counter registers. */ + DP_OUT(base, DP_RBCL, 0); + DP_OUT(base, DP_RBCH, 0); + + /* Enter loopback mode while we clear the buffer. */ + DP_OUT(base, DP_TCR, DP_TCR_LOCAL); + DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); + + /* + * Read in as many packets as we can and acknowledge any and receive + * interrupts. Since the buffer has overflowed, a receive event of + * some kind will have occured. + */ + dp83902a_RxEvent(); + DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); + + /* Clear the overflow condition and leave loopback mode. */ + DP_OUT(base, DP_ISR, DP_ISR_OFLW); + DP_OUT(base, DP_TCR, DP_TCR_NORMAL); + + /* + * If a transmit command was issued, but no transmit event has occured, + * restart it here. + */ + DP_IN(base, DP_ISR, isr); + if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); + } +} + +static void +dp83902a_poll(void) +{ + struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; + u8 *base = dp->base; + u8 isr; + + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); + DP_IN(base, DP_ISR, isr); + while (0 != isr) { + /* + * The CNT interrupt triggers when the MSB of one of the error + * counters is set. We don't much care about these counters, but + * we should read their values to reset them. + */ + if (isr & DP_ISR_CNT) { + dp83902a_ClearCounters(); + } + /* + * Check for overflow. It's a special case, since there's a + * particular procedure that must be followed to get back into + * a running state.a + */ + if (isr & DP_ISR_OFLW) { + dp83902a_Overflow(); + } else { + /* + * Other kinds of interrupts can be acknowledged simply by + * clearing the relevant bits of the ISR. Do that now, then + * handle the interrupts we care about. + */ + DP_OUT(base, DP_ISR, isr); /* Clear set bits */ + if (!dp->running) break; /* Is this necessary? */ + /* + * Check for tx_started on TX event since these may happen + * spuriously it seems. + */ + if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { + dp83902a_TxEvent(); + } + if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { + dp83902a_RxEvent(); + } + } + DP_IN(base, DP_ISR, isr); + } +} + + +/* U-boot specific routines */ +static u8 *pbuf = NULL; + +static int pkey = -1; +static int initialized = 0; + +void uboot_push_packet_len(int len) { + PRINTK("pushed len = %d\n", len); + if (len >= 2000) { + printf("NE2000: packet too big\n"); + return; + } + dp83902a_recv(&pbuf[0], len); + + /*Just pass it to the upper layer*/ + NetReceive(&pbuf[0], len); +} + +void uboot_push_tx_done(int key, int val) { + PRINTK("pushed key = %d\n", key); + pkey = key; +} + +int eth_init(bd_t *bd) { + int r; + u8 dev_addr[6]; + char ethaddr[20]; + + PRINTK("### eth_init\n"); + + if (!pbuf) { + pbuf = malloc(2000); + if (!pbuf) { + printf("Cannot allocate rx buffer\n"); + return -1; + } + } + +#ifdef CONFIG_DRIVER_NE2000_CCR + { + vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; + + PRINTK("CCR before is %x\n", *p); + *p = CONFIG_DRIVER_NE2000_VAL; + PRINTK("CCR after is %x\n", *p); + } +#endif + + nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; + + r = get_prom(dev_addr, nic.base); + if (!r) + return -1; + + sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", + dev_addr[0], dev_addr[1], + dev_addr[2], dev_addr[3], + dev_addr[4], dev_addr[5]) ; + PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); + setenv ("ethaddr", ethaddr); + + nic.data = nic.base + DP_DATA; + nic.tx_buf1 = START_PG; + nic.tx_buf2 = START_PG2; + nic.rx_buf_start = RX_START; + nic.rx_buf_end = RX_END; + + if (dp83902a_init() == false) + return -1; + + dp83902a_start(dev_addr); + initialized = 1; + + return 0; +} + +void eth_halt() { + + PRINTK("### eth_halt\n"); + if(initialized) + dp83902a_stop(); + initialized = 0; +} + +int eth_rx() { + dp83902a_poll(); + return 1; +} + +int eth_send(volatile void *packet, int length) { + int tmo; + + PRINTK("### eth_send\n"); + + pkey = -1; + + dp83902a_send((u8 *) packet, length, 666); + tmo = get_timer (0) + TOUT * CFG_HZ; + while(1) { + dp83902a_poll(); + if (pkey != -1) { + PRINTK("Packet sucesfully sent\n"); + return 0; + } + if (get_timer (0) >= tmo) { + printf("transmission error (timoeut)\n"); + return 0; + } + + } + return 0; +} diff --git a/drivers/net/ne2000_base.h b/drivers/net/ne2000_base.h index 948b290..5446de4 100644 --- a/drivers/net/ne2000_base.h +++ b/drivers/net/ne2000_base.h @@ -80,10 +80,35 @@ are GPL, so this is, of course, GPL. #define __NE2000_BASE_H__ #define bool int - #define false 0 #define true 1 +/* + * Debugging details + * + * Set to perms of: + * 0 disables all debug output + * 1 for process debug output + * 2 for added data IO output: get_reg, put_reg + * 4 for packet allocation/free output + * 8 for only startup status, so we can tell we're installed OK + */ +#if 0 +#define DEBUG 0xf +#else +#define DEBUG 0 +#endif + +#if DEBUG & 1 +#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0) +#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0) +#define PRINTK(args...) printf(args) +#else +#define DEBUG_FUNCTION() do {} while(0) +#define DEBUG_LINE() do {} while(0) +#define PRINTK(args...) +#endif + /* timeout for tx/rx in s */ #define TOUT 5 /* Ether MAC address size */ @@ -119,11 +144,6 @@ typedef struct dp83902a_priv_data { int rx_buf_start, rx_buf_end; } dp83902a_priv_data_t; -/* - * Some forward declarations - */ -static void dp83902a_poll(void); - /* ------------------------------------------------------------------------ */ /* Register offsets */ @@ -281,4 +301,8 @@ static void dp83902a_poll(void); #define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */ #define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */ + +/* Functions */ +int get_prom(u8* mac_addr, u8* base_addr); + #endif /* __NE2000_BASE_H__ */ diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 8ab6d07..e34076f 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -1366,6 +1366,8 @@ struct phy_info phy_info_VSC8601 = { {MIIM_EXT_PAGE_ACCESS,0,NULL}, #endif #endif + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init}, {miim_end,} }, (struct phy_cmd[]){ /* startup */ |