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> 44*f9abdfe0SMike 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 */ 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 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 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 11230f57471SLouis Su static int ax88180_phy_reset (struct eth_device *dev) 11330f57471SLouis Su { 11430f57471SLouis Su unsigned short delay_cnt = 500; 11530f57471SLouis Su 116*f9abdfe0SMike 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) */ 119*f9abdfe0SMike 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 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 16030f57471SLouis Su for (i = 0; i < (sizeof (program_seq) / sizeof (program_seq[0])); i++) 16130f57471SLouis Su OUTW (dev, program_seq[i].value, program_seq[i].offset); 16230f57471SLouis Su } 16330f57471SLouis Su 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 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) 19530f57471SLouis Su unsigned short *rxdata = (unsigned short *)NetRxPackets[0]; 19630f57471SLouis Su #else 19730f57471SLouis Su unsigned long *rxdata = (unsigned long *)NetRxPackets[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. */ 24030f57471SLouis Su NetReceive (NetRxPackets[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 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; 269*f9abdfe0SMike Frysinger priv->PhyID0 = ax88180_mdio_read(dev, MII_PHYSID1); 27030f57471SLouis Su 271141ab7a5SMike Frysinger switch (priv->PhyID0) { 272*f9abdfe0SMike Frysinger case MARVELL_88E1111_PHYSID0: 27330f57471SLouis Su debug("ax88180: Found Marvell 88E1111 PHY." 27430f57471SLouis Su " (PHY Addr=0x%x)\n", priv->PhyAddr); 27530f57471SLouis Su 27630f57471SLouis Su tmp_regval = ax88180_mdio_read(dev, M88_EXT_SSR); 277141ab7a5SMike Frysinger if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE) { 27830f57471SLouis Su ax88180_mdio_write(dev, M88_EXT_SCR, DEFAULT_EXT_SCR); 27930f57471SLouis Su if (ax88180_phy_reset(dev) < 0) 28030f57471SLouis Su return 0; 28130f57471SLouis Su ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT); 28230f57471SLouis Su } 28330f57471SLouis Su 284141ab7a5SMike Frysinger return 1; 28530f57471SLouis Su 286*f9abdfe0SMike Frysinger case CICADA_CIS8201_PHYSID0: 28730f57471SLouis Su debug("ax88180: Found CICADA CIS8201 PHY" 28830f57471SLouis Su " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr); 289141ab7a5SMike Frysinger 29030f57471SLouis Su ax88180_mdio_write(dev, CIS_IMR, 29130f57471SLouis Su (CIS_INT_ENABLE | LINK_CHANGE_INT)); 29230f57471SLouis Su 29330f57471SLouis Su /* Set CIS_SMI_PRIORITY bit before force the media mode */ 294141ab7a5SMike Frysinger tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS); 29530f57471SLouis Su tmp_regval &= ~CIS_SMI_PRIORITY; 296141ab7a5SMike Frysinger ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval); 297141ab7a5SMike Frysinger 298141ab7a5SMike Frysinger return 1; 299141ab7a5SMike Frysinger 300141ab7a5SMike Frysinger case 0xffff: 301141ab7a5SMike Frysinger /* No PHY at this addr */ 302141ab7a5SMike Frysinger break; 303141ab7a5SMike Frysinger 304141ab7a5SMike Frysinger default: 305141ab7a5SMike Frysinger printf("ax88180: Unknown PHY chipset %#x at addr %#x\n", 306141ab7a5SMike Frysinger priv->PhyID0, priv->PhyAddr); 307141ab7a5SMike Frysinger break; 30830f57471SLouis Su } 30930f57471SLouis Su } 31030f57471SLouis Su 311141ab7a5SMike Frysinger printf("ax88180: Unknown PHY chipset!!\n"); 312141ab7a5SMike Frysinger return 0; 31330f57471SLouis Su } 31430f57471SLouis Su 315bb7336a4SHoan Hoang static void ax88180_media_config (struct eth_device *dev) 31630f57471SLouis Su { 31730f57471SLouis Su struct ax88180_private *priv = (struct ax88180_private *)dev->priv; 31830f57471SLouis Su unsigned long bmcr_val, bmsr_val; 31930f57471SLouis Su unsigned long rxcfg_val, maccfg0_val, maccfg1_val; 32030f57471SLouis Su unsigned long RealMediaMode; 32130f57471SLouis Su int i; 32230f57471SLouis Su 32330f57471SLouis Su /* Waiting 2 seconds for PHY link stable */ 32430f57471SLouis Su for (i = 0; i < 20000; i++) { 325*f9abdfe0SMike Frysinger bmsr_val = ax88180_mdio_read (dev, MII_BMSR); 326*f9abdfe0SMike Frysinger if (bmsr_val & BMSR_LSTATUS) { 32730f57471SLouis Su break; 32830f57471SLouis Su } 32930f57471SLouis Su udelay (100); 33030f57471SLouis Su } 33130f57471SLouis Su 332*f9abdfe0SMike Frysinger bmsr_val = ax88180_mdio_read (dev, MII_BMSR); 33330f57471SLouis Su debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val); 33430f57471SLouis Su 335*f9abdfe0SMike Frysinger if (bmsr_val & BMSR_LSTATUS) { 336*f9abdfe0SMike Frysinger bmcr_val = ax88180_mdio_read (dev, MII_BMCR); 33730f57471SLouis Su 338*f9abdfe0SMike Frysinger if (bmcr_val & BMCR_ANENABLE) { 33930f57471SLouis Su 34030f57471SLouis Su /* 34130f57471SLouis Su * Waiting for Auto-negotiation completion, this may 34230f57471SLouis Su * take up to 5 seconds. 34330f57471SLouis Su */ 34430f57471SLouis Su debug ("ax88180: Auto-negotiation is " 34530f57471SLouis Su "enabled. Waiting for NWay completion..\n"); 34630f57471SLouis Su for (i = 0; i < 50000; i++) { 347*f9abdfe0SMike Frysinger bmsr_val = ax88180_mdio_read (dev, MII_BMSR); 348*f9abdfe0SMike Frysinger if (bmsr_val & BMSR_ANEGCOMPLETE) { 34930f57471SLouis Su break; 35030f57471SLouis Su } 35130f57471SLouis Su udelay (100); 35230f57471SLouis Su } 35330f57471SLouis Su } else 35430f57471SLouis Su debug ("ax88180: Auto-negotiation is disabled.\n"); 35530f57471SLouis Su 35630f57471SLouis Su debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n", 35730f57471SLouis Su (unsigned int)bmcr_val, (unsigned int)bmsr_val); 35830f57471SLouis Su 35930f57471SLouis Su /* Get real media mode here */ 360141ab7a5SMike Frysinger switch (priv->PhyID0) { 361*f9abdfe0SMike Frysinger case MARVELL_88E1111_PHYSID0: 362bb7336a4SHoan Hoang RealMediaMode = get_MarvellPHY_media_mode(dev); 363141ab7a5SMike Frysinger break; 364*f9abdfe0SMike Frysinger case CICADA_CIS8201_PHYSID0: 365bb7336a4SHoan Hoang RealMediaMode = get_CicadaPHY_media_mode(dev); 366141ab7a5SMike Frysinger break; 367141ab7a5SMike Frysinger default: 36830f57471SLouis Su RealMediaMode = MEDIA_1000FULL; 369141ab7a5SMike Frysinger break; 37030f57471SLouis Su } 37130f57471SLouis Su 37230f57471SLouis Su priv->LinkState = INS_LINK_UP; 37330f57471SLouis Su 37430f57471SLouis Su switch (RealMediaMode) { 37530f57471SLouis Su case MEDIA_1000FULL: 37630f57471SLouis Su debug ("ax88180: 1000Mbps Full-duplex mode.\n"); 37730f57471SLouis Su rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; 37830f57471SLouis Su maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; 37930f57471SLouis Su maccfg1_val = GIGA_MODE_EN | RXFLOW_EN | 38030f57471SLouis Su FULLDUPLEX | DEFAULT_MACCFG1; 38130f57471SLouis Su break; 38230f57471SLouis Su 38330f57471SLouis Su case MEDIA_1000HALF: 38430f57471SLouis Su debug ("ax88180: 1000Mbps Half-duplex mode.\n"); 38530f57471SLouis Su rxcfg_val = DEFAULT_RXCFG; 38630f57471SLouis Su maccfg0_val = DEFAULT_MACCFG0; 38730f57471SLouis Su maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1; 38830f57471SLouis Su break; 38930f57471SLouis Su 39030f57471SLouis Su case MEDIA_100FULL: 39130f57471SLouis Su debug ("ax88180: 100Mbps Full-duplex mode.\n"); 39230f57471SLouis Su rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; 39330f57471SLouis Su maccfg0_val = SPEED100 | TXFLOW_ENABLE 39430f57471SLouis Su | DEFAULT_MACCFG0; 39530f57471SLouis Su maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; 39630f57471SLouis Su break; 39730f57471SLouis Su 39830f57471SLouis Su case MEDIA_100HALF: 39930f57471SLouis Su debug ("ax88180: 100Mbps Half-duplex mode.\n"); 40030f57471SLouis Su rxcfg_val = DEFAULT_RXCFG; 40130f57471SLouis Su maccfg0_val = SPEED100 | DEFAULT_MACCFG0; 40230f57471SLouis Su maccfg1_val = DEFAULT_MACCFG1; 40330f57471SLouis Su break; 40430f57471SLouis Su 40530f57471SLouis Su case MEDIA_10FULL: 40630f57471SLouis Su debug ("ax88180: 10Mbps Full-duplex mode.\n"); 40730f57471SLouis Su rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; 40830f57471SLouis Su maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; 40930f57471SLouis Su maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; 41030f57471SLouis Su break; 41130f57471SLouis Su 41230f57471SLouis Su case MEDIA_10HALF: 41330f57471SLouis Su debug ("ax88180: 10Mbps Half-duplex mode.\n"); 41430f57471SLouis Su rxcfg_val = DEFAULT_RXCFG; 41530f57471SLouis Su maccfg0_val = DEFAULT_MACCFG0; 41630f57471SLouis Su maccfg1_val = DEFAULT_MACCFG1; 41730f57471SLouis Su break; 41830f57471SLouis Su default: 41930f57471SLouis Su debug ("ax88180: Unknow media mode.\n"); 42030f57471SLouis Su rxcfg_val = DEFAULT_RXCFG; 42130f57471SLouis Su maccfg0_val = DEFAULT_MACCFG0; 42230f57471SLouis Su maccfg1_val = DEFAULT_MACCFG1; 42330f57471SLouis Su 42430f57471SLouis Su priv->LinkState = INS_LINK_DOWN; 42530f57471SLouis Su break; 42630f57471SLouis Su } 42730f57471SLouis Su 42830f57471SLouis Su } else { 42930f57471SLouis Su rxcfg_val = DEFAULT_RXCFG; 43030f57471SLouis Su maccfg0_val = DEFAULT_MACCFG0; 43130f57471SLouis Su maccfg1_val = DEFAULT_MACCFG1; 43230f57471SLouis Su 43330f57471SLouis Su priv->LinkState = INS_LINK_DOWN; 43430f57471SLouis Su } 43530f57471SLouis Su 43630f57471SLouis Su OUTW (dev, rxcfg_val, RXCFG); 43730f57471SLouis Su OUTW (dev, maccfg0_val, MACCFG0); 43830f57471SLouis Su OUTW (dev, maccfg1_val, MACCFG1); 43930f57471SLouis Su 44030f57471SLouis Su return; 44130f57471SLouis Su } 44230f57471SLouis Su 443bb7336a4SHoan Hoang static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev) 44430f57471SLouis Su { 44530f57471SLouis Su unsigned long m88_ssr; 44630f57471SLouis Su unsigned long MediaMode; 44730f57471SLouis Su 44830f57471SLouis Su m88_ssr = ax88180_mdio_read (dev, M88_SSR); 44930f57471SLouis Su switch (m88_ssr & SSR_MEDIA_MASK) { 45030f57471SLouis Su case SSR_1000FULL: 45130f57471SLouis Su MediaMode = MEDIA_1000FULL; 45230f57471SLouis Su break; 45330f57471SLouis Su case SSR_1000HALF: 45430f57471SLouis Su MediaMode = MEDIA_1000HALF; 45530f57471SLouis Su break; 45630f57471SLouis Su case SSR_100FULL: 45730f57471SLouis Su MediaMode = MEDIA_100FULL; 45830f57471SLouis Su break; 45930f57471SLouis Su case SSR_100HALF: 46030f57471SLouis Su MediaMode = MEDIA_100HALF; 46130f57471SLouis Su break; 46230f57471SLouis Su case SSR_10FULL: 46330f57471SLouis Su MediaMode = MEDIA_10FULL; 46430f57471SLouis Su break; 46530f57471SLouis Su case SSR_10HALF: 46630f57471SLouis Su MediaMode = MEDIA_10HALF; 46730f57471SLouis Su break; 46830f57471SLouis Su default: 46930f57471SLouis Su MediaMode = MEDIA_UNKNOWN; 47030f57471SLouis Su break; 47130f57471SLouis Su } 47230f57471SLouis Su 47330f57471SLouis Su return MediaMode; 47430f57471SLouis Su } 47530f57471SLouis Su 476bb7336a4SHoan Hoang static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev) 47730f57471SLouis Su { 47830f57471SLouis Su unsigned long tmp_regval; 47930f57471SLouis Su unsigned long MediaMode; 48030f57471SLouis Su 48130f57471SLouis Su tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS); 48230f57471SLouis Su switch (tmp_regval & CIS_MEDIA_MASK) { 48330f57471SLouis Su case CIS_1000FULL: 48430f57471SLouis Su MediaMode = MEDIA_1000FULL; 48530f57471SLouis Su break; 48630f57471SLouis Su case CIS_1000HALF: 48730f57471SLouis Su MediaMode = MEDIA_1000HALF; 48830f57471SLouis Su break; 48930f57471SLouis Su case CIS_100FULL: 49030f57471SLouis Su MediaMode = MEDIA_100FULL; 49130f57471SLouis Su break; 49230f57471SLouis Su case CIS_100HALF: 49330f57471SLouis Su MediaMode = MEDIA_100HALF; 49430f57471SLouis Su break; 49530f57471SLouis Su case CIS_10FULL: 49630f57471SLouis Su MediaMode = MEDIA_10FULL; 49730f57471SLouis Su break; 49830f57471SLouis Su case CIS_10HALF: 49930f57471SLouis Su MediaMode = MEDIA_10HALF; 50030f57471SLouis Su break; 50130f57471SLouis Su default: 50230f57471SLouis Su MediaMode = MEDIA_UNKNOWN; 50330f57471SLouis Su break; 50430f57471SLouis Su } 50530f57471SLouis Su 50630f57471SLouis Su return MediaMode; 50730f57471SLouis Su } 50830f57471SLouis Su 50930f57471SLouis Su static void ax88180_halt (struct eth_device *dev) 51030f57471SLouis Su { 51130f57471SLouis Su /* Disable AX88180 TX/RX functions */ 51230f57471SLouis Su OUTW (dev, WAKEMOD, CMD); 51330f57471SLouis Su } 51430f57471SLouis Su 51530f57471SLouis Su static int ax88180_init (struct eth_device *dev, bd_t * bd) 51630f57471SLouis Su { 51730f57471SLouis Su struct ax88180_private *priv = (struct ax88180_private *)dev->priv; 51830f57471SLouis Su unsigned short tmp_regval; 51930f57471SLouis Su 52030f57471SLouis Su ax88180_mac_reset (dev); 52130f57471SLouis Su 52230f57471SLouis Su /* Disable interrupt */ 52330f57471SLouis Su OUTW (dev, CLEAR_IMR, IMR); 52430f57471SLouis Su 52530f57471SLouis Su /* Disable AX88180 TX/RX functions */ 52630f57471SLouis Su OUTW (dev, WAKEMOD, CMD); 52730f57471SLouis Su 52830f57471SLouis Su /* Fill the MAC address */ 52930f57471SLouis Su tmp_regval = 53030f57471SLouis Su dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8); 53130f57471SLouis Su OUTW (dev, tmp_regval, MACID0); 53230f57471SLouis Su 53330f57471SLouis Su tmp_regval = 53430f57471SLouis Su dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8); 53530f57471SLouis Su OUTW (dev, tmp_regval, MACID1); 53630f57471SLouis Su 53730f57471SLouis Su tmp_regval = 53830f57471SLouis Su dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8); 53930f57471SLouis Su OUTW (dev, tmp_regval, MACID2); 54030f57471SLouis Su 541bb7336a4SHoan Hoang ax88180_media_config (dev); 54230f57471SLouis Su 54330f57471SLouis Su OUTW (dev, DEFAULT_RXFILTER, RXFILTER); 54430f57471SLouis Su 54530f57471SLouis Su /* Initial variables here */ 54630f57471SLouis Su priv->FirstTxDesc = TXDP0; 54730f57471SLouis Su priv->NextTxDesc = TXDP0; 54830f57471SLouis Su 54930f57471SLouis Su /* Check if there is any invalid interrupt status and clear it. */ 55030f57471SLouis Su OUTW (dev, INW (dev, ISR), ISR); 55130f57471SLouis Su 55230f57471SLouis Su /* Start AX88180 TX/RX functions */ 55330f57471SLouis Su OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD); 55430f57471SLouis Su 55530f57471SLouis Su return 0; 55630f57471SLouis Su } 55730f57471SLouis Su 55830f57471SLouis Su /* Get a data block via Ethernet */ 55930f57471SLouis Su static int ax88180_recv (struct eth_device *dev) 56030f57471SLouis Su { 56130f57471SLouis Su unsigned short ISR_Status; 56230f57471SLouis Su unsigned short tmp_regval; 56330f57471SLouis Su 56430f57471SLouis Su /* Read and check interrupt status here. */ 56530f57471SLouis Su ISR_Status = INW (dev, ISR); 56630f57471SLouis Su 56730f57471SLouis Su while (ISR_Status) { 56830f57471SLouis Su /* Clear the interrupt status */ 56930f57471SLouis Su OUTW (dev, ISR_Status, ISR); 57030f57471SLouis Su 57130f57471SLouis Su debug ("\nax88180: The interrupt status = 0x%04x\n", 57230f57471SLouis Su ISR_Status); 57330f57471SLouis Su 57430f57471SLouis Su if (ISR_Status & ISR_PHY) { 57530f57471SLouis Su /* Read ISR register once to clear PHY interrupt bit */ 57630f57471SLouis Su tmp_regval = ax88180_mdio_read (dev, M88_ISR); 577bb7336a4SHoan Hoang ax88180_media_config (dev); 57830f57471SLouis Su } 57930f57471SLouis Su 58030f57471SLouis Su if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) { 58130f57471SLouis Su ax88180_rx_handler (dev); 58230f57471SLouis Su } 58330f57471SLouis Su 58430f57471SLouis Su /* Read and check interrupt status again */ 58530f57471SLouis Su ISR_Status = INW (dev, ISR); 58630f57471SLouis Su } 58730f57471SLouis Su 58830f57471SLouis Su return 0; 58930f57471SLouis Su } 59030f57471SLouis Su 59130f57471SLouis Su /* Send a data block via Ethernet. */ 59230f57471SLouis Su static int 59330f57471SLouis Su ax88180_send (struct eth_device *dev, volatile void *packet, int length) 59430f57471SLouis Su { 59530f57471SLouis Su struct ax88180_private *priv = (struct ax88180_private *)dev->priv; 59630f57471SLouis Su unsigned short TXDES_addr; 59730f57471SLouis Su unsigned short txcmd_txdp, txbs_txdp; 59830f57471SLouis Su unsigned short tmp_data; 59930f57471SLouis Su int i; 60030f57471SLouis Su #if defined (CONFIG_DRIVER_AX88180_16BIT) 60130f57471SLouis Su volatile unsigned short *txdata = (volatile unsigned short *)packet; 60230f57471SLouis Su #else 60330f57471SLouis Su volatile unsigned long *txdata = (volatile unsigned long *)packet; 60430f57471SLouis Su #endif 60530f57471SLouis Su unsigned short count; 60630f57471SLouis Su 60730f57471SLouis Su if (priv->LinkState != INS_LINK_UP) { 60830f57471SLouis Su return 0; 60930f57471SLouis Su } 61030f57471SLouis Su 61130f57471SLouis Su priv->FirstTxDesc = priv->NextTxDesc; 61230f57471SLouis Su txbs_txdp = 1 << priv->FirstTxDesc; 61330f57471SLouis Su 61430f57471SLouis Su debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc); 61530f57471SLouis Su 61630f57471SLouis Su txcmd_txdp = priv->FirstTxDesc << 13; 61730f57471SLouis Su TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2); 61830f57471SLouis Su 61930f57471SLouis Su OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD); 62030f57471SLouis Su 62130f57471SLouis Su /* Comput access times */ 62230f57471SLouis Su count = (length + priv->PadSize) >> priv->BusWidth; 62330f57471SLouis Su 62430f57471SLouis Su for (i = 0; i < count; i++) { 62530f57471SLouis Su WRITE_TXBUF (dev, *(txdata + i)); 62630f57471SLouis Su } 62730f57471SLouis Su 62830f57471SLouis Su OUTW (dev, txcmd_txdp | length, TXCMD); 62930f57471SLouis Su OUTW (dev, txbs_txdp, TXBS); 63030f57471SLouis Su OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr); 63130f57471SLouis Su 63230f57471SLouis Su priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK; 63330f57471SLouis Su 63430f57471SLouis Su /* 63530f57471SLouis Su * Check the available transmit descriptor, if we had exhausted all 63630f57471SLouis Su * transmit descriptor ,then we have to wait for at least one free 63730f57471SLouis Su * descriptor 63830f57471SLouis Su */ 63930f57471SLouis Su txbs_txdp = 1 << priv->NextTxDesc; 64030f57471SLouis Su tmp_data = INW (dev, TXBS); 64130f57471SLouis Su 64230f57471SLouis Su if (tmp_data & txbs_txdp) { 64330f57471SLouis Su if (ax88180_poll_tx_complete (dev) < 0) { 64430f57471SLouis Su ax88180_mac_reset (dev); 64530f57471SLouis Su priv->FirstTxDesc = TXDP0; 64630f57471SLouis Su priv->NextTxDesc = TXDP0; 64730f57471SLouis Su printf ("ax88180: Transmit time out occurred!\n"); 64830f57471SLouis Su } 64930f57471SLouis Su } 65030f57471SLouis Su 65130f57471SLouis Su return 0; 65230f57471SLouis Su } 65330f57471SLouis Su 65430f57471SLouis Su static void ax88180_read_mac_addr (struct eth_device *dev) 65530f57471SLouis Su { 65630f57471SLouis Su unsigned short macid0_val, macid1_val, macid2_val; 65730f57471SLouis Su unsigned short tmp_regval; 65830f57471SLouis Su unsigned short i; 65930f57471SLouis Su 66030f57471SLouis Su /* Reload MAC address from EEPROM */ 66130f57471SLouis Su OUTW (dev, RELOAD_EEPROM, PROMCTRL); 66230f57471SLouis Su 66330f57471SLouis Su /* Waiting for reload eeprom completion */ 66430f57471SLouis Su for (i = 0; i < 500; i++) { 66530f57471SLouis Su tmp_regval = INW (dev, PROMCTRL); 66630f57471SLouis Su if ((tmp_regval & RELOAD_EEPROM) == 0) 66730f57471SLouis Su break; 66830f57471SLouis Su udelay (1000); 66930f57471SLouis Su } 67030f57471SLouis Su 67130f57471SLouis Su /* Get MAC addresses */ 67230f57471SLouis Su macid0_val = INW (dev, MACID0); 67330f57471SLouis Su macid1_val = INW (dev, MACID1); 67430f57471SLouis Su macid2_val = INW (dev, MACID2); 67530f57471SLouis Su 67630f57471SLouis Su if (((macid0_val | macid1_val | macid2_val) != 0) && 67730f57471SLouis Su ((macid0_val & 0x01) == 0)) { 67830f57471SLouis Su dev->enetaddr[0] = (unsigned char)macid0_val; 67930f57471SLouis Su dev->enetaddr[1] = (unsigned char)(macid0_val >> 8); 68030f57471SLouis Su dev->enetaddr[2] = (unsigned char)macid1_val; 68130f57471SLouis Su dev->enetaddr[3] = (unsigned char)(macid1_val >> 8); 68230f57471SLouis Su dev->enetaddr[4] = (unsigned char)macid2_val; 68330f57471SLouis Su dev->enetaddr[5] = (unsigned char)(macid2_val >> 8); 68430f57471SLouis Su } 68530f57471SLouis Su } 68630f57471SLouis Su 68730f57471SLouis Su /* 68830f57471SLouis Su =========================================================================== 68930f57471SLouis Su <<<<<< Exported SubProgram Bodies >>>>>> 69030f57471SLouis Su =========================================================================== 69130f57471SLouis Su */ 69230f57471SLouis Su int ax88180_initialize (bd_t * bis) 69330f57471SLouis Su { 69430f57471SLouis Su struct eth_device *dev; 69530f57471SLouis Su struct ax88180_private *priv; 69630f57471SLouis Su 69730f57471SLouis Su dev = (struct eth_device *)malloc (sizeof *dev); 69830f57471SLouis Su 69930f57471SLouis Su if (NULL == dev) 70030f57471SLouis Su return 0; 70130f57471SLouis Su 70230f57471SLouis Su memset (dev, 0, sizeof *dev); 70330f57471SLouis Su 70430f57471SLouis Su priv = (struct ax88180_private *)malloc (sizeof (*priv)); 70530f57471SLouis Su 70630f57471SLouis Su if (NULL == priv) 70730f57471SLouis Su return 0; 70830f57471SLouis Su 70930f57471SLouis Su memset (priv, 0, sizeof *priv); 71030f57471SLouis Su 71130f57471SLouis Su sprintf (dev->name, "ax88180"); 71230f57471SLouis Su dev->iobase = AX88180_BASE; 71330f57471SLouis Su dev->priv = priv; 71430f57471SLouis Su dev->init = ax88180_init; 71530f57471SLouis Su dev->halt = ax88180_halt; 71630f57471SLouis Su dev->send = ax88180_send; 71730f57471SLouis Su dev->recv = ax88180_recv; 71830f57471SLouis Su 71930f57471SLouis Su priv->BusWidth = BUS_WIDTH_32; 72030f57471SLouis Su priv->PadSize = 3; 72130f57471SLouis Su #if defined (CONFIG_DRIVER_AX88180_16BIT) 72230f57471SLouis Su OUTW (dev, (START_BASE >> 8), BASE); 72330f57471SLouis Su OUTW (dev, DECODE_EN, DECODE); 72430f57471SLouis Su 72530f57471SLouis Su priv->BusWidth = BUS_WIDTH_16; 72630f57471SLouis Su priv->PadSize = 1; 72730f57471SLouis Su #endif 72830f57471SLouis Su 72930f57471SLouis Su ax88180_mac_reset (dev); 73030f57471SLouis Su 73130f57471SLouis Su /* Disable interrupt */ 73230f57471SLouis Su OUTW (dev, CLEAR_IMR, IMR); 73330f57471SLouis Su 73430f57471SLouis Su /* Disable AX88180 TX/RX functions */ 73530f57471SLouis Su OUTW (dev, WAKEMOD, CMD); 73630f57471SLouis Su 73730f57471SLouis Su ax88180_read_mac_addr (dev); 73830f57471SLouis Su 73930f57471SLouis Su eth_register (dev); 74030f57471SLouis Su 74130f57471SLouis Su return ax88180_phy_initial (dev); 74230f57471SLouis Su 74330f57471SLouis Su } 744