ax88180.c

来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 728 行 · 第 1/2 页

C
728
字号
/* * 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 shortax88180_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 voidax88180_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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?