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