blob: 2945995457bc630a144bec21ceb5220593938300 [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
67#ifdef CONFIG_DRIVER_DM9000
68
69#include "dm9000x.h"
70
71/* Board/System/Debug information/definition ---------------- */
72
73#define DM9801_NOISE_FLOOR 0x08
74#define DM9802_NOISE_FLOOR 0x05
75
76/* #define CONFIG_DM9000_DEBUG */
77
78#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020079#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
80#define DM9000_DMP_PACKET(func,packet,length) \
81 do { \
82 int i; \
83 printf(func ": length: %d\n", length); \
84 for (i = 0; i < length; i++) { \
85 if (i % 8 == 0) \
86 printf("\n%s: %02x: ", func, i); \
87 printf("%02x ", ((unsigned char *) packet)[i]); \
88 } printf("\n"); \
89 } while(0)
90#else
wdenk7ac16102004-08-01 22:48:16 +000091#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020092#define DM9000_DMP_PACKET(func,packet,length)
93#endif
94
wdenk7ac16102004-08-01 22:48:16 +000095enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD =
96 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO =
97 8, DM9000_1M_HPNA = 0x10
98};
99enum DM9000_NIC_TYPE { FASTETHER_NIC = 0, HOMERUN_NIC = 1, LONGRUN_NIC = 2
100};
101
102/* Structure/enum declaration ------------------------------- */
103typedef struct board_info {
104 u32 runt_length_counter; /* counter: RX length < 64byte */
105 u32 long_length_counter; /* counter: RX length > 1514byte */
106 u32 reset_counter; /* counter: RESET */
107 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
108 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
109 u16 tx_pkt_cnt;
110 u16 queue_start_addr;
111 u16 dbug_cnt;
112 u8 phy_addr;
113 u8 device_wait_reset; /* device state */
114 u8 nic_type; /* NIC type */
115 unsigned char srom[128];
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200116 void (*outblk)(void *data_ptr, int count);
117 void (*inblk)(void *data_ptr, int count);
118 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200119} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200120static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000121
122/* For module input parameter */
123static int media_mode = DM9000_AUTO;
124static u8 nfloor = 0;
125
126/* function declaration ------------------------------------- */
127int eth_init(bd_t * bd);
128int eth_send(volatile void *, int);
129int eth_rx(void);
130void eth_halt(void);
131static int dm9000_probe(void);
132static u16 phy_read(int);
133static void phy_write(int, u16);
stefano babic6708a602007-08-30 23:01:49 +0200134u16 read_srom_word(int);
wdenk7ac16102004-08-01 22:48:16 +0000135static u8 DM9000_ior(int);
136static void DM9000_iow(int reg, u8 value);
137
138/* DM9000 network board routine ---------------------------- */
139
140#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
141#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
142#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
143#define DM9000_inb(r) (*(volatile u8 *)r)
144#define DM9000_inw(r) (*(volatile u16 *)r)
145#define DM9000_inl(r) (*(volatile u32 *)r)
146
147#ifdef CONFIG_DM9000_DEBUG
148static void
149dump_regs(void)
150{
151 DM9000_DBG("\n");
152 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
153 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
154 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
155 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
156 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
157 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
158 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200159 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000160 DM9000_DBG("\n");
161}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200162#endif
163
164static void dm9000_outblk_8bit(void *data_ptr, int count)
165{
166 int i;
167 for (i = 0; i < count; i++)
168 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
169}
170
171static void dm9000_outblk_16bit(void *data_ptr, int count)
172{
173 int i;
174 u32 tmplen = (count + 1) / 2;
175
176 for (i = 0; i < tmplen; i++)
177 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
178}
179static void dm9000_outblk_32bit(void *data_ptr, int count)
180{
181 int i;
182 u32 tmplen = (count + 3) / 4;
183
184 for (i = 0; i < tmplen; i++)
185 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
186}
187
188static void dm9000_inblk_8bit(void *data_ptr, int count)
189{
190 int i;
191 for (i = 0; i < count; i++)
192 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
193}
194
195static void dm9000_inblk_16bit(void *data_ptr, int count)
196{
197 int i;
198 u32 tmplen = (count + 1) / 2;
199
200 for (i = 0; i < tmplen; i++)
201 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
202}
203static void dm9000_inblk_32bit(void *data_ptr, int count)
204{
205 int i;
206 u32 tmplen = (count + 3) / 4;
207
208 for (i = 0; i < tmplen; i++)
209 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
210}
211
212static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
213{
214 u32 tmpdata = DM9000_inl(DM9000_DATA);
215
216 DM9000_outb(DM9000_MRCMD, DM9000_IO);
217
218 *RxStatus = tmpdata;
219 *RxLen = tmpdata >> 16;
220}
221
222static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
223{
224 DM9000_outb(DM9000_MRCMD, DM9000_IO);
225
226 *RxStatus = DM9000_inw(DM9000_DATA);
227 *RxLen = DM9000_inw(DM9000_DATA);
228}
229
230static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
231{
232 DM9000_outb(DM9000_MRCMD, DM9000_IO);
233
234 *RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
235 *RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
236}
wdenk7ac16102004-08-01 22:48:16 +0000237
238/*
239 Search DM9000 board, allocate space and register it
240*/
241int
242dm9000_probe(void)
243{
244 u32 id_val;
245 id_val = DM9000_ior(DM9000_VIDL);
246 id_val |= DM9000_ior(DM9000_VIDH) << 8;
247 id_val |= DM9000_ior(DM9000_PIDL) << 16;
248 id_val |= DM9000_ior(DM9000_PIDH) << 24;
249 if (id_val == DM9000_ID) {
250 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
251 id_val);
252 return 0;
253 } else {
254 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
255 CONFIG_DM9000_BASE, id_val);
256 return -1;
257 }
258}
259
260/* Set PHY operationg mode
261*/
262static void
263set_PHY_mode(void)
264{
265 u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
266 if (!(media_mode & DM9000_AUTO)) {
267 switch (media_mode) {
268 case DM9000_10MHD:
269 phy_reg4 = 0x21;
270 phy_reg0 = 0x0000;
271 break;
272 case DM9000_10MFD:
273 phy_reg4 = 0x41;
274 phy_reg0 = 0x1100;
275 break;
276 case DM9000_100MHD:
277 phy_reg4 = 0x81;
278 phy_reg0 = 0x2000;
279 break;
280 case DM9000_100MFD:
281 phy_reg4 = 0x101;
282 phy_reg0 = 0x3100;
283 break;
284 }
285 phy_write(4, phy_reg4); /* Set PHY media mode */
286 phy_write(0, phy_reg0); /* Tmp */
287 }
288 DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */
289 DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */
290}
291
292/*
293 Init HomeRun DM9801
294*/
295static void
296program_dm9801(u16 HPNA_rev)
297{
298 __u16 reg16, reg17, reg24, reg25;
299 if (!nfloor)
300 nfloor = DM9801_NOISE_FLOOR;
301 reg16 = phy_read(16);
302 reg17 = phy_read(17);
303 reg24 = phy_read(24);
304 reg25 = phy_read(25);
305 switch (HPNA_rev) {
306 case 0xb900: /* DM9801 E3 */
307 reg16 |= 0x1000;
308 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000;
309 break;
310 case 0xb901: /* DM9801 E4 */
311 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200;
312 reg17 = (reg17 & 0xfff0) + nfloor + 3;
313 break;
314 case 0xb902: /* DM9801 E5 */
315 case 0xb903: /* DM9801 E6 */
316 default:
317 reg16 |= 0x1000;
318 reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200;
319 reg17 = (reg17 & 0xfff0) + nfloor;
320 }
321 phy_write(16, reg16);
322 phy_write(17, reg17);
323 phy_write(25, reg25);
324}
325
326/*
327 Init LongRun DM9802
328*/
329static void
330program_dm9802(void)
331{
332 __u16 reg25;
333 if (!nfloor)
334 nfloor = DM9802_NOISE_FLOOR;
335 reg25 = phy_read(25);
336 reg25 = (reg25 & 0xff00) + nfloor;
337 phy_write(25, reg25);
338}
339
340/* Identify NIC type
341*/
342static void
343identify_nic(void)
344{
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200345 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000346 u16 phy_reg3;
347 DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
348 phy_reg3 = phy_read(3);
349 switch (phy_reg3 & 0xfff0) {
350 case 0xb900:
351 if (phy_read(31) == 0x4404) {
352 db->nic_type = HOMERUN_NIC;
353 program_dm9801(phy_reg3);
354 DM9000_DBG("found homerun NIC\n");
355 } else {
356 db->nic_type = LONGRUN_NIC;
357 DM9000_DBG("found longrun NIC\n");
358 program_dm9802();
359 }
360 break;
361 default:
362 db->nic_type = FASTETHER_NIC;
363 break;
364 }
365 DM9000_iow(DM9000_NCR, 0);
366}
367
368/* General Purpose dm9000 reset routine */
369static void
370dm9000_reset(void)
371{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200372 DM9000_DBG("resetting DM9000\n");
373
374 /* Reset DM9000,
375 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
376
377 /* DEBUG: Make all GPIO pins outputs */
378 DM9000_iow(DM9000_GPCR, 0x0F);
379 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
380 DM9000_iow(DM9000_GPR, 0);
381 /* Step 2: Software reset */
382 DM9000_iow(DM9000_NCR, 3);
383
384 do {
385 DM9000_DBG("resetting the DM9000, 1st reset\n");
386 udelay(25); /* Wait at least 20 us */
387 } while (DM9000_ior(DM9000_NCR) & 1);
388
389 DM9000_iow(DM9000_NCR, 0);
390 DM9000_iow(DM9000_NCR, 3); /* Issue a second reset */
391
392 do {
393 DM9000_DBG("resetting the DM9000, 2nd reset\n");
394 udelay(25); /* Wait at least 20 us */
395 } while (DM9000_ior(DM9000_NCR) & 1);
396
397 /* Check whether the ethernet controller is present */
398 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
399 (DM9000_ior(DM9000_PIDH) != 0x90))
400 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000401}
402
403/* Initilize dm9000 board
404*/
405int
406eth_init(bd_t * bd)
407{
408 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200409 u8 io_mode;
410 struct board_info *db = &dm9000_info;
411
wdenk7ac16102004-08-01 22:48:16 +0000412 DM9000_DBG("eth_init()\n");
413
414 /* RESET device */
415 dm9000_reset();
416 dm9000_probe();
417
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200418 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
419 io_mode = DM9000_ior(DM9000_ISR) >> 6;
420
421 switch (io_mode) {
422 case 0x0: /* 16-bit mode */
423 printf("DM9000: running in 16 bit mode\n");
424 db->outblk = dm9000_outblk_16bit;
425 db->inblk = dm9000_inblk_16bit;
426 db->rx_status = dm9000_rx_status_16bit;
427 break;
428 case 0x01: /* 32-bit mode */
429 printf("DM9000: running in 32 bit mode\n");
430 db->outblk = dm9000_outblk_32bit;
431 db->inblk = dm9000_inblk_32bit;
432 db->rx_status = dm9000_rx_status_32bit;
433 break;
434 case 0x02: /* 8 bit mode */
435 printf("DM9000: running in 8 bit mode\n");
436 db->outblk = dm9000_outblk_8bit;
437 db->inblk = dm9000_inblk_8bit;
438 db->rx_status = dm9000_rx_status_8bit;
439 break;
440 default:
441 /* Assume 8 bit mode, will probably not work anyway */
442 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
443 db->outblk = dm9000_outblk_8bit;
444 db->inblk = dm9000_inblk_8bit;
445 db->rx_status = dm9000_rx_status_8bit;
446 break;
447 }
448
wdenk7ac16102004-08-01 22:48:16 +0000449 /* NIC Type: FASTETHER, HOMERUN, LONGRUN */
450 identify_nic();
451
452 /* GPIO0 on pre-activate PHY */
453 DM9000_iow(DM9000_GPR, 0x00); /*REG_1F bit0 activate phyxcer */
454
455 /* Set PHY */
456 set_PHY_mode();
457
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200458 /* Program operating register, only intern phy supported by now */
459 DM9000_iow(DM9000_NCR, 0x0);
460 /* TX Polling clear */
461 DM9000_iow(DM9000_TCR, 0);
462 /* Less 3Kb, 200us */
463 DM9000_iow(DM9000_BPTR, 0x3f);
464 /* Flow Control : High/Low Water */
465 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
466 /* SH FIXME: This looks strange! Flow Control */
467 DM9000_iow(DM9000_FCR, 0x0);
468 /* Special Mode */
469 DM9000_iow(DM9000_SMCR, 0);
470 /* clear TX status */
471 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
472 /* Clear interrupt status */
473 DM9000_iow(DM9000_ISR, 0x0f);
wdenk7ac16102004-08-01 22:48:16 +0000474
475 /* Set Node address */
476 for (i = 0; i < 6; i++)
477 ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300478
stefano babicedb06872007-08-21 15:50:33 +0200479 if (is_zero_ether_addr(bd->bi_enetaddr) ||
480 is_multicast_ether_addr(bd->bi_enetaddr)) {
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300481 /* try reading from environment */
482 u8 i;
483 char *s, *e;
484 s = getenv ("ethaddr");
485 for (i = 0; i < 6; ++i) {
486 bd->bi_enetaddr[i] = s ?
487 simple_strtoul (s, &e, 16) : 0;
488 if (s)
489 s = (*e) ? e + 1 : e;
490 }
491 }
492
wdenk7ac16102004-08-01 22:48:16 +0000493 printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
494 bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
495 bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
496 for (i = 0, oft = 0x10; i < 6; i++, oft++)
497 DM9000_iow(oft, bd->bi_enetaddr[i]);
498 for (i = 0, oft = 0x16; i < 8; i++, oft++)
499 DM9000_iow(oft, 0xff);
500
501 /* read back mac, just to be sure */
502 for (i = 0, oft = 0x10; i < 6; i++, oft++)
503 DM9000_DBG("%02x:", DM9000_ior(oft));
504 DM9000_DBG("\n");
505
506 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200507 /* RX enable */
508 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
509 /* Enable TX/RX interrupt mask */
510 DM9000_iow(DM9000_IMR, IMR_PAR);
511
wdenk7ac16102004-08-01 22:48:16 +0000512 i = 0;
513 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
514 udelay(1000);
515 i++;
516 if (i == 10000) {
517 printf("could not establish link\n");
518 return 0;
519 }
520 }
521
522 /* see what we've got */
523 lnk = phy_read(17) >> 12;
524 printf("operating at ");
525 switch (lnk) {
526 case 1:
527 printf("10M half duplex ");
528 break;
529 case 2:
530 printf("10M full duplex ");
531 break;
532 case 4:
533 printf("100M half duplex ");
534 break;
535 case 8:
536 printf("100M full duplex ");
537 break;
538 default:
539 printf("unknown: %d ", lnk);
540 break;
541 }
542 printf("mode\n");
543 return 0;
544}
545
546/*
547 Hardware start transmission.
548 Send a packet to media from the upper layer.
549*/
550int
551eth_send(volatile void *packet, int length)
552{
553 char *data_ptr;
wdenk7ac16102004-08-01 22:48:16 +0000554 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200555 struct board_info *db = &dm9000_info;
556
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200557 DM9000_DMP_PACKET("eth_send", packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000558
Remy Bohmer16cb2642008-06-03 15:26:23 +0200559 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
560
wdenk7ac16102004-08-01 22:48:16 +0000561 /* Move data to DM9000 TX RAM */
562 data_ptr = (char *) packet;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200563 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000564
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200565 /* push the data to the TX-fifo */
566 (db->outblk)(data_ptr, length);
wdenk7ac16102004-08-01 22:48:16 +0000567
568 /* Set TX length to DM9000 */
569 DM9000_iow(DM9000_TXPLL, length & 0xff);
570 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
571
572 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200573 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000574
575 /* wait for end of transmission */
576 tmo = get_timer(0) + 5 * CFG_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200577 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
578 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000579 if (get_timer(0) >= tmo) {
580 printf("transmission timeout\n");
581 break;
582 }
583 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200584 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
585
wdenk7ac16102004-08-01 22:48:16 +0000586 DM9000_DBG("transmit done\n\n");
587 return 0;
588}
589
590/*
591 Stop the interface.
592 The interface is stopped when it is brought.
593*/
594void
595eth_halt(void)
596{
597 DM9000_DBG("eth_halt\n");
598
599 /* RESET devie */
600 phy_write(0, 0x8000); /* PHY RESET */
601 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
602 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
603 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
604}
605
606/*
607 Received a packet and pass to upper layer
608*/
609int
610eth_rx(void)
611{
612 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
613 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200614 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000615
Remy Bohmereec38a12008-06-03 15:26:25 +0200616 /* Check packet ready or not, we must check
617 the ISR status first for DM9000A */
618 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000619 return 0;
620
Remy Bohmereec38a12008-06-03 15:26:25 +0200621 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000622
Remy Bohmereec38a12008-06-03 15:26:25 +0200623 /* There is _at least_ 1 package in the fifo, read them all */
624 for (;;) {
625 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000626
Remy Bohmereec38a12008-06-03 15:26:25 +0200627 /* Get most updated data */
628 rxbyte = DM9000_inb(DM9000_DATA);
wdenk7ac16102004-08-01 22:48:16 +0000629
Remy Bohmereec38a12008-06-03 15:26:25 +0200630 /* Status check: this byte must be 0 or 1 */
631 if (rxbyte > DM9000_PKT_RDY) {
632 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
633 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
634 printf("DM9000 error: status check fail: 0x%x\n",
635 rxbyte);
636 return 0;
637 }
wdenk7ac16102004-08-01 22:48:16 +0000638
Remy Bohmereec38a12008-06-03 15:26:25 +0200639 if (rxbyte != DM9000_PKT_RDY)
640 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000641
Remy Bohmereec38a12008-06-03 15:26:25 +0200642 DM9000_DBG("receiving packet\n");
643
644 /* A packet ready now & Get status/length */
645 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000646
Remy Bohmereec38a12008-06-03 15:26:25 +0200647 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
648
649 /* Move data from DM9000 */
650 /* Read received packet from RX SRAM */
651 (db->inblk)(rdptr, RxLen);
652
653 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
654 || (RxLen > DM9000_PKT_MAX)) {
655 if (RxStatus & 0x100) {
656 printf("rx fifo error\n");
657 }
658 if (RxStatus & 0x200) {
659 printf("rx crc error\n");
660 }
661 if (RxStatus & 0x8000) {
662 printf("rx length error\n");
663 }
664 if (RxLen > DM9000_PKT_MAX) {
665 printf("rx length too big\n");
666 dm9000_reset();
667 }
668 } else {
669 DM9000_DMP_PACKET("eth_rx", rdptr, RxLen);
670
671 DM9000_DBG("passing packet to upper layer\n");
672 NetReceive(NetRxPackets[0], RxLen);
673 }
wdenk7ac16102004-08-01 22:48:16 +0000674 }
675 return 0;
676}
677
678/*
679 Read a word data from SROM
680*/
stefano babic6708a602007-08-30 23:01:49 +0200681u16
wdenk7ac16102004-08-01 22:48:16 +0000682read_srom_word(int offset)
683{
684 DM9000_iow(DM9000_EPAR, offset);
685 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200686 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000687 DM9000_iow(DM9000_EPCR, 0x0);
688 return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
689}
690
stefano babic6708a602007-08-30 23:01:49 +0200691void
692write_srom_word(int offset, u16 val)
693{
694 DM9000_iow(DM9000_EPAR, offset);
695 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
696 DM9000_iow(DM9000_EPDRL, (val & 0xff));
697 DM9000_iow(DM9000_EPCR, 0x12);
698 udelay(8000);
699 DM9000_iow(DM9000_EPCR, 0);
700}
701
702
wdenk7ac16102004-08-01 22:48:16 +0000703/*
704 Read a byte from I/O port
705*/
706static u8
707DM9000_ior(int reg)
708{
709 DM9000_outb(reg, DM9000_IO);
710 return DM9000_inb(DM9000_DATA);
711}
712
713/*
714 Write a byte to I/O port
715*/
716static void
717DM9000_iow(int reg, u8 value)
718{
719 DM9000_outb(reg, DM9000_IO);
720 DM9000_outb(value, DM9000_DATA);
721}
722
723/*
724 Read a word from phyxcer
725*/
726static u16
727phy_read(int reg)
728{
729 u16 val;
730
731 /* Fill the phyxcer register into REG_0C */
732 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
733 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200734 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000735 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
736 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
737
738 /* The read data keeps on REG_0D & REG_0E */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200739 DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000740 return val;
741}
742
743/*
744 Write a word to phyxcer
745*/
746static void
747phy_write(int reg, u16 value)
748{
749
750 /* Fill the phyxcer register into REG_0C */
751 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
752
753 /* Fill the written data into REG_0D & REG_0E */
754 DM9000_iow(DM9000_EPDRL, (value & 0xff));
755 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
756 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200757 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000758 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200759 DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000760}
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200761#endif /* CONFIG_DRIVER_DM9000 */