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 + -
显示快捷键?