diff options
| author | Louis Su <louis@asix.com.tw> | 2008-07-09 11:01:37 +0800 | 
|---|---|---|
| committer | Ben Warren <biggerbadderben@gmail.com> | 2008-10-13 22:33:12 -0700 | 
| commit | 30f574717277238b9014b8136c90eea77196490f (patch) | |
| tree | de9f2d24d9f573a6bce340cff12ba830e9726b44 /drivers/net/ax88180.c | |
| parent | c9d6b6925344740ca1db2f8a6bab7921ff820de3 (diff) | |
| download | olio-uboot-2014.01-30f574717277238b9014b8136c90eea77196490f.tar.xz olio-uboot-2014.01-30f574717277238b9014b8136c90eea77196490f.zip | |
AX88180: new gigabit network driver
Signed-off-by: Louis Su <louis@asix.com.tw>
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
Diffstat (limited to 'drivers/net/ax88180.c')
| -rw-r--r-- | drivers/net/ax88180.c | 727 | 
1 files changed, 727 insertions, 0 deletions
| diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c new file mode 100644 index 000000000..d843397f3 --- /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); + +} |