xref: /openbmc/u-boot/drivers/net/ax88180.c (revision 4f892924)
130f57471SLouis Su /*
230f57471SLouis Su  * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
330f57471SLouis Su  *
430f57471SLouis Su  * This program is free software; you can distribute it and/or modify
530f57471SLouis Su  * it under the terms of the GNU General Public License (Version 2) as
630f57471SLouis Su  * published by the Free Software Foundation.
730f57471SLouis Su  * This program is distributed in the hope it will be useful, but
830f57471SLouis Su  * WITHOUT ANY WARRANTY; without even the implied warranty of
930f57471SLouis Su  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1030f57471SLouis Su  * See the GNU General Public License for more details.
1130f57471SLouis Su  * You should have received a copy of the GNU General Public License
1230f57471SLouis Su  * along with this program; if not, write to the Free Software
1330f57471SLouis Su  * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
1430f57471SLouis Su  * USA.
1530f57471SLouis Su  */
1630f57471SLouis Su 
1730f57471SLouis Su /*
1830f57471SLouis Su  * ========================================================================
1930f57471SLouis Su  * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
2030f57471SLouis Su  *
2130f57471SLouis Su  * The AX88180 Ethernet controller is a high performance and highly
2230f57471SLouis Su  * integrated local CPU bus Ethernet controller with embedded 40K bytes
2330f57471SLouis Su  * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
2430f57471SLouis Su  * embedded systems.
2530f57471SLouis Su  * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
2630f57471SLouis Su  * controller that supports both MII and RGMII interfaces and is
2730f57471SLouis Su  * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
2830f57471SLouis Su  *
2930f57471SLouis Su  * Please visit ASIX's web site (http://www.asix.com.tw) for more
3030f57471SLouis Su  * details.
3130f57471SLouis Su  *
3230f57471SLouis Su  * Module Name	: ax88180.c
3330f57471SLouis Su  * Date		: 2008-07-07
3430f57471SLouis Su  * History
3530f57471SLouis Su  * 09/06/2006	: New release for AX88180 US2 chip.
3630f57471SLouis Su  * 07/07/2008	: Fix up the coding style and using inline functions
3730f57471SLouis Su  *		  instead of macros
3830f57471SLouis Su  * ========================================================================
3930f57471SLouis Su  */
4030f57471SLouis Su #include <common.h>
4130f57471SLouis Su #include <command.h>
4230f57471SLouis Su #include <net.h>
4330f57471SLouis Su #include <malloc.h>
44f9abdfe0SMike Frysinger #include <linux/mii.h>
4530f57471SLouis Su #include "ax88180.h"
4630f57471SLouis Su 
4730f57471SLouis Su /*
4830f57471SLouis Su  * ===========================================================================
4930f57471SLouis Su  * Local SubProgram Declaration
5030f57471SLouis Su  * ===========================================================================
5130f57471SLouis Su  */
5230f57471SLouis Su static void ax88180_rx_handler (struct eth_device *dev);
5330f57471SLouis Su static int ax88180_phy_initial (struct eth_device *dev);
54bb7336a4SHoan Hoang static void ax88180_media_config (struct eth_device *dev);
55bb7336a4SHoan Hoang static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev);
56bb7336a4SHoan Hoang static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev);
5730f57471SLouis Su static unsigned short ax88180_mdio_read (struct eth_device *dev,
5830f57471SLouis Su 					 unsigned long regaddr);
5930f57471SLouis Su static void ax88180_mdio_write (struct eth_device *dev,
6030f57471SLouis Su 				unsigned long regaddr, unsigned short regdata);
6130f57471SLouis Su 
6230f57471SLouis Su /*
6330f57471SLouis Su  * ===========================================================================
6430f57471SLouis Su  * Local SubProgram Bodies
6530f57471SLouis Su  * ===========================================================================
6630f57471SLouis Su  */
ax88180_mdio_check_complete(struct eth_device * dev)6730f57471SLouis Su static int ax88180_mdio_check_complete (struct eth_device *dev)
6830f57471SLouis Su {
6930f57471SLouis Su 	int us_cnt = 10000;
7030f57471SLouis Su 	unsigned short tmpval;
7130f57471SLouis Su 
7230f57471SLouis Su 	/* MDIO read/write should not take more than 10 ms */
7330f57471SLouis Su 	while (--us_cnt) {
7430f57471SLouis Su 		tmpval = INW (dev, MDIOCTRL);
7530f57471SLouis Su 		if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
7630f57471SLouis Su 			break;
7730f57471SLouis Su 	}
7830f57471SLouis Su 
7930f57471SLouis Su 	return us_cnt;
8030f57471SLouis Su }
8130f57471SLouis Su 
8230f57471SLouis Su static unsigned short
ax88180_mdio_read(struct eth_device * dev,unsigned long regaddr)8330f57471SLouis Su ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
8430f57471SLouis Su {
8530f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
8630f57471SLouis Su 	unsigned long tmpval = 0;
8730f57471SLouis Su 
8830f57471SLouis Su 	OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
8930f57471SLouis Su 
9030f57471SLouis Su 	if (ax88180_mdio_check_complete (dev))
9130f57471SLouis Su 		tmpval = INW (dev, MDIODP);
9230f57471SLouis Su 	else
9330f57471SLouis Su 		printf ("Failed to read PHY register!\n");
9430f57471SLouis Su 
9530f57471SLouis Su 	return (unsigned short)(tmpval & 0xFFFF);
9630f57471SLouis Su }
9730f57471SLouis Su 
9830f57471SLouis Su static void
ax88180_mdio_write(struct eth_device * dev,unsigned long regaddr,unsigned short regdata)9930f57471SLouis Su ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
10030f57471SLouis Su 		    unsigned short regdata)
10130f57471SLouis Su {
10230f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
10330f57471SLouis Su 
10430f57471SLouis Su 	OUTW (dev, regdata, MDIODP);
10530f57471SLouis Su 
10630f57471SLouis Su 	OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
10730f57471SLouis Su 
10830f57471SLouis Su 	if (!ax88180_mdio_check_complete (dev))
10930f57471SLouis Su 		printf ("Failed to write PHY register!\n");
11030f57471SLouis Su }
11130f57471SLouis Su 
ax88180_phy_reset(struct eth_device * dev)11230f57471SLouis Su static int ax88180_phy_reset (struct eth_device *dev)
11330f57471SLouis Su {
11430f57471SLouis Su 	unsigned short delay_cnt = 500;
11530f57471SLouis Su 
116f9abdfe0SMike Frysinger 	ax88180_mdio_write (dev, MII_BMCR, (BMCR_RESET | BMCR_ANENABLE));
11730f57471SLouis Su 
11830f57471SLouis Su 	/* Wait for the reset to complete, or time out (500 ms) */
119f9abdfe0SMike Frysinger 	while (ax88180_mdio_read (dev, MII_BMCR) & BMCR_RESET) {
12030f57471SLouis Su 		udelay (1000);
12130f57471SLouis Su 		if (--delay_cnt == 0) {
12230f57471SLouis Su 			printf ("Failed to reset PHY!\n");
12330f57471SLouis Su 			return -1;
12430f57471SLouis Su 		}
12530f57471SLouis Su 	}
12630f57471SLouis Su 
12730f57471SLouis Su 	return 0;
12830f57471SLouis Su }
12930f57471SLouis Su 
ax88180_mac_reset(struct eth_device * dev)13030f57471SLouis Su static void ax88180_mac_reset (struct eth_device *dev)
13130f57471SLouis Su {
13230f57471SLouis Su 	unsigned long tmpval;
13330f57471SLouis Su 	unsigned char i;
13430f57471SLouis Su 
13530f57471SLouis Su 	struct {
13630f57471SLouis Su 		unsigned short offset, value;
13730f57471SLouis Su 	} program_seq[] = {
13830f57471SLouis Su 		{
13930f57471SLouis Su 		MISC, MISC_NORMAL}, {
14030f57471SLouis Su 		RXINDICATOR, DEFAULT_RXINDICATOR}, {
14130f57471SLouis Su 		TXCMD, DEFAULT_TXCMD}, {
14230f57471SLouis Su 		TXBS, DEFAULT_TXBS}, {
14330f57471SLouis Su 		TXDES0, DEFAULT_TXDES0}, {
14430f57471SLouis Su 		TXDES1, DEFAULT_TXDES1}, {
14530f57471SLouis Su 		TXDES2, DEFAULT_TXDES2}, {
14630f57471SLouis Su 		TXDES3, DEFAULT_TXDES3}, {
14730f57471SLouis Su 		TXCFG, DEFAULT_TXCFG}, {
14830f57471SLouis Su 		MACCFG2, DEFAULT_MACCFG2}, {
14930f57471SLouis Su 		MACCFG3, DEFAULT_MACCFG3}, {
15030f57471SLouis Su 		TXLEN, DEFAULT_TXLEN}, {
15130f57471SLouis Su 		RXBTHD0, DEFAULT_RXBTHD0}, {
15230f57471SLouis Su 		RXBTHD1, DEFAULT_RXBTHD1}, {
15330f57471SLouis Su 		RXFULTHD, DEFAULT_RXFULTHD}, {
15430f57471SLouis Su 		DOGTHD0, DEFAULT_DOGTHD0}, {
15530f57471SLouis Su 	DOGTHD1, DEFAULT_DOGTHD1},};
15630f57471SLouis Su 
15730f57471SLouis Su 	OUTW (dev, MISC_RESET_MAC, MISC);
15830f57471SLouis Su 	tmpval = INW (dev, MISC);
15930f57471SLouis Su 
160a62cd29cSAxel Lin 	for (i = 0; i < ARRAY_SIZE(program_seq); i++)
16130f57471SLouis Su 		OUTW (dev, program_seq[i].value, program_seq[i].offset);
16230f57471SLouis Su }
16330f57471SLouis Su 
ax88180_poll_tx_complete(struct eth_device * dev)16430f57471SLouis Su static int ax88180_poll_tx_complete (struct eth_device *dev)
16530f57471SLouis Su {
16630f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
16730f57471SLouis Su 	unsigned long tmpval, txbs_txdp;
16830f57471SLouis Su 	int TimeOutCnt = 10000;
16930f57471SLouis Su 
17030f57471SLouis Su 	txbs_txdp = 1 << priv->NextTxDesc;
17130f57471SLouis Su 
17230f57471SLouis Su 	while (TimeOutCnt--) {
17330f57471SLouis Su 
17430f57471SLouis Su 		tmpval = INW (dev, TXBS);
17530f57471SLouis Su 
17630f57471SLouis Su 		if ((tmpval & txbs_txdp) == 0)
17730f57471SLouis Su 			break;
17830f57471SLouis Su 
17930f57471SLouis Su 		udelay (100);
18030f57471SLouis Su 	}
18130f57471SLouis Su 
18230f57471SLouis Su 	if (TimeOutCnt)
18330f57471SLouis Su 		return 0;
18430f57471SLouis Su 	else
18530f57471SLouis Su 		return -TimeOutCnt;
18630f57471SLouis Su }
18730f57471SLouis Su 
ax88180_rx_handler(struct eth_device * dev)18830f57471SLouis Su static void ax88180_rx_handler (struct eth_device *dev)
18930f57471SLouis Su {
19030f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
19130f57471SLouis Su 	unsigned long data_size;
19230f57471SLouis Su 	unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
19330f57471SLouis Su 	int i;
19430f57471SLouis Su #if defined (CONFIG_DRIVER_AX88180_16BIT)
1951fd92db8SJoe Hershberger 	unsigned short *rxdata = (unsigned short *)net_rx_packets[0];
19630f57471SLouis Su #else
1971fd92db8SJoe Hershberger 	unsigned long *rxdata = (unsigned long *)net_rx_packets[0];
19830f57471SLouis Su #endif
19930f57471SLouis Su 	unsigned short count;
20030f57471SLouis Su 
20130f57471SLouis Su 	rxcurt_ptr = INW (dev, RXCURT);
20230f57471SLouis Su 	rxbound_ptr = INW (dev, RXBOUND);
20330f57471SLouis Su 	next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
20430f57471SLouis Su 
20530f57471SLouis Su 	debug ("ax88180: RX original RXBOUND=0x%04x,"
20630f57471SLouis Su 	       " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
20730f57471SLouis Su 
20830f57471SLouis Su 	while (next_ptr != rxcurt_ptr) {
20930f57471SLouis Su 
21030f57471SLouis Su 		OUTW (dev, RX_START_READ, RXINDICATOR);
21130f57471SLouis Su 
21230f57471SLouis Su 		data_size = READ_RXBUF (dev) & 0xFFFF;
21330f57471SLouis Su 
21430f57471SLouis Su 		if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
21530f57471SLouis Su 
21630f57471SLouis Su 			OUTW (dev, RX_STOP_READ, RXINDICATOR);
21730f57471SLouis Su 
21830f57471SLouis Su 			ax88180_mac_reset (dev);
21930f57471SLouis Su 			printf ("ax88180: Invalid Rx packet length!"
22030f57471SLouis Su 				" (len=0x%04lx)\n", data_size);
22130f57471SLouis Su 
22230f57471SLouis Su 			debug ("ax88180: RX RXBOUND=0x%04x,"
22330f57471SLouis Su 			       "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
22430f57471SLouis Su 			return;
22530f57471SLouis Su 		}
22630f57471SLouis Su 
22730f57471SLouis Su 		rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
22830f57471SLouis Su 		rxbound_ptr &= RX_PAGE_NUM_MASK;
22930f57471SLouis Su 
23030f57471SLouis Su 		/* Comput access times */
23130f57471SLouis Su 		count = (data_size + priv->PadSize) >> priv->BusWidth;
23230f57471SLouis Su 
23330f57471SLouis Su 		for (i = 0; i < count; i++) {
23430f57471SLouis Su 			*(rxdata + i) = READ_RXBUF (dev);
23530f57471SLouis Su 		}
23630f57471SLouis Su 
23730f57471SLouis Su 		OUTW (dev, RX_STOP_READ, RXINDICATOR);
23830f57471SLouis Su 
23930f57471SLouis Su 		/* Pass the packet up to the protocol layers. */
2401fd92db8SJoe Hershberger 		net_process_received_packet(net_rx_packets[0], data_size);
24130f57471SLouis Su 
24230f57471SLouis Su 		OUTW (dev, rxbound_ptr, RXBOUND);
24330f57471SLouis Su 
24430f57471SLouis Su 		rxcurt_ptr = INW (dev, RXCURT);
24530f57471SLouis Su 		rxbound_ptr = INW (dev, RXBOUND);
24630f57471SLouis Su 		next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
24730f57471SLouis Su 
24830f57471SLouis Su 		debug ("ax88180: RX updated RXBOUND=0x%04x,"
24930f57471SLouis Su 		       "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
25030f57471SLouis Su 	}
25130f57471SLouis Su 
25230f57471SLouis Su 	return;
25330f57471SLouis Su }
25430f57471SLouis Su 
ax88180_phy_initial(struct eth_device * dev)25530f57471SLouis Su static int ax88180_phy_initial (struct eth_device *dev)
25630f57471SLouis Su {
25730f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
25830f57471SLouis Su 	unsigned long tmp_regval;
259141ab7a5SMike Frysinger 	unsigned short phyaddr;
26030f57471SLouis Su 
261141ab7a5SMike Frysinger 	/* Search for first avaliable PHY chipset */
262141ab7a5SMike Frysinger #ifdef CONFIG_PHY_ADDR
263141ab7a5SMike Frysinger 	phyaddr = CONFIG_PHY_ADDR;
264141ab7a5SMike Frysinger #else
265141ab7a5SMike Frysinger 	for (phyaddr = 0; phyaddr < 32; ++phyaddr)
266141ab7a5SMike Frysinger #endif
267141ab7a5SMike Frysinger 	{
268141ab7a5SMike Frysinger 		priv->PhyAddr = phyaddr;
269f9abdfe0SMike Frysinger 		priv->PhyID0 = ax88180_mdio_read(dev, MII_PHYSID1);
27025667068SHoan Hoang 		priv->PhyID1 = ax88180_mdio_read(dev, MII_PHYSID2);
27130f57471SLouis Su 
272141ab7a5SMike Frysinger 		switch (priv->PhyID0) {
27325667068SHoan Hoang 		case MARVELL_ALASKA_PHYSID0:
27425667068SHoan Hoang 			debug("ax88180: Found Marvell Alaska PHY family."
27530f57471SLouis Su 			      " (PHY Addr=0x%x)\n", priv->PhyAddr);
27630f57471SLouis Su 
27725667068SHoan Hoang 			switch (priv->PhyID1) {
27825667068SHoan Hoang 			case MARVELL_88E1118_PHYSID1:
27925667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 2);
28025667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_CR,
28125667068SHoan Hoang 					M88E1118_CR_DEFAULT);
28225667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 3);
28325667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_LEDCTL,
28425667068SHoan Hoang 					M88E1118_LEDCTL_DEFAULT);
28525667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_LEDMIX,
28625667068SHoan Hoang 					M88E1118_LEDMIX_LED050 | M88E1118_LEDMIX_LED150 | 0x15);
28725667068SHoan Hoang 				ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 0);
28825667068SHoan Hoang 			default: /* Default to 88E1111 Phy */
28925667068SHoan Hoang 				tmp_regval = ax88180_mdio_read(dev, M88E1111_EXT_SSR);
29025667068SHoan Hoang 				if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE)
29125667068SHoan Hoang 					ax88180_mdio_write(dev, M88E1111_EXT_SCR,
29225667068SHoan Hoang 						DEFAULT_EXT_SCR);
29325667068SHoan Hoang 			}
29425667068SHoan Hoang 
29530f57471SLouis Su 			if (ax88180_phy_reset(dev) < 0)
29630f57471SLouis Su 				return 0;
29730f57471SLouis Su 			ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT);
29830f57471SLouis Su 
299141ab7a5SMike Frysinger 			return 1;
30030f57471SLouis Su 
301f9abdfe0SMike Frysinger 		case CICADA_CIS8201_PHYSID0:
30230f57471SLouis Su 			debug("ax88180: Found CICADA CIS8201 PHY"
30330f57471SLouis Su 			      " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
304141ab7a5SMike Frysinger 
30530f57471SLouis Su 			ax88180_mdio_write(dev, CIS_IMR,
30630f57471SLouis Su 					    (CIS_INT_ENABLE | LINK_CHANGE_INT));
30730f57471SLouis Su 
30830f57471SLouis Su 			/* Set CIS_SMI_PRIORITY bit before force the media mode */
309141ab7a5SMike Frysinger 			tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS);
31030f57471SLouis Su 			tmp_regval &= ~CIS_SMI_PRIORITY;
311141ab7a5SMike Frysinger 			ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval);
312141ab7a5SMike Frysinger 
313141ab7a5SMike Frysinger 			return 1;
314141ab7a5SMike Frysinger 
315141ab7a5SMike Frysinger 		case 0xffff:
316141ab7a5SMike Frysinger 			/* No PHY at this addr */
317141ab7a5SMike Frysinger 			break;
318141ab7a5SMike Frysinger 
319141ab7a5SMike Frysinger 		default:
320141ab7a5SMike Frysinger 			printf("ax88180: Unknown PHY chipset %#x at addr %#x\n",
321141ab7a5SMike Frysinger 			       priv->PhyID0, priv->PhyAddr);
322141ab7a5SMike Frysinger 			break;
32330f57471SLouis Su 		}
32430f57471SLouis Su 	}
32530f57471SLouis Su 
326141ab7a5SMike Frysinger 	printf("ax88180: Unknown PHY chipset!!\n");
327141ab7a5SMike Frysinger 	return 0;
32830f57471SLouis Su }
32930f57471SLouis Su 
ax88180_media_config(struct eth_device * dev)330bb7336a4SHoan Hoang static void ax88180_media_config (struct eth_device *dev)
33130f57471SLouis Su {
33230f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
33330f57471SLouis Su 	unsigned long bmcr_val, bmsr_val;
33430f57471SLouis Su 	unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
33530f57471SLouis Su 	unsigned long RealMediaMode;
33630f57471SLouis Su 	int i;
33730f57471SLouis Su 
33830f57471SLouis Su 	/* Waiting 2 seconds for PHY link stable */
33930f57471SLouis Su 	for (i = 0; i < 20000; i++) {
340f9abdfe0SMike Frysinger 		bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
341f9abdfe0SMike Frysinger 		if (bmsr_val & BMSR_LSTATUS) {
34230f57471SLouis Su 			break;
34330f57471SLouis Su 		}
34430f57471SLouis Su 		udelay (100);
34530f57471SLouis Su 	}
34630f57471SLouis Su 
347f9abdfe0SMike Frysinger 	bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
34830f57471SLouis Su 	debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
34930f57471SLouis Su 
350f9abdfe0SMike Frysinger 	if (bmsr_val & BMSR_LSTATUS) {
351f9abdfe0SMike Frysinger 		bmcr_val = ax88180_mdio_read (dev, MII_BMCR);
35230f57471SLouis Su 
353f9abdfe0SMike Frysinger 		if (bmcr_val & BMCR_ANENABLE) {
35430f57471SLouis Su 
35530f57471SLouis Su 			/*
35630f57471SLouis Su 			 * Waiting for Auto-negotiation completion, this may
35730f57471SLouis Su 			 * take up to 5 seconds.
35830f57471SLouis Su 			 */
35930f57471SLouis Su 			debug ("ax88180: Auto-negotiation is "
36030f57471SLouis Su 			       "enabled. Waiting for NWay completion..\n");
36130f57471SLouis Su 			for (i = 0; i < 50000; i++) {
362f9abdfe0SMike Frysinger 				bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
363f9abdfe0SMike Frysinger 				if (bmsr_val & BMSR_ANEGCOMPLETE) {
36430f57471SLouis Su 					break;
36530f57471SLouis Su 				}
36630f57471SLouis Su 				udelay (100);
36730f57471SLouis Su 			}
36830f57471SLouis Su 		} else
36930f57471SLouis Su 			debug ("ax88180: Auto-negotiation is disabled.\n");
37030f57471SLouis Su 
37130f57471SLouis Su 		debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
37230f57471SLouis Su 		       (unsigned int)bmcr_val, (unsigned int)bmsr_val);
37330f57471SLouis Su 
37430f57471SLouis Su 		/* Get real media mode here */
375141ab7a5SMike Frysinger 		switch (priv->PhyID0) {
37625667068SHoan Hoang 		case MARVELL_ALASKA_PHYSID0:
377bb7336a4SHoan Hoang 			RealMediaMode = get_MarvellPHY_media_mode(dev);
378141ab7a5SMike Frysinger 			break;
379f9abdfe0SMike Frysinger 		case CICADA_CIS8201_PHYSID0:
380bb7336a4SHoan Hoang 			RealMediaMode = get_CicadaPHY_media_mode(dev);
381141ab7a5SMike Frysinger 			break;
382141ab7a5SMike Frysinger 		default:
38330f57471SLouis Su 			RealMediaMode = MEDIA_1000FULL;
384141ab7a5SMike Frysinger 			break;
38530f57471SLouis Su 		}
38630f57471SLouis Su 
38730f57471SLouis Su 		priv->LinkState = INS_LINK_UP;
38830f57471SLouis Su 
38930f57471SLouis Su 		switch (RealMediaMode) {
39030f57471SLouis Su 		case MEDIA_1000FULL:
39130f57471SLouis Su 			debug ("ax88180: 1000Mbps Full-duplex mode.\n");
39230f57471SLouis Su 			rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
39330f57471SLouis Su 			maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
39430f57471SLouis Su 			maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
39530f57471SLouis Su 			    FULLDUPLEX | DEFAULT_MACCFG1;
39630f57471SLouis Su 			break;
39730f57471SLouis Su 
39830f57471SLouis Su 		case MEDIA_1000HALF:
39930f57471SLouis Su 			debug ("ax88180: 1000Mbps Half-duplex mode.\n");
40030f57471SLouis Su 			rxcfg_val = DEFAULT_RXCFG;
40130f57471SLouis Su 			maccfg0_val = DEFAULT_MACCFG0;
40230f57471SLouis Su 			maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
40330f57471SLouis Su 			break;
40430f57471SLouis Su 
40530f57471SLouis Su 		case MEDIA_100FULL:
40630f57471SLouis Su 			debug ("ax88180: 100Mbps Full-duplex mode.\n");
40730f57471SLouis Su 			rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
40830f57471SLouis Su 			maccfg0_val = SPEED100 | TXFLOW_ENABLE
40930f57471SLouis Su 			    | DEFAULT_MACCFG0;
41030f57471SLouis Su 			maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
41130f57471SLouis Su 			break;
41230f57471SLouis Su 
41330f57471SLouis Su 		case MEDIA_100HALF:
41430f57471SLouis Su 			debug ("ax88180: 100Mbps Half-duplex mode.\n");
41530f57471SLouis Su 			rxcfg_val = DEFAULT_RXCFG;
41630f57471SLouis Su 			maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
41730f57471SLouis Su 			maccfg1_val = DEFAULT_MACCFG1;
41830f57471SLouis Su 			break;
41930f57471SLouis Su 
42030f57471SLouis Su 		case MEDIA_10FULL:
42130f57471SLouis Su 			debug ("ax88180: 10Mbps Full-duplex mode.\n");
42230f57471SLouis Su 			rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
42330f57471SLouis Su 			maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
42430f57471SLouis Su 			maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
42530f57471SLouis Su 			break;
42630f57471SLouis Su 
42730f57471SLouis Su 		case MEDIA_10HALF:
42830f57471SLouis Su 			debug ("ax88180: 10Mbps Half-duplex mode.\n");
42930f57471SLouis Su 			rxcfg_val = DEFAULT_RXCFG;
43030f57471SLouis Su 			maccfg0_val = DEFAULT_MACCFG0;
43130f57471SLouis Su 			maccfg1_val = DEFAULT_MACCFG1;
43230f57471SLouis Su 			break;
43330f57471SLouis Su 		default:
43430f57471SLouis Su 			debug ("ax88180: Unknow media mode.\n");
43530f57471SLouis Su 			rxcfg_val = DEFAULT_RXCFG;
43630f57471SLouis Su 			maccfg0_val = DEFAULT_MACCFG0;
43730f57471SLouis Su 			maccfg1_val = DEFAULT_MACCFG1;
43830f57471SLouis Su 
43930f57471SLouis Su 			priv->LinkState = INS_LINK_DOWN;
44030f57471SLouis Su 			break;
44130f57471SLouis Su 		}
44230f57471SLouis Su 
44330f57471SLouis Su 	} else {
44430f57471SLouis Su 		rxcfg_val = DEFAULT_RXCFG;
44530f57471SLouis Su 		maccfg0_val = DEFAULT_MACCFG0;
44630f57471SLouis Su 		maccfg1_val = DEFAULT_MACCFG1;
44730f57471SLouis Su 
44830f57471SLouis Su 		priv->LinkState = INS_LINK_DOWN;
44930f57471SLouis Su 	}
45030f57471SLouis Su 
45130f57471SLouis Su 	OUTW (dev, rxcfg_val, RXCFG);
45230f57471SLouis Su 	OUTW (dev, maccfg0_val, MACCFG0);
45330f57471SLouis Su 	OUTW (dev, maccfg1_val, MACCFG1);
45430f57471SLouis Su 
45530f57471SLouis Su 	return;
45630f57471SLouis Su }
45730f57471SLouis Su 
get_MarvellPHY_media_mode(struct eth_device * dev)458bb7336a4SHoan Hoang static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev)
45930f57471SLouis Su {
46030f57471SLouis Su 	unsigned long m88_ssr;
46130f57471SLouis Su 	unsigned long MediaMode;
46230f57471SLouis Su 
46330f57471SLouis Su 	m88_ssr = ax88180_mdio_read (dev, M88_SSR);
46430f57471SLouis Su 	switch (m88_ssr & SSR_MEDIA_MASK) {
46530f57471SLouis Su 	case SSR_1000FULL:
46630f57471SLouis Su 		MediaMode = MEDIA_1000FULL;
46730f57471SLouis Su 		break;
46830f57471SLouis Su 	case SSR_1000HALF:
46930f57471SLouis Su 		MediaMode = MEDIA_1000HALF;
47030f57471SLouis Su 		break;
47130f57471SLouis Su 	case SSR_100FULL:
47230f57471SLouis Su 		MediaMode = MEDIA_100FULL;
47330f57471SLouis Su 		break;
47430f57471SLouis Su 	case SSR_100HALF:
47530f57471SLouis Su 		MediaMode = MEDIA_100HALF;
47630f57471SLouis Su 		break;
47730f57471SLouis Su 	case SSR_10FULL:
47830f57471SLouis Su 		MediaMode = MEDIA_10FULL;
47930f57471SLouis Su 		break;
48030f57471SLouis Su 	case SSR_10HALF:
48130f57471SLouis Su 		MediaMode = MEDIA_10HALF;
48230f57471SLouis Su 		break;
48330f57471SLouis Su 	default:
48430f57471SLouis Su 		MediaMode = MEDIA_UNKNOWN;
48530f57471SLouis Su 		break;
48630f57471SLouis Su 	}
48730f57471SLouis Su 
48830f57471SLouis Su 	return MediaMode;
48930f57471SLouis Su }
49030f57471SLouis Su 
get_CicadaPHY_media_mode(struct eth_device * dev)491bb7336a4SHoan Hoang static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev)
49230f57471SLouis Su {
49330f57471SLouis Su 	unsigned long tmp_regval;
49430f57471SLouis Su 	unsigned long MediaMode;
49530f57471SLouis Su 
49630f57471SLouis Su 	tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
49730f57471SLouis Su 	switch (tmp_regval & CIS_MEDIA_MASK) {
49830f57471SLouis Su 	case CIS_1000FULL:
49930f57471SLouis Su 		MediaMode = MEDIA_1000FULL;
50030f57471SLouis Su 		break;
50130f57471SLouis Su 	case CIS_1000HALF:
50230f57471SLouis Su 		MediaMode = MEDIA_1000HALF;
50330f57471SLouis Su 		break;
50430f57471SLouis Su 	case CIS_100FULL:
50530f57471SLouis Su 		MediaMode = MEDIA_100FULL;
50630f57471SLouis Su 		break;
50730f57471SLouis Su 	case CIS_100HALF:
50830f57471SLouis Su 		MediaMode = MEDIA_100HALF;
50930f57471SLouis Su 		break;
51030f57471SLouis Su 	case CIS_10FULL:
51130f57471SLouis Su 		MediaMode = MEDIA_10FULL;
51230f57471SLouis Su 		break;
51330f57471SLouis Su 	case CIS_10HALF:
51430f57471SLouis Su 		MediaMode = MEDIA_10HALF;
51530f57471SLouis Su 		break;
51630f57471SLouis Su 	default:
51730f57471SLouis Su 		MediaMode = MEDIA_UNKNOWN;
51830f57471SLouis Su 		break;
51930f57471SLouis Su 	}
52030f57471SLouis Su 
52130f57471SLouis Su 	return MediaMode;
52230f57471SLouis Su }
52330f57471SLouis Su 
ax88180_halt(struct eth_device * dev)52430f57471SLouis Su static void ax88180_halt (struct eth_device *dev)
52530f57471SLouis Su {
52630f57471SLouis Su 	/* Disable AX88180 TX/RX functions */
52730f57471SLouis Su 	OUTW (dev, WAKEMOD, CMD);
52830f57471SLouis Su }
52930f57471SLouis Su 
ax88180_init(struct eth_device * dev,bd_t * bd)53030f57471SLouis Su static int ax88180_init (struct eth_device *dev, bd_t * bd)
53130f57471SLouis Su {
53230f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
53330f57471SLouis Su 	unsigned short tmp_regval;
53430f57471SLouis Su 
53530f57471SLouis Su 	ax88180_mac_reset (dev);
53630f57471SLouis Su 
53730f57471SLouis Su 	/* Disable interrupt */
53830f57471SLouis Su 	OUTW (dev, CLEAR_IMR, IMR);
53930f57471SLouis Su 
54030f57471SLouis Su 	/* Disable AX88180 TX/RX functions */
54130f57471SLouis Su 	OUTW (dev, WAKEMOD, CMD);
54230f57471SLouis Su 
54330f57471SLouis Su 	/* Fill the MAC address */
54430f57471SLouis Su 	tmp_regval =
54530f57471SLouis Su 	    dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
54630f57471SLouis Su 	OUTW (dev, tmp_regval, MACID0);
54730f57471SLouis Su 
54830f57471SLouis Su 	tmp_regval =
54930f57471SLouis Su 	    dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
55030f57471SLouis Su 	OUTW (dev, tmp_regval, MACID1);
55130f57471SLouis Su 
55230f57471SLouis Su 	tmp_regval =
55330f57471SLouis Su 	    dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
55430f57471SLouis Su 	OUTW (dev, tmp_regval, MACID2);
55530f57471SLouis Su 
556bb7336a4SHoan Hoang 	ax88180_media_config (dev);
55730f57471SLouis Su 
55830f57471SLouis Su 	OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
55930f57471SLouis Su 
56030f57471SLouis Su 	/* Initial variables here */
56130f57471SLouis Su 	priv->FirstTxDesc = TXDP0;
56230f57471SLouis Su 	priv->NextTxDesc = TXDP0;
56330f57471SLouis Su 
56430f57471SLouis Su 	/* Check if there is any invalid interrupt status and clear it. */
56530f57471SLouis Su 	OUTW (dev, INW (dev, ISR), ISR);
56630f57471SLouis Su 
56730f57471SLouis Su 	/* Start AX88180 TX/RX functions */
56830f57471SLouis Su 	OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
56930f57471SLouis Su 
57030f57471SLouis Su 	return 0;
57130f57471SLouis Su }
57230f57471SLouis Su 
57330f57471SLouis Su /* Get a data block via Ethernet */
ax88180_recv(struct eth_device * dev)57430f57471SLouis Su static int ax88180_recv (struct eth_device *dev)
57530f57471SLouis Su {
57630f57471SLouis Su 	unsigned short ISR_Status;
57730f57471SLouis Su 	unsigned short tmp_regval;
57830f57471SLouis Su 
57930f57471SLouis Su 	/* Read and check interrupt status here. */
58030f57471SLouis Su 	ISR_Status = INW (dev, ISR);
58130f57471SLouis Su 
58230f57471SLouis Su 	while (ISR_Status) {
58330f57471SLouis Su 		/* Clear the interrupt status */
58430f57471SLouis Su 		OUTW (dev, ISR_Status, ISR);
58530f57471SLouis Su 
58630f57471SLouis Su 		debug ("\nax88180: The interrupt status = 0x%04x\n",
58730f57471SLouis Su 		       ISR_Status);
58830f57471SLouis Su 
58930f57471SLouis Su 		if (ISR_Status & ISR_PHY) {
59030f57471SLouis Su 			/* Read ISR register once to clear PHY interrupt bit */
59130f57471SLouis Su 			tmp_regval = ax88180_mdio_read (dev, M88_ISR);
592bb7336a4SHoan Hoang 			ax88180_media_config (dev);
59330f57471SLouis Su 		}
59430f57471SLouis Su 
59530f57471SLouis Su 		if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
59630f57471SLouis Su 			ax88180_rx_handler (dev);
59730f57471SLouis Su 		}
59830f57471SLouis Su 
59930f57471SLouis Su 		/* Read and check interrupt status again */
60030f57471SLouis Su 		ISR_Status = INW (dev, ISR);
60130f57471SLouis Su 	}
60230f57471SLouis Su 
60330f57471SLouis Su 	return 0;
60430f57471SLouis Su }
60530f57471SLouis Su 
60630f57471SLouis Su /* Send a data block via Ethernet. */
ax88180_send(struct eth_device * dev,void * packet,int length)60710cbe3b6SJoe Hershberger static int ax88180_send(struct eth_device *dev, void *packet, int length)
60830f57471SLouis Su {
60930f57471SLouis Su 	struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
61030f57471SLouis Su 	unsigned short TXDES_addr;
61130f57471SLouis Su 	unsigned short txcmd_txdp, txbs_txdp;
61230f57471SLouis Su 	unsigned short tmp_data;
61330f57471SLouis Su 	int i;
61430f57471SLouis Su #if defined (CONFIG_DRIVER_AX88180_16BIT)
61530f57471SLouis Su 	volatile unsigned short *txdata = (volatile unsigned short *)packet;
61630f57471SLouis Su #else
61730f57471SLouis Su 	volatile unsigned long *txdata = (volatile unsigned long *)packet;
61830f57471SLouis Su #endif
61930f57471SLouis Su 	unsigned short count;
62030f57471SLouis Su 
62130f57471SLouis Su 	if (priv->LinkState != INS_LINK_UP) {
62230f57471SLouis Su 		return 0;
62330f57471SLouis Su 	}
62430f57471SLouis Su 
62530f57471SLouis Su 	priv->FirstTxDesc = priv->NextTxDesc;
62630f57471SLouis Su 	txbs_txdp = 1 << priv->FirstTxDesc;
62730f57471SLouis Su 
62830f57471SLouis Su 	debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
62930f57471SLouis Su 
63030f57471SLouis Su 	txcmd_txdp = priv->FirstTxDesc << 13;
63130f57471SLouis Su 	TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
63230f57471SLouis Su 
63330f57471SLouis Su 	OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
63430f57471SLouis Su 
63530f57471SLouis Su 	/* Comput access times */
63630f57471SLouis Su 	count = (length + priv->PadSize) >> priv->BusWidth;
63730f57471SLouis Su 
63830f57471SLouis Su 	for (i = 0; i < count; i++) {
63930f57471SLouis Su 		WRITE_TXBUF (dev, *(txdata + i));
64030f57471SLouis Su 	}
64130f57471SLouis Su 
64230f57471SLouis Su 	OUTW (dev, txcmd_txdp | length, TXCMD);
64330f57471SLouis Su 	OUTW (dev, txbs_txdp, TXBS);
64430f57471SLouis Su 	OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
64530f57471SLouis Su 
64630f57471SLouis Su 	priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
64730f57471SLouis Su 
64830f57471SLouis Su 	/*
64930f57471SLouis Su 	 * Check the available transmit descriptor, if we had exhausted all
65030f57471SLouis Su 	 * transmit descriptor ,then we have to wait for at least one free
65130f57471SLouis Su 	 * descriptor
65230f57471SLouis Su 	 */
65330f57471SLouis Su 	txbs_txdp = 1 << priv->NextTxDesc;
65430f57471SLouis Su 	tmp_data = INW (dev, TXBS);
65530f57471SLouis Su 
65630f57471SLouis Su 	if (tmp_data & txbs_txdp) {
65730f57471SLouis Su 		if (ax88180_poll_tx_complete (dev) < 0) {
65830f57471SLouis Su 			ax88180_mac_reset (dev);
65930f57471SLouis Su 			priv->FirstTxDesc = TXDP0;
66030f57471SLouis Su 			priv->NextTxDesc = TXDP0;
66130f57471SLouis Su 			printf ("ax88180: Transmit time out occurred!\n");
66230f57471SLouis Su 		}
66330f57471SLouis Su 	}
66430f57471SLouis Su 
66530f57471SLouis Su 	return 0;
66630f57471SLouis Su }
66730f57471SLouis Su 
ax88180_read_mac_addr(struct eth_device * dev)66830f57471SLouis Su static void ax88180_read_mac_addr (struct eth_device *dev)
66930f57471SLouis Su {
67030f57471SLouis Su 	unsigned short macid0_val, macid1_val, macid2_val;
67130f57471SLouis Su 	unsigned short tmp_regval;
67230f57471SLouis Su 	unsigned short i;
67330f57471SLouis Su 
67430f57471SLouis Su 	/* Reload MAC address from EEPROM */
67530f57471SLouis Su 	OUTW (dev, RELOAD_EEPROM, PROMCTRL);
67630f57471SLouis Su 
67730f57471SLouis Su 	/* Waiting for reload eeprom completion */
67830f57471SLouis Su 	for (i = 0; i < 500; i++) {
67930f57471SLouis Su 		tmp_regval = INW (dev, PROMCTRL);
68030f57471SLouis Su 		if ((tmp_regval & RELOAD_EEPROM) == 0)
68130f57471SLouis Su 			break;
68230f57471SLouis Su 		udelay (1000);
68330f57471SLouis Su 	}
68430f57471SLouis Su 
68530f57471SLouis Su 	/* Get MAC addresses */
68630f57471SLouis Su 	macid0_val = INW (dev, MACID0);
68730f57471SLouis Su 	macid1_val = INW (dev, MACID1);
68830f57471SLouis Su 	macid2_val = INW (dev, MACID2);
68930f57471SLouis Su 
69030f57471SLouis Su 	if (((macid0_val | macid1_val | macid2_val) != 0) &&
69130f57471SLouis Su 	    ((macid0_val & 0x01) == 0)) {
69230f57471SLouis Su 		dev->enetaddr[0] = (unsigned char)macid0_val;
69330f57471SLouis Su 		dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
69430f57471SLouis Su 		dev->enetaddr[2] = (unsigned char)macid1_val;
69530f57471SLouis Su 		dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
69630f57471SLouis Su 		dev->enetaddr[4] = (unsigned char)macid2_val;
69730f57471SLouis Su 		dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
69830f57471SLouis Su 	}
69930f57471SLouis Su }
70030f57471SLouis Su 
701*53302bdcSSimon Glass /* Exported SubProgram Bodies */
ax88180_initialize(bd_t * bis)70230f57471SLouis Su int ax88180_initialize (bd_t * bis)
70330f57471SLouis Su {
70430f57471SLouis Su 	struct eth_device *dev;
70530f57471SLouis Su 	struct ax88180_private *priv;
70630f57471SLouis Su 
70730f57471SLouis Su 	dev = (struct eth_device *)malloc (sizeof *dev);
70830f57471SLouis Su 
70930f57471SLouis Su 	if (NULL == dev)
71030f57471SLouis Su 		return 0;
71130f57471SLouis Su 
71230f57471SLouis Su 	memset (dev, 0, sizeof *dev);
71330f57471SLouis Su 
71430f57471SLouis Su 	priv = (struct ax88180_private *)malloc (sizeof (*priv));
71530f57471SLouis Su 
71630f57471SLouis Su 	if (NULL == priv)
71730f57471SLouis Su 		return 0;
71830f57471SLouis Su 
71930f57471SLouis Su 	memset (priv, 0, sizeof *priv);
72030f57471SLouis Su 
721192bc694SBen Whitten 	strcpy(dev->name, "ax88180");
72230f57471SLouis Su 	dev->iobase = AX88180_BASE;
72330f57471SLouis Su 	dev->priv = priv;
72430f57471SLouis Su 	dev->init = ax88180_init;
72530f57471SLouis Su 	dev->halt = ax88180_halt;
72630f57471SLouis Su 	dev->send = ax88180_send;
72730f57471SLouis Su 	dev->recv = ax88180_recv;
72830f57471SLouis Su 
72930f57471SLouis Su 	priv->BusWidth = BUS_WIDTH_32;
73030f57471SLouis Su 	priv->PadSize = 3;
73130f57471SLouis Su #if defined (CONFIG_DRIVER_AX88180_16BIT)
73230f57471SLouis Su 	OUTW (dev, (START_BASE >> 8), BASE);
73330f57471SLouis Su 	OUTW (dev, DECODE_EN, DECODE);
73430f57471SLouis Su 
73530f57471SLouis Su 	priv->BusWidth = BUS_WIDTH_16;
73630f57471SLouis Su 	priv->PadSize = 1;
73730f57471SLouis Su #endif
73830f57471SLouis Su 
73930f57471SLouis Su 	ax88180_mac_reset (dev);
74030f57471SLouis Su 
74130f57471SLouis Su 	/* Disable interrupt */
74230f57471SLouis Su 	OUTW (dev, CLEAR_IMR, IMR);
74330f57471SLouis Su 
74430f57471SLouis Su 	/* Disable AX88180 TX/RX functions */
74530f57471SLouis Su 	OUTW (dev, WAKEMOD, CMD);
74630f57471SLouis Su 
74730f57471SLouis Su 	ax88180_read_mac_addr (dev);
74830f57471SLouis Su 
74930f57471SLouis Su 	eth_register (dev);
75030f57471SLouis Su 
75130f57471SLouis Su 	return ax88180_phy_initial (dev);
75230f57471SLouis Su 
75330f57471SLouis Su }
754