blob: 28cb41272a9ea7470049bacac0d76d96f7e7ef3a [file] [log] [blame]
Louis Su8dcca362008-07-09 11:01:37 +08001/*
2 * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
3 *
4 * This program is free software; you can distribute it and/or modify
5 * it under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 * This program is distributed in the hope it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
14 * USA.
15 */
16
17/*
18 * ========================================================================
19 * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
20 *
21 * The AX88180 Ethernet controller is a high performance and highly
22 * integrated local CPU bus Ethernet controller with embedded 40K bytes
23 * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
24 * embedded systems.
25 * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
26 * controller that supports both MII and RGMII interfaces and is
27 * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
28 *
29 * Please visit ASIX's web site (http://www.asix.com.tw) for more
30 * details.
31 *
32 * Module Name : ax88180.c
33 * Date : 2008-07-07
34 * History
35 * 09/06/2006 : New release for AX88180 US2 chip.
36 * 07/07/2008 : Fix up the coding style and using inline functions
37 * instead of macros
38 * ========================================================================
39 */
40#include <common.h>
41#include <command.h>
Simon Glass0f2af882020-05-10 11:40:05 -060042#include <log.h>
Louis Su8dcca362008-07-09 11:01:37 +080043#include <net.h>
44#include <malloc.h>
Simon Glassdbd79542020-05-10 11:40:11 -060045#include <linux/delay.h>
Mike Frysingerb68c2102010-05-10 16:47:36 -040046#include <linux/mii.h>
Louis Su8dcca362008-07-09 11:01:37 +080047#include "ax88180.h"
48
49/*
50 * ===========================================================================
51 * Local SubProgram Declaration
52 * ===========================================================================
53 */
54static void ax88180_rx_handler (struct eth_device *dev);
55static int ax88180_phy_initial (struct eth_device *dev);
Hoan Hoang0b8c3552010-05-10 16:09:35 -040056static void ax88180_media_config (struct eth_device *dev);
57static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev);
58static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev);
Louis Su8dcca362008-07-09 11:01:37 +080059static unsigned short ax88180_mdio_read (struct eth_device *dev,
60 unsigned long regaddr);
61static void ax88180_mdio_write (struct eth_device *dev,
62 unsigned long regaddr, unsigned short regdata);
63
64/*
65 * ===========================================================================
66 * Local SubProgram Bodies
67 * ===========================================================================
68 */
69static int ax88180_mdio_check_complete (struct eth_device *dev)
70{
71 int us_cnt = 10000;
72 unsigned short tmpval;
73
74 /* MDIO read/write should not take more than 10 ms */
75 while (--us_cnt) {
76 tmpval = INW (dev, MDIOCTRL);
77 if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
78 break;
79 }
80
81 return us_cnt;
82}
83
84static unsigned short
85ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
86{
87 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
88 unsigned long tmpval = 0;
89
90 OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
91
92 if (ax88180_mdio_check_complete (dev))
93 tmpval = INW (dev, MDIODP);
94 else
95 printf ("Failed to read PHY register!\n");
96
97 return (unsigned short)(tmpval & 0xFFFF);
98}
99
100static void
101ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
102 unsigned short regdata)
103{
104 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
105
106 OUTW (dev, regdata, MDIODP);
107
108 OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
109
110 if (!ax88180_mdio_check_complete (dev))
111 printf ("Failed to write PHY register!\n");
112}
113
114static int ax88180_phy_reset (struct eth_device *dev)
115{
116 unsigned short delay_cnt = 500;
117
Mike Frysingerb68c2102010-05-10 16:47:36 -0400118 ax88180_mdio_write (dev, MII_BMCR, (BMCR_RESET | BMCR_ANENABLE));
Louis Su8dcca362008-07-09 11:01:37 +0800119
120 /* Wait for the reset to complete, or time out (500 ms) */
Mike Frysingerb68c2102010-05-10 16:47:36 -0400121 while (ax88180_mdio_read (dev, MII_BMCR) & BMCR_RESET) {
Simon Glass0db4b942020-05-10 11:40:10 -0600122 udelay(1000);
Louis Su8dcca362008-07-09 11:01:37 +0800123 if (--delay_cnt == 0) {
124 printf ("Failed to reset PHY!\n");
125 return -1;
126 }
127 }
128
129 return 0;
130}
131
132static void ax88180_mac_reset (struct eth_device *dev)
133{
134 unsigned long tmpval;
135 unsigned char i;
136
137 struct {
138 unsigned short offset, value;
139 } program_seq[] = {
140 {
141 MISC, MISC_NORMAL}, {
142 RXINDICATOR, DEFAULT_RXINDICATOR}, {
143 TXCMD, DEFAULT_TXCMD}, {
144 TXBS, DEFAULT_TXBS}, {
145 TXDES0, DEFAULT_TXDES0}, {
146 TXDES1, DEFAULT_TXDES1}, {
147 TXDES2, DEFAULT_TXDES2}, {
148 TXDES3, DEFAULT_TXDES3}, {
149 TXCFG, DEFAULT_TXCFG}, {
150 MACCFG2, DEFAULT_MACCFG2}, {
151 MACCFG3, DEFAULT_MACCFG3}, {
152 TXLEN, DEFAULT_TXLEN}, {
153 RXBTHD0, DEFAULT_RXBTHD0}, {
154 RXBTHD1, DEFAULT_RXBTHD1}, {
155 RXFULTHD, DEFAULT_RXFULTHD}, {
156 DOGTHD0, DEFAULT_DOGTHD0}, {
157 DOGTHD1, DEFAULT_DOGTHD1},};
158
159 OUTW (dev, MISC_RESET_MAC, MISC);
160 tmpval = INW (dev, MISC);
161
Axel Lin10a72b62013-07-03 11:24:18 +0800162 for (i = 0; i < ARRAY_SIZE(program_seq); i++)
Louis Su8dcca362008-07-09 11:01:37 +0800163 OUTW (dev, program_seq[i].value, program_seq[i].offset);
164}
165
166static int ax88180_poll_tx_complete (struct eth_device *dev)
167{
168 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
169 unsigned long tmpval, txbs_txdp;
170 int TimeOutCnt = 10000;
171
172 txbs_txdp = 1 << priv->NextTxDesc;
173
174 while (TimeOutCnt--) {
175
176 tmpval = INW (dev, TXBS);
177
178 if ((tmpval & txbs_txdp) == 0)
179 break;
180
Simon Glass0db4b942020-05-10 11:40:10 -0600181 udelay(100);
Louis Su8dcca362008-07-09 11:01:37 +0800182 }
183
184 if (TimeOutCnt)
185 return 0;
186 else
187 return -TimeOutCnt;
188}
189
190static void ax88180_rx_handler (struct eth_device *dev)
191{
192 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
193 unsigned long data_size;
194 unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
195 int i;
196#if defined (CONFIG_DRIVER_AX88180_16BIT)
Joe Hershberger9f09a362015-04-08 01:41:06 -0500197 unsigned short *rxdata = (unsigned short *)net_rx_packets[0];
Louis Su8dcca362008-07-09 11:01:37 +0800198#else
Joe Hershberger9f09a362015-04-08 01:41:06 -0500199 unsigned long *rxdata = (unsigned long *)net_rx_packets[0];
Louis Su8dcca362008-07-09 11:01:37 +0800200#endif
201 unsigned short count;
202
203 rxcurt_ptr = INW (dev, RXCURT);
204 rxbound_ptr = INW (dev, RXBOUND);
205 next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
206
207 debug ("ax88180: RX original RXBOUND=0x%04x,"
208 " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
209
210 while (next_ptr != rxcurt_ptr) {
211
212 OUTW (dev, RX_START_READ, RXINDICATOR);
213
214 data_size = READ_RXBUF (dev) & 0xFFFF;
215
216 if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
217
218 OUTW (dev, RX_STOP_READ, RXINDICATOR);
219
220 ax88180_mac_reset (dev);
221 printf ("ax88180: Invalid Rx packet length!"
222 " (len=0x%04lx)\n", data_size);
223
224 debug ("ax88180: RX RXBOUND=0x%04x,"
225 "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
226 return;
227 }
228
229 rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
230 rxbound_ptr &= RX_PAGE_NUM_MASK;
231
232 /* Comput access times */
233 count = (data_size + priv->PadSize) >> priv->BusWidth;
234
235 for (i = 0; i < count; i++) {
236 *(rxdata + i) = READ_RXBUF (dev);
237 }
238
239 OUTW (dev, RX_STOP_READ, RXINDICATOR);
240
241 /* Pass the packet up to the protocol layers. */
Joe Hershberger9f09a362015-04-08 01:41:06 -0500242 net_process_received_packet(net_rx_packets[0], data_size);
Louis Su8dcca362008-07-09 11:01:37 +0800243
244 OUTW (dev, rxbound_ptr, RXBOUND);
245
246 rxcurt_ptr = INW (dev, RXCURT);
247 rxbound_ptr = INW (dev, RXBOUND);
248 next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
249
250 debug ("ax88180: RX updated RXBOUND=0x%04x,"
251 "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
252 }
253
254 return;
255}
256
257static int ax88180_phy_initial (struct eth_device *dev)
258{
259 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
260 unsigned long tmp_regval;
Mike Frysinger762c9322010-05-10 16:10:00 -0400261 unsigned short phyaddr;
Louis Su8dcca362008-07-09 11:01:37 +0800262
Mike Frysinger762c9322010-05-10 16:10:00 -0400263 /* Search for first avaliable PHY chipset */
264#ifdef CONFIG_PHY_ADDR
265 phyaddr = CONFIG_PHY_ADDR;
266#else
267 for (phyaddr = 0; phyaddr < 32; ++phyaddr)
268#endif
269 {
270 priv->PhyAddr = phyaddr;
Mike Frysingerb68c2102010-05-10 16:47:36 -0400271 priv->PhyID0 = ax88180_mdio_read(dev, MII_PHYSID1);
Hoan Hoangd8ea6dc2010-05-11 02:42:38 -0400272 priv->PhyID1 = ax88180_mdio_read(dev, MII_PHYSID2);
Louis Su8dcca362008-07-09 11:01:37 +0800273
Mike Frysinger762c9322010-05-10 16:10:00 -0400274 switch (priv->PhyID0) {
Hoan Hoangd8ea6dc2010-05-11 02:42:38 -0400275 case MARVELL_ALASKA_PHYSID0:
276 debug("ax88180: Found Marvell Alaska PHY family."
Mike Frysinger762c9322010-05-10 16:10:00 -0400277 " (PHY Addr=0x%x)\n", priv->PhyAddr);
Louis Su8dcca362008-07-09 11:01:37 +0800278
Hoan Hoangd8ea6dc2010-05-11 02:42:38 -0400279 switch (priv->PhyID1) {
280 case MARVELL_88E1118_PHYSID1:
281 ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 2);
282 ax88180_mdio_write(dev, M88E1118_CR,
283 M88E1118_CR_DEFAULT);
284 ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 3);
285 ax88180_mdio_write(dev, M88E1118_LEDCTL,
286 M88E1118_LEDCTL_DEFAULT);
287 ax88180_mdio_write(dev, M88E1118_LEDMIX,
288 M88E1118_LEDMIX_LED050 | M88E1118_LEDMIX_LED150 | 0x15);
289 ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 0);
290 default: /* Default to 88E1111 Phy */
291 tmp_regval = ax88180_mdio_read(dev, M88E1111_EXT_SSR);
292 if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE)
293 ax88180_mdio_write(dev, M88E1111_EXT_SCR,
294 DEFAULT_EXT_SCR);
Mike Frysinger762c9322010-05-10 16:10:00 -0400295 }
Louis Su8dcca362008-07-09 11:01:37 +0800296
Hoan Hoangd8ea6dc2010-05-11 02:42:38 -0400297 if (ax88180_phy_reset(dev) < 0)
298 return 0;
299 ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT);
300
Mike Frysinger762c9322010-05-10 16:10:00 -0400301 return 1;
Louis Su8dcca362008-07-09 11:01:37 +0800302
Mike Frysingerb68c2102010-05-10 16:47:36 -0400303 case CICADA_CIS8201_PHYSID0:
Mike Frysinger762c9322010-05-10 16:10:00 -0400304 debug("ax88180: Found CICADA CIS8201 PHY"
305 " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
Louis Su8dcca362008-07-09 11:01:37 +0800306
Mike Frysinger762c9322010-05-10 16:10:00 -0400307 ax88180_mdio_write(dev, CIS_IMR,
Louis Su8dcca362008-07-09 11:01:37 +0800308 (CIS_INT_ENABLE | LINK_CHANGE_INT));
309
310 /* Set CIS_SMI_PRIORITY bit before force the media mode */
Mike Frysinger762c9322010-05-10 16:10:00 -0400311 tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS);
Louis Su8dcca362008-07-09 11:01:37 +0800312 tmp_regval &= ~CIS_SMI_PRIORITY;
Mike Frysinger762c9322010-05-10 16:10:00 -0400313 ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval);
314
315 return 1;
316
317 case 0xffff:
318 /* No PHY at this addr */
319 break;
320
321 default:
322 printf("ax88180: Unknown PHY chipset %#x at addr %#x\n",
323 priv->PhyID0, priv->PhyAddr);
324 break;
Louis Su8dcca362008-07-09 11:01:37 +0800325 }
326 }
327
Mike Frysinger762c9322010-05-10 16:10:00 -0400328 printf("ax88180: Unknown PHY chipset!!\n");
329 return 0;
Louis Su8dcca362008-07-09 11:01:37 +0800330}
331
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400332static void ax88180_media_config (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800333{
334 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
335 unsigned long bmcr_val, bmsr_val;
336 unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
337 unsigned long RealMediaMode;
338 int i;
339
340 /* Waiting 2 seconds for PHY link stable */
341 for (i = 0; i < 20000; i++) {
Mike Frysingerb68c2102010-05-10 16:47:36 -0400342 bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
343 if (bmsr_val & BMSR_LSTATUS) {
Louis Su8dcca362008-07-09 11:01:37 +0800344 break;
345 }
Simon Glass0db4b942020-05-10 11:40:10 -0600346 udelay(100);
Louis Su8dcca362008-07-09 11:01:37 +0800347 }
348
Mike Frysingerb68c2102010-05-10 16:47:36 -0400349 bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
Louis Su8dcca362008-07-09 11:01:37 +0800350 debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
351
Mike Frysingerb68c2102010-05-10 16:47:36 -0400352 if (bmsr_val & BMSR_LSTATUS) {
353 bmcr_val = ax88180_mdio_read (dev, MII_BMCR);
Louis Su8dcca362008-07-09 11:01:37 +0800354
Mike Frysingerb68c2102010-05-10 16:47:36 -0400355 if (bmcr_val & BMCR_ANENABLE) {
Louis Su8dcca362008-07-09 11:01:37 +0800356
357 /*
358 * Waiting for Auto-negotiation completion, this may
359 * take up to 5 seconds.
360 */
361 debug ("ax88180: Auto-negotiation is "
362 "enabled. Waiting for NWay completion..\n");
363 for (i = 0; i < 50000; i++) {
Mike Frysingerb68c2102010-05-10 16:47:36 -0400364 bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
365 if (bmsr_val & BMSR_ANEGCOMPLETE) {
Louis Su8dcca362008-07-09 11:01:37 +0800366 break;
367 }
Simon Glass0db4b942020-05-10 11:40:10 -0600368 udelay(100);
Louis Su8dcca362008-07-09 11:01:37 +0800369 }
370 } else
371 debug ("ax88180: Auto-negotiation is disabled.\n");
372
373 debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
374 (unsigned int)bmcr_val, (unsigned int)bmsr_val);
375
376 /* Get real media mode here */
Mike Frysinger762c9322010-05-10 16:10:00 -0400377 switch (priv->PhyID0) {
Hoan Hoangd8ea6dc2010-05-11 02:42:38 -0400378 case MARVELL_ALASKA_PHYSID0:
Mike Frysinger762c9322010-05-10 16:10:00 -0400379 RealMediaMode = get_MarvellPHY_media_mode(dev);
380 break;
Mike Frysingerb68c2102010-05-10 16:47:36 -0400381 case CICADA_CIS8201_PHYSID0:
Mike Frysinger762c9322010-05-10 16:10:00 -0400382 RealMediaMode = get_CicadaPHY_media_mode(dev);
383 break;
384 default:
Louis Su8dcca362008-07-09 11:01:37 +0800385 RealMediaMode = MEDIA_1000FULL;
Mike Frysinger762c9322010-05-10 16:10:00 -0400386 break;
Louis Su8dcca362008-07-09 11:01:37 +0800387 }
388
389 priv->LinkState = INS_LINK_UP;
390
391 switch (RealMediaMode) {
392 case MEDIA_1000FULL:
393 debug ("ax88180: 1000Mbps Full-duplex mode.\n");
394 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
395 maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
396 maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
397 FULLDUPLEX | DEFAULT_MACCFG1;
398 break;
399
400 case MEDIA_1000HALF:
401 debug ("ax88180: 1000Mbps Half-duplex mode.\n");
402 rxcfg_val = DEFAULT_RXCFG;
403 maccfg0_val = DEFAULT_MACCFG0;
404 maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
405 break;
406
407 case MEDIA_100FULL:
408 debug ("ax88180: 100Mbps Full-duplex mode.\n");
409 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
410 maccfg0_val = SPEED100 | TXFLOW_ENABLE
411 | DEFAULT_MACCFG0;
412 maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
413 break;
414
415 case MEDIA_100HALF:
416 debug ("ax88180: 100Mbps Half-duplex mode.\n");
417 rxcfg_val = DEFAULT_RXCFG;
418 maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
419 maccfg1_val = DEFAULT_MACCFG1;
420 break;
421
422 case MEDIA_10FULL:
423 debug ("ax88180: 10Mbps Full-duplex mode.\n");
424 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
425 maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
426 maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
427 break;
428
429 case MEDIA_10HALF:
430 debug ("ax88180: 10Mbps Half-duplex mode.\n");
431 rxcfg_val = DEFAULT_RXCFG;
432 maccfg0_val = DEFAULT_MACCFG0;
433 maccfg1_val = DEFAULT_MACCFG1;
434 break;
435 default:
436 debug ("ax88180: Unknow media mode.\n");
437 rxcfg_val = DEFAULT_RXCFG;
438 maccfg0_val = DEFAULT_MACCFG0;
439 maccfg1_val = DEFAULT_MACCFG1;
440
441 priv->LinkState = INS_LINK_DOWN;
442 break;
443 }
444
445 } else {
446 rxcfg_val = DEFAULT_RXCFG;
447 maccfg0_val = DEFAULT_MACCFG0;
448 maccfg1_val = DEFAULT_MACCFG1;
449
450 priv->LinkState = INS_LINK_DOWN;
451 }
452
453 OUTW (dev, rxcfg_val, RXCFG);
454 OUTW (dev, maccfg0_val, MACCFG0);
455 OUTW (dev, maccfg1_val, MACCFG1);
456
457 return;
458}
459
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400460static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800461{
462 unsigned long m88_ssr;
463 unsigned long MediaMode;
464
465 m88_ssr = ax88180_mdio_read (dev, M88_SSR);
466 switch (m88_ssr & SSR_MEDIA_MASK) {
467 case SSR_1000FULL:
468 MediaMode = MEDIA_1000FULL;
469 break;
470 case SSR_1000HALF:
471 MediaMode = MEDIA_1000HALF;
472 break;
473 case SSR_100FULL:
474 MediaMode = MEDIA_100FULL;
475 break;
476 case SSR_100HALF:
477 MediaMode = MEDIA_100HALF;
478 break;
479 case SSR_10FULL:
480 MediaMode = MEDIA_10FULL;
481 break;
482 case SSR_10HALF:
483 MediaMode = MEDIA_10HALF;
484 break;
485 default:
486 MediaMode = MEDIA_UNKNOWN;
487 break;
488 }
489
490 return MediaMode;
491}
492
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400493static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800494{
495 unsigned long tmp_regval;
496 unsigned long MediaMode;
497
498 tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
499 switch (tmp_regval & CIS_MEDIA_MASK) {
500 case CIS_1000FULL:
501 MediaMode = MEDIA_1000FULL;
502 break;
503 case CIS_1000HALF:
504 MediaMode = MEDIA_1000HALF;
505 break;
506 case CIS_100FULL:
507 MediaMode = MEDIA_100FULL;
508 break;
509 case CIS_100HALF:
510 MediaMode = MEDIA_100HALF;
511 break;
512 case CIS_10FULL:
513 MediaMode = MEDIA_10FULL;
514 break;
515 case CIS_10HALF:
516 MediaMode = MEDIA_10HALF;
517 break;
518 default:
519 MediaMode = MEDIA_UNKNOWN;
520 break;
521 }
522
523 return MediaMode;
524}
525
526static void ax88180_halt (struct eth_device *dev)
527{
528 /* Disable AX88180 TX/RX functions */
529 OUTW (dev, WAKEMOD, CMD);
530}
531
532static int ax88180_init (struct eth_device *dev, bd_t * bd)
533{
534 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
535 unsigned short tmp_regval;
536
537 ax88180_mac_reset (dev);
538
539 /* Disable interrupt */
540 OUTW (dev, CLEAR_IMR, IMR);
541
542 /* Disable AX88180 TX/RX functions */
543 OUTW (dev, WAKEMOD, CMD);
544
545 /* Fill the MAC address */
546 tmp_regval =
547 dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
548 OUTW (dev, tmp_regval, MACID0);
549
550 tmp_regval =
551 dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
552 OUTW (dev, tmp_regval, MACID1);
553
554 tmp_regval =
555 dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
556 OUTW (dev, tmp_regval, MACID2);
557
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400558 ax88180_media_config (dev);
Louis Su8dcca362008-07-09 11:01:37 +0800559
560 OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
561
562 /* Initial variables here */
563 priv->FirstTxDesc = TXDP0;
564 priv->NextTxDesc = TXDP0;
565
566 /* Check if there is any invalid interrupt status and clear it. */
567 OUTW (dev, INW (dev, ISR), ISR);
568
569 /* Start AX88180 TX/RX functions */
570 OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
571
572 return 0;
573}
574
575/* Get a data block via Ethernet */
576static int ax88180_recv (struct eth_device *dev)
577{
578 unsigned short ISR_Status;
579 unsigned short tmp_regval;
580
581 /* Read and check interrupt status here. */
582 ISR_Status = INW (dev, ISR);
583
584 while (ISR_Status) {
585 /* Clear the interrupt status */
586 OUTW (dev, ISR_Status, ISR);
587
588 debug ("\nax88180: The interrupt status = 0x%04x\n",
589 ISR_Status);
590
591 if (ISR_Status & ISR_PHY) {
592 /* Read ISR register once to clear PHY interrupt bit */
593 tmp_regval = ax88180_mdio_read (dev, M88_ISR);
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400594 ax88180_media_config (dev);
Louis Su8dcca362008-07-09 11:01:37 +0800595 }
596
597 if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
598 ax88180_rx_handler (dev);
599 }
600
601 /* Read and check interrupt status again */
602 ISR_Status = INW (dev, ISR);
603 }
604
605 return 0;
606}
607
608/* Send a data block via Ethernet. */
Joe Hershbergere4e04882012-05-22 18:36:19 +0000609static int ax88180_send(struct eth_device *dev, void *packet, int length)
Louis Su8dcca362008-07-09 11:01:37 +0800610{
611 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
612 unsigned short TXDES_addr;
613 unsigned short txcmd_txdp, txbs_txdp;
614 unsigned short tmp_data;
615 int i;
616#if defined (CONFIG_DRIVER_AX88180_16BIT)
617 volatile unsigned short *txdata = (volatile unsigned short *)packet;
618#else
619 volatile unsigned long *txdata = (volatile unsigned long *)packet;
620#endif
621 unsigned short count;
622
623 if (priv->LinkState != INS_LINK_UP) {
624 return 0;
625 }
626
627 priv->FirstTxDesc = priv->NextTxDesc;
628 txbs_txdp = 1 << priv->FirstTxDesc;
629
630 debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
631
632 txcmd_txdp = priv->FirstTxDesc << 13;
633 TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
634
635 OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
636
637 /* Comput access times */
638 count = (length + priv->PadSize) >> priv->BusWidth;
639
640 for (i = 0; i < count; i++) {
641 WRITE_TXBUF (dev, *(txdata + i));
642 }
643
644 OUTW (dev, txcmd_txdp | length, TXCMD);
645 OUTW (dev, txbs_txdp, TXBS);
646 OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
647
648 priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
649
650 /*
651 * Check the available transmit descriptor, if we had exhausted all
652 * transmit descriptor ,then we have to wait for at least one free
653 * descriptor
654 */
655 txbs_txdp = 1 << priv->NextTxDesc;
656 tmp_data = INW (dev, TXBS);
657
658 if (tmp_data & txbs_txdp) {
659 if (ax88180_poll_tx_complete (dev) < 0) {
660 ax88180_mac_reset (dev);
661 priv->FirstTxDesc = TXDP0;
662 priv->NextTxDesc = TXDP0;
663 printf ("ax88180: Transmit time out occurred!\n");
664 }
665 }
666
667 return 0;
668}
669
670static void ax88180_read_mac_addr (struct eth_device *dev)
671{
672 unsigned short macid0_val, macid1_val, macid2_val;
673 unsigned short tmp_regval;
674 unsigned short i;
675
676 /* Reload MAC address from EEPROM */
677 OUTW (dev, RELOAD_EEPROM, PROMCTRL);
678
679 /* Waiting for reload eeprom completion */
680 for (i = 0; i < 500; i++) {
681 tmp_regval = INW (dev, PROMCTRL);
682 if ((tmp_regval & RELOAD_EEPROM) == 0)
683 break;
Simon Glass0db4b942020-05-10 11:40:10 -0600684 udelay(1000);
Louis Su8dcca362008-07-09 11:01:37 +0800685 }
686
687 /* Get MAC addresses */
688 macid0_val = INW (dev, MACID0);
689 macid1_val = INW (dev, MACID1);
690 macid2_val = INW (dev, MACID2);
691
692 if (((macid0_val | macid1_val | macid2_val) != 0) &&
693 ((macid0_val & 0x01) == 0)) {
694 dev->enetaddr[0] = (unsigned char)macid0_val;
695 dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
696 dev->enetaddr[2] = (unsigned char)macid1_val;
697 dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
698 dev->enetaddr[4] = (unsigned char)macid2_val;
699 dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
700 }
701}
702
Simon Glass49c675e2016-10-17 20:12:34 -0600703/* Exported SubProgram Bodies */
Louis Su8dcca362008-07-09 11:01:37 +0800704int ax88180_initialize (bd_t * bis)
705{
706 struct eth_device *dev;
707 struct ax88180_private *priv;
708
709 dev = (struct eth_device *)malloc (sizeof *dev);
710
711 if (NULL == dev)
712 return 0;
713
714 memset (dev, 0, sizeof *dev);
715
716 priv = (struct ax88180_private *)malloc (sizeof (*priv));
717
718 if (NULL == priv)
719 return 0;
720
721 memset (priv, 0, sizeof *priv);
722
Ben Whitten34fd6c92015-12-30 13:05:58 +0000723 strcpy(dev->name, "ax88180");
Louis Su8dcca362008-07-09 11:01:37 +0800724 dev->iobase = AX88180_BASE;
725 dev->priv = priv;
726 dev->init = ax88180_init;
727 dev->halt = ax88180_halt;
728 dev->send = ax88180_send;
729 dev->recv = ax88180_recv;
730
731 priv->BusWidth = BUS_WIDTH_32;
732 priv->PadSize = 3;
733#if defined (CONFIG_DRIVER_AX88180_16BIT)
734 OUTW (dev, (START_BASE >> 8), BASE);
735 OUTW (dev, DECODE_EN, DECODE);
736
737 priv->BusWidth = BUS_WIDTH_16;
738 priv->PadSize = 1;
739#endif
740
741 ax88180_mac_reset (dev);
742
743 /* Disable interrupt */
744 OUTW (dev, CLEAR_IMR, IMR);
745
746 /* Disable AX88180 TX/RX functions */
747 OUTW (dev, WAKEMOD, CMD);
748
749 ax88180_read_mac_addr (dev);
750
751 eth_register (dev);
752
753 return ax88180_phy_initial (dev);
754
755}