blob: e7365fe062b3e14cb1001e3c4efc2f373bc2506b [file] [log] [blame]
wdenk7ac16102004-08-01 22:48:16 +00001/*
2 dm9000.c: Version 1.2 12/15/2003
3
4 A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
5 Copyright (C) 1997 Sten Wang
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
18
19V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
Wolfgang Denka1be4762008-05-20 16:00:29 +020020 06/22/2001 Support DM9801 progrmming
21 E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
22 E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
23 R17 = (R17 & 0xfff0) | NF + 3
24 E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
25 R17 = (R17 & 0xfff0) | NF
wdenk7ac16102004-08-01 22:48:16 +000026
Wolfgang Denka1be4762008-05-20 16:00:29 +020027v1.00 modify by simon 2001.9.5
wdenk7ac16102004-08-01 22:48:16 +000028 change for kernel 2.4.x
29
Wolfgang Denka1be4762008-05-20 16:00:29 +020030v1.1 11/09/2001 fix force mode bug
wdenk7ac16102004-08-01 22:48:16 +000031
32v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
33 Fixed phy reset.
34 Added tx/rx 32 bit mode.
35 Cleaned up for kernel merge.
36
37--------------------------------------
38
Remy Bohmer5f63bf42008-06-03 15:26:21 +020039 12/15/2003 Initial port to u-boot by
40 Sascha Hauer <saschahauer@web.de>
41
42 06/03/2008 Remy Bohmer <linux@bohmer.net>
Remy Bohmereec38a12008-06-03 15:26:25 +020043 - Fixed the driver to work with DM9000A.
44 (check on ISR receive status bit before reading the
45 FIFO as described in DM9000 programming guide and
46 application notes)
Remy Bohmer5f63bf42008-06-03 15:26:21 +020047 - Added autodetect of databus width.
Remy Bohmerf4329dc2008-06-03 15:26:22 +020048 - Made debug code compile again.
Remy Bohmer16cb2642008-06-03 15:26:23 +020049 - Adapt eth_send such that it matches the DM9000*
50 application notes. Needed to make it work properly
51 for DM9000A.
Remy Bohmer2f13d2c2008-06-03 15:26:24 +020052 - Adapted reset procedure to match DM9000 application
53 notes (i.e. double reset)
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020054 - some minor code cleanups
Remy Bohmer5f63bf42008-06-03 15:26:21 +020055 These changes are tested with DM9000{A,EP,E} together
56 with a 200MHz Atmel AT91SAM92161 core
wdenk7ac16102004-08-01 22:48:16 +000057
58TODO: Homerun NIC and longrun NIC are not functional, only internal at the
59 moment.
60*/
61
62#include <common.h>
63#include <command.h>
64#include <net.h>
65#include <asm/io.h>
66
wdenk7ac16102004-08-01 22:48:16 +000067#include "dm9000x.h"
68
69/* Board/System/Debug information/definition ---------------- */
70
71#define DM9801_NOISE_FLOOR 0x08
72#define DM9802_NOISE_FLOOR 0x05
73
74/* #define CONFIG_DM9000_DEBUG */
75
76#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020077#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
78#define DM9000_DMP_PACKET(func,packet,length) \
79 do { \
80 int i; \
81 printf(func ": length: %d\n", length); \
82 for (i = 0; i < length; i++) { \
83 if (i % 8 == 0) \
84 printf("\n%s: %02x: ", func, i); \
85 printf("%02x ", ((unsigned char *) packet)[i]); \
86 } printf("\n"); \
87 } while(0)
88#else
wdenk7ac16102004-08-01 22:48:16 +000089#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020090#define DM9000_DMP_PACKET(func,packet,length)
91#endif
92
wdenk7ac16102004-08-01 22:48:16 +000093enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD =
94 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO =
95 8, DM9000_1M_HPNA = 0x10
96};
97enum DM9000_NIC_TYPE { FASTETHER_NIC = 0, HOMERUN_NIC = 1, LONGRUN_NIC = 2
98};
99
100/* Structure/enum declaration ------------------------------- */
101typedef struct board_info {
102 u32 runt_length_counter; /* counter: RX length < 64byte */
103 u32 long_length_counter; /* counter: RX length > 1514byte */
104 u32 reset_counter; /* counter: RESET */
105 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
106 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
107 u16 tx_pkt_cnt;
108 u16 queue_start_addr;
109 u16 dbug_cnt;
110 u8 phy_addr;
111 u8 device_wait_reset; /* device state */
112 u8 nic_type; /* NIC type */
113 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200114 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200115 void (*inblk)(void *data_ptr, int count);
116 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200117} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200118static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000119
120/* For module input parameter */
121static int media_mode = DM9000_AUTO;
122static u8 nfloor = 0;
123
124/* function declaration ------------------------------------- */
125int eth_init(bd_t * bd);
126int eth_send(volatile void *, int);
127int eth_rx(void);
128void eth_halt(void);
129static int dm9000_probe(void);
130static u16 phy_read(int);
131static void phy_write(int, u16);
stefano babic6708a602007-08-30 23:01:49 +0200132u16 read_srom_word(int);
wdenk7ac16102004-08-01 22:48:16 +0000133static u8 DM9000_ior(int);
134static void DM9000_iow(int reg, u8 value);
135
136/* DM9000 network board routine ---------------------------- */
137
138#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
139#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
140#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
141#define DM9000_inb(r) (*(volatile u8 *)r)
142#define DM9000_inw(r) (*(volatile u16 *)r)
143#define DM9000_inl(r) (*(volatile u32 *)r)
144
145#ifdef CONFIG_DM9000_DEBUG
146static void
147dump_regs(void)
148{
149 DM9000_DBG("\n");
150 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
151 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
152 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
153 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
154 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
155 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
156 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200157 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000158 DM9000_DBG("\n");
159}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200160#endif
161
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200162static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200163{
164 int i;
165 for (i = 0; i < count; i++)
166 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
167}
168
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200169static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200170{
171 int i;
172 u32 tmplen = (count + 1) / 2;
173
174 for (i = 0; i < tmplen; i++)
175 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
176}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200177static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200178{
179 int i;
180 u32 tmplen = (count + 3) / 4;
181
182 for (i = 0; i < tmplen; i++)
183 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
184}
185
186static void dm9000_inblk_8bit(void *data_ptr, int count)
187{
188 int i;
189 for (i = 0; i < count; i++)
190 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
191}
192
193static void dm9000_inblk_16bit(void *data_ptr, int count)
194{
195 int i;
196 u32 tmplen = (count + 1) / 2;
197
198 for (i = 0; i < tmplen; i++)
199 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
200}
201static void dm9000_inblk_32bit(void *data_ptr, int count)
202{
203 int i;
204 u32 tmplen = (count + 3) / 4;
205
206 for (i = 0; i < tmplen; i++)
207 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
208}
209
210static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
211{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200212 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200213
214 DM9000_outb(DM9000_MRCMD, DM9000_IO);
215
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200216 tmpdata = DM9000_inl(DM9000_DATA);
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500217 *RxStatus = __le16_to_cpu(tmpdata);
218 *RxLen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200219}
220
221static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
222{
223 DM9000_outb(DM9000_MRCMD, DM9000_IO);
224
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500225 *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
226 *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200227}
228
229static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
230{
231 DM9000_outb(DM9000_MRCMD, DM9000_IO);
232
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500233 *RxStatus =
234 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
235 (DM9000_inb(DM9000_DATA) << 8));
236 *RxLen =
237 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
238 (DM9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200239}
wdenk7ac16102004-08-01 22:48:16 +0000240
241/*
242 Search DM9000 board, allocate space and register it
243*/
244int
245dm9000_probe(void)
246{
247 u32 id_val;
248 id_val = DM9000_ior(DM9000_VIDL);
249 id_val |= DM9000_ior(DM9000_VIDH) << 8;
250 id_val |= DM9000_ior(DM9000_PIDL) << 16;
251 id_val |= DM9000_ior(DM9000_PIDH) << 24;
252 if (id_val == DM9000_ID) {
253 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
254 id_val);
255 return 0;
256 } else {
257 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
258 CONFIG_DM9000_BASE, id_val);
259 return -1;
260 }
261}
262
263/* Set PHY operationg mode
264*/
265static void
266set_PHY_mode(void)
267{
268 u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
269 if (!(media_mode & DM9000_AUTO)) {
270 switch (media_mode) {
271 case DM9000_10MHD:
272 phy_reg4 = 0x21;
273 phy_reg0 = 0x0000;
274 break;
275 case DM9000_10MFD:
276 phy_reg4 = 0x41;
277 phy_reg0 = 0x1100;
278 break;
279 case DM9000_100MHD:
280 phy_reg4 = 0x81;
281 phy_reg0 = 0x2000;
282 break;
283 case DM9000_100MFD:
284 phy_reg4 = 0x101;
285 phy_reg0 = 0x3100;
286 break;
287 }
288 phy_write(4, phy_reg4); /* Set PHY media mode */
289 phy_write(0, phy_reg0); /* Tmp */
290 }
291 DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */
292 DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */
293}
294
295/*
296 Init HomeRun DM9801
297*/
298static void
299program_dm9801(u16 HPNA_rev)
300{
301 __u16 reg16, reg17, reg24, reg25;
302 if (!nfloor)
303 nfloor = DM9801_NOISE_FLOOR;
304 reg16 = phy_read(16);
305 reg17 = phy_read(17);
306 reg24 = phy_read(24);
307 reg25 = phy_read(25);
308 switch (HPNA_rev) {
309 case 0xb900: /* DM9801 E3 */
310 reg16 |= 0x1000;
311 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000;
312 break;
313 case 0xb901: /* DM9801 E4 */
314 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200;
315 reg17 = (reg17 & 0xfff0) + nfloor + 3;
316 break;
317 case 0xb902: /* DM9801 E5 */
318 case 0xb903: /* DM9801 E6 */
319 default:
320 reg16 |= 0x1000;
321 reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200;
322 reg17 = (reg17 & 0xfff0) + nfloor;
323 }
324 phy_write(16, reg16);
325 phy_write(17, reg17);
326 phy_write(25, reg25);
327}
328
329/*
330 Init LongRun DM9802
331*/
332static void
333program_dm9802(void)
334{
335 __u16 reg25;
336 if (!nfloor)
337 nfloor = DM9802_NOISE_FLOOR;
338 reg25 = phy_read(25);
339 reg25 = (reg25 & 0xff00) + nfloor;
340 phy_write(25, reg25);
341}
342
343/* Identify NIC type
344*/
345static void
346identify_nic(void)
347{
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200348 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000349 u16 phy_reg3;
350 DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
351 phy_reg3 = phy_read(3);
352 switch (phy_reg3 & 0xfff0) {
353 case 0xb900:
354 if (phy_read(31) == 0x4404) {
355 db->nic_type = HOMERUN_NIC;
356 program_dm9801(phy_reg3);
357 DM9000_DBG("found homerun NIC\n");
358 } else {
359 db->nic_type = LONGRUN_NIC;
360 DM9000_DBG("found longrun NIC\n");
361 program_dm9802();
362 }
363 break;
364 default:
365 db->nic_type = FASTETHER_NIC;
366 break;
367 }
368 DM9000_iow(DM9000_NCR, 0);
369}
370
371/* General Purpose dm9000 reset routine */
372static void
373dm9000_reset(void)
374{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200375 DM9000_DBG("resetting DM9000\n");
376
377 /* Reset DM9000,
378 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
379
380 /* DEBUG: Make all GPIO pins outputs */
381 DM9000_iow(DM9000_GPCR, 0x0F);
382 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
383 DM9000_iow(DM9000_GPR, 0);
384 /* Step 2: Software reset */
385 DM9000_iow(DM9000_NCR, 3);
386
387 do {
388 DM9000_DBG("resetting the DM9000, 1st reset\n");
389 udelay(25); /* Wait at least 20 us */
390 } while (DM9000_ior(DM9000_NCR) & 1);
391
392 DM9000_iow(DM9000_NCR, 0);
393 DM9000_iow(DM9000_NCR, 3); /* Issue a second reset */
394
395 do {
396 DM9000_DBG("resetting the DM9000, 2nd reset\n");
397 udelay(25); /* Wait at least 20 us */
398 } while (DM9000_ior(DM9000_NCR) & 1);
399
400 /* Check whether the ethernet controller is present */
401 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
402 (DM9000_ior(DM9000_PIDH) != 0x90))
403 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000404}
405
406/* Initilize dm9000 board
407*/
408int
409eth_init(bd_t * bd)
410{
411 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200412 u8 io_mode;
413 struct board_info *db = &dm9000_info;
414
wdenk7ac16102004-08-01 22:48:16 +0000415 DM9000_DBG("eth_init()\n");
416
417 /* RESET device */
418 dm9000_reset();
419 dm9000_probe();
420
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200421 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
422 io_mode = DM9000_ior(DM9000_ISR) >> 6;
423
424 switch (io_mode) {
425 case 0x0: /* 16-bit mode */
426 printf("DM9000: running in 16 bit mode\n");
427 db->outblk = dm9000_outblk_16bit;
428 db->inblk = dm9000_inblk_16bit;
429 db->rx_status = dm9000_rx_status_16bit;
430 break;
431 case 0x01: /* 32-bit mode */
432 printf("DM9000: running in 32 bit mode\n");
433 db->outblk = dm9000_outblk_32bit;
434 db->inblk = dm9000_inblk_32bit;
435 db->rx_status = dm9000_rx_status_32bit;
436 break;
437 case 0x02: /* 8 bit mode */
438 printf("DM9000: running in 8 bit mode\n");
439 db->outblk = dm9000_outblk_8bit;
440 db->inblk = dm9000_inblk_8bit;
441 db->rx_status = dm9000_rx_status_8bit;
442 break;
443 default:
444 /* Assume 8 bit mode, will probably not work anyway */
445 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
446 db->outblk = dm9000_outblk_8bit;
447 db->inblk = dm9000_inblk_8bit;
448 db->rx_status = dm9000_rx_status_8bit;
449 break;
450 }
451
wdenk7ac16102004-08-01 22:48:16 +0000452 /* NIC Type: FASTETHER, HOMERUN, LONGRUN */
453 identify_nic();
454
455 /* GPIO0 on pre-activate PHY */
456 DM9000_iow(DM9000_GPR, 0x00); /*REG_1F bit0 activate phyxcer */
457
458 /* Set PHY */
459 set_PHY_mode();
460
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200461 /* Program operating register, only intern phy supported by now */
462 DM9000_iow(DM9000_NCR, 0x0);
463 /* TX Polling clear */
464 DM9000_iow(DM9000_TCR, 0);
465 /* Less 3Kb, 200us */
466 DM9000_iow(DM9000_BPTR, 0x3f);
467 /* Flow Control : High/Low Water */
468 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
469 /* SH FIXME: This looks strange! Flow Control */
470 DM9000_iow(DM9000_FCR, 0x0);
471 /* Special Mode */
472 DM9000_iow(DM9000_SMCR, 0);
473 /* clear TX status */
474 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
475 /* Clear interrupt status */
476 DM9000_iow(DM9000_ISR, 0x0f);
wdenk7ac16102004-08-01 22:48:16 +0000477
478 /* Set Node address */
Stelian Pop61e69d72008-05-08 20:52:22 +0200479#ifndef CONFIG_AT91SAM9261EK
wdenk7ac16102004-08-01 22:48:16 +0000480 for (i = 0; i < 6; i++)
481 ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
Stelian Pop61e69d72008-05-08 20:52:22 +0200482#endif
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300483
stefano babicedb06872007-08-21 15:50:33 +0200484 if (is_zero_ether_addr(bd->bi_enetaddr) ||
485 is_multicast_ether_addr(bd->bi_enetaddr)) {
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300486 /* try reading from environment */
487 u8 i;
488 char *s, *e;
489 s = getenv ("ethaddr");
490 for (i = 0; i < 6; ++i) {
491 bd->bi_enetaddr[i] = s ?
492 simple_strtoul (s, &e, 16) : 0;
493 if (s)
494 s = (*e) ? e + 1 : e;
495 }
496 }
497
wdenk7ac16102004-08-01 22:48:16 +0000498 printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
499 bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
500 bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
501 for (i = 0, oft = 0x10; i < 6; i++, oft++)
502 DM9000_iow(oft, bd->bi_enetaddr[i]);
503 for (i = 0, oft = 0x16; i < 8; i++, oft++)
504 DM9000_iow(oft, 0xff);
505
506 /* read back mac, just to be sure */
507 for (i = 0, oft = 0x10; i < 6; i++, oft++)
508 DM9000_DBG("%02x:", DM9000_ior(oft));
509 DM9000_DBG("\n");
510
511 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200512 /* RX enable */
513 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
514 /* Enable TX/RX interrupt mask */
515 DM9000_iow(DM9000_IMR, IMR_PAR);
516
wdenk7ac16102004-08-01 22:48:16 +0000517 i = 0;
518 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
519 udelay(1000);
520 i++;
521 if (i == 10000) {
522 printf("could not establish link\n");
523 return 0;
524 }
525 }
526
527 /* see what we've got */
528 lnk = phy_read(17) >> 12;
529 printf("operating at ");
530 switch (lnk) {
531 case 1:
532 printf("10M half duplex ");
533 break;
534 case 2:
535 printf("10M full duplex ");
536 break;
537 case 4:
538 printf("100M half duplex ");
539 break;
540 case 8:
541 printf("100M full duplex ");
542 break;
543 default:
544 printf("unknown: %d ", lnk);
545 break;
546 }
547 printf("mode\n");
548 return 0;
549}
550
551/*
552 Hardware start transmission.
553 Send a packet to media from the upper layer.
554*/
555int
556eth_send(volatile void *packet, int length)
557{
wdenk7ac16102004-08-01 22:48:16 +0000558 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200559 struct board_info *db = &dm9000_info;
560
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200561 DM9000_DMP_PACKET("eth_send", packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000562
Remy Bohmer16cb2642008-06-03 15:26:23 +0200563 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
564
wdenk7ac16102004-08-01 22:48:16 +0000565 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200566 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000567
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200568 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200569 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000570
571 /* Set TX length to DM9000 */
572 DM9000_iow(DM9000_TXPLL, length & 0xff);
573 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
574
575 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200576 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000577
578 /* wait for end of transmission */
579 tmo = get_timer(0) + 5 * CFG_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200580 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
581 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000582 if (get_timer(0) >= tmo) {
583 printf("transmission timeout\n");
584 break;
585 }
586 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200587 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
588
wdenk7ac16102004-08-01 22:48:16 +0000589 DM9000_DBG("transmit done\n\n");
590 return 0;
591}
592
593/*
594 Stop the interface.
595 The interface is stopped when it is brought.
596*/
597void
598eth_halt(void)
599{
600 DM9000_DBG("eth_halt\n");
601
602 /* RESET devie */
603 phy_write(0, 0x8000); /* PHY RESET */
604 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
605 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
606 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
607}
608
609/*
610 Received a packet and pass to upper layer
611*/
612int
613eth_rx(void)
614{
615 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
616 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200617 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000618
Remy Bohmereec38a12008-06-03 15:26:25 +0200619 /* Check packet ready or not, we must check
620 the ISR status first for DM9000A */
621 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000622 return 0;
623
Remy Bohmereec38a12008-06-03 15:26:25 +0200624 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000625
Remy Bohmereec38a12008-06-03 15:26:25 +0200626 /* There is _at least_ 1 package in the fifo, read them all */
627 for (;;) {
628 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000629
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200630 /* Get most updated data,
631 only look at bits 0:1, See application notes DM9000 */
632 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000633
Remy Bohmereec38a12008-06-03 15:26:25 +0200634 /* Status check: this byte must be 0 or 1 */
635 if (rxbyte > DM9000_PKT_RDY) {
636 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
637 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
638 printf("DM9000 error: status check fail: 0x%x\n",
639 rxbyte);
640 return 0;
641 }
wdenk7ac16102004-08-01 22:48:16 +0000642
Remy Bohmereec38a12008-06-03 15:26:25 +0200643 if (rxbyte != DM9000_PKT_RDY)
644 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000645
Remy Bohmereec38a12008-06-03 15:26:25 +0200646 DM9000_DBG("receiving packet\n");
647
648 /* A packet ready now & Get status/length */
649 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000650
Remy Bohmereec38a12008-06-03 15:26:25 +0200651 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
652
653 /* Move data from DM9000 */
654 /* Read received packet from RX SRAM */
655 (db->inblk)(rdptr, RxLen);
656
657 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
658 || (RxLen > DM9000_PKT_MAX)) {
659 if (RxStatus & 0x100) {
660 printf("rx fifo error\n");
661 }
662 if (RxStatus & 0x200) {
663 printf("rx crc error\n");
664 }
665 if (RxStatus & 0x8000) {
666 printf("rx length error\n");
667 }
668 if (RxLen > DM9000_PKT_MAX) {
669 printf("rx length too big\n");
670 dm9000_reset();
671 }
672 } else {
673 DM9000_DMP_PACKET("eth_rx", rdptr, RxLen);
674
675 DM9000_DBG("passing packet to upper layer\n");
676 NetReceive(NetRxPackets[0], RxLen);
677 }
wdenk7ac16102004-08-01 22:48:16 +0000678 }
679 return 0;
680}
681
682/*
683 Read a word data from SROM
684*/
stefano babic6708a602007-08-30 23:01:49 +0200685u16
wdenk7ac16102004-08-01 22:48:16 +0000686read_srom_word(int offset)
687{
688 DM9000_iow(DM9000_EPAR, offset);
689 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200690 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000691 DM9000_iow(DM9000_EPCR, 0x0);
692 return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
693}
694
stefano babic6708a602007-08-30 23:01:49 +0200695void
696write_srom_word(int offset, u16 val)
697{
698 DM9000_iow(DM9000_EPAR, offset);
699 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
700 DM9000_iow(DM9000_EPDRL, (val & 0xff));
701 DM9000_iow(DM9000_EPCR, 0x12);
702 udelay(8000);
703 DM9000_iow(DM9000_EPCR, 0);
704}
705
706
wdenk7ac16102004-08-01 22:48:16 +0000707/*
708 Read a byte from I/O port
709*/
710static u8
711DM9000_ior(int reg)
712{
713 DM9000_outb(reg, DM9000_IO);
714 return DM9000_inb(DM9000_DATA);
715}
716
717/*
718 Write a byte to I/O port
719*/
720static void
721DM9000_iow(int reg, u8 value)
722{
723 DM9000_outb(reg, DM9000_IO);
724 DM9000_outb(value, DM9000_DATA);
725}
726
727/*
728 Read a word from phyxcer
729*/
730static u16
731phy_read(int reg)
732{
733 u16 val;
734
735 /* Fill the phyxcer register into REG_0C */
736 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
737 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200738 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000739 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
740 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
741
742 /* The read data keeps on REG_0D & REG_0E */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200743 DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000744 return val;
745}
746
747/*
748 Write a word to phyxcer
749*/
750static void
751phy_write(int reg, u16 value)
752{
753
754 /* Fill the phyxcer register into REG_0C */
755 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
756
757 /* Fill the written data into REG_0D & REG_0E */
758 DM9000_iow(DM9000_EPDRL, (value & 0xff));
759 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
760 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200761 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000762 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200763 DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000764}