blob: c2144d9bc69c28738283c9e0dbaa00fb619a859a [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 Bohmer90d1fed2008-06-05 13:03:36 +0200116 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200117 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
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200164static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200165{
166 int i;
167 for (i = 0; i < count; i++)
168 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
169}
170
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200171static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200172{
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}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200179static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200180{
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{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200214 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200215
216 DM9000_outb(DM9000_MRCMD, DM9000_IO);
217
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200218 tmpdata = DM9000_inl(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200219 *RxStatus = tmpdata;
220 *RxLen = tmpdata >> 16;
221}
222
223static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
224{
225 DM9000_outb(DM9000_MRCMD, DM9000_IO);
226
227 *RxStatus = DM9000_inw(DM9000_DATA);
228 *RxLen = DM9000_inw(DM9000_DATA);
229}
230
231static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
232{
233 DM9000_outb(DM9000_MRCMD, DM9000_IO);
234
235 *RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
236 *RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
237}
wdenk7ac16102004-08-01 22:48:16 +0000238
239/*
240 Search DM9000 board, allocate space and register it
241*/
242int
243dm9000_probe(void)
244{
245 u32 id_val;
246 id_val = DM9000_ior(DM9000_VIDL);
247 id_val |= DM9000_ior(DM9000_VIDH) << 8;
248 id_val |= DM9000_ior(DM9000_PIDL) << 16;
249 id_val |= DM9000_ior(DM9000_PIDH) << 24;
250 if (id_val == DM9000_ID) {
251 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
252 id_val);
253 return 0;
254 } else {
255 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
256 CONFIG_DM9000_BASE, id_val);
257 return -1;
258 }
259}
260
261/* Set PHY operationg mode
262*/
263static void
264set_PHY_mode(void)
265{
266 u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
267 if (!(media_mode & DM9000_AUTO)) {
268 switch (media_mode) {
269 case DM9000_10MHD:
270 phy_reg4 = 0x21;
271 phy_reg0 = 0x0000;
272 break;
273 case DM9000_10MFD:
274 phy_reg4 = 0x41;
275 phy_reg0 = 0x1100;
276 break;
277 case DM9000_100MHD:
278 phy_reg4 = 0x81;
279 phy_reg0 = 0x2000;
280 break;
281 case DM9000_100MFD:
282 phy_reg4 = 0x101;
283 phy_reg0 = 0x3100;
284 break;
285 }
286 phy_write(4, phy_reg4); /* Set PHY media mode */
287 phy_write(0, phy_reg0); /* Tmp */
288 }
289 DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */
290 DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */
291}
292
293/*
294 Init HomeRun DM9801
295*/
296static void
297program_dm9801(u16 HPNA_rev)
298{
299 __u16 reg16, reg17, reg24, reg25;
300 if (!nfloor)
301 nfloor = DM9801_NOISE_FLOOR;
302 reg16 = phy_read(16);
303 reg17 = phy_read(17);
304 reg24 = phy_read(24);
305 reg25 = phy_read(25);
306 switch (HPNA_rev) {
307 case 0xb900: /* DM9801 E3 */
308 reg16 |= 0x1000;
309 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000;
310 break;
311 case 0xb901: /* DM9801 E4 */
312 reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200;
313 reg17 = (reg17 & 0xfff0) + nfloor + 3;
314 break;
315 case 0xb902: /* DM9801 E5 */
316 case 0xb903: /* DM9801 E6 */
317 default:
318 reg16 |= 0x1000;
319 reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200;
320 reg17 = (reg17 & 0xfff0) + nfloor;
321 }
322 phy_write(16, reg16);
323 phy_write(17, reg17);
324 phy_write(25, reg25);
325}
326
327/*
328 Init LongRun DM9802
329*/
330static void
331program_dm9802(void)
332{
333 __u16 reg25;
334 if (!nfloor)
335 nfloor = DM9802_NOISE_FLOOR;
336 reg25 = phy_read(25);
337 reg25 = (reg25 & 0xff00) + nfloor;
338 phy_write(25, reg25);
339}
340
341/* Identify NIC type
342*/
343static void
344identify_nic(void)
345{
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200346 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000347 u16 phy_reg3;
348 DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
349 phy_reg3 = phy_read(3);
350 switch (phy_reg3 & 0xfff0) {
351 case 0xb900:
352 if (phy_read(31) == 0x4404) {
353 db->nic_type = HOMERUN_NIC;
354 program_dm9801(phy_reg3);
355 DM9000_DBG("found homerun NIC\n");
356 } else {
357 db->nic_type = LONGRUN_NIC;
358 DM9000_DBG("found longrun NIC\n");
359 program_dm9802();
360 }
361 break;
362 default:
363 db->nic_type = FASTETHER_NIC;
364 break;
365 }
366 DM9000_iow(DM9000_NCR, 0);
367}
368
369/* General Purpose dm9000 reset routine */
370static void
371dm9000_reset(void)
372{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200373 DM9000_DBG("resetting DM9000\n");
374
375 /* Reset DM9000,
376 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
377
378 /* DEBUG: Make all GPIO pins outputs */
379 DM9000_iow(DM9000_GPCR, 0x0F);
380 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
381 DM9000_iow(DM9000_GPR, 0);
382 /* Step 2: Software reset */
383 DM9000_iow(DM9000_NCR, 3);
384
385 do {
386 DM9000_DBG("resetting the DM9000, 1st reset\n");
387 udelay(25); /* Wait at least 20 us */
388 } while (DM9000_ior(DM9000_NCR) & 1);
389
390 DM9000_iow(DM9000_NCR, 0);
391 DM9000_iow(DM9000_NCR, 3); /* Issue a second reset */
392
393 do {
394 DM9000_DBG("resetting the DM9000, 2nd reset\n");
395 udelay(25); /* Wait at least 20 us */
396 } while (DM9000_ior(DM9000_NCR) & 1);
397
398 /* Check whether the ethernet controller is present */
399 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
400 (DM9000_ior(DM9000_PIDH) != 0x90))
401 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000402}
403
404/* Initilize dm9000 board
405*/
406int
407eth_init(bd_t * bd)
408{
409 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200410 u8 io_mode;
411 struct board_info *db = &dm9000_info;
412
wdenk7ac16102004-08-01 22:48:16 +0000413 DM9000_DBG("eth_init()\n");
414
415 /* RESET device */
416 dm9000_reset();
417 dm9000_probe();
418
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200419 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
420 io_mode = DM9000_ior(DM9000_ISR) >> 6;
421
422 switch (io_mode) {
423 case 0x0: /* 16-bit mode */
424 printf("DM9000: running in 16 bit mode\n");
425 db->outblk = dm9000_outblk_16bit;
426 db->inblk = dm9000_inblk_16bit;
427 db->rx_status = dm9000_rx_status_16bit;
428 break;
429 case 0x01: /* 32-bit mode */
430 printf("DM9000: running in 32 bit mode\n");
431 db->outblk = dm9000_outblk_32bit;
432 db->inblk = dm9000_inblk_32bit;
433 db->rx_status = dm9000_rx_status_32bit;
434 break;
435 case 0x02: /* 8 bit mode */
436 printf("DM9000: running in 8 bit mode\n");
437 db->outblk = dm9000_outblk_8bit;
438 db->inblk = dm9000_inblk_8bit;
439 db->rx_status = dm9000_rx_status_8bit;
440 break;
441 default:
442 /* Assume 8 bit mode, will probably not work anyway */
443 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
444 db->outblk = dm9000_outblk_8bit;
445 db->inblk = dm9000_inblk_8bit;
446 db->rx_status = dm9000_rx_status_8bit;
447 break;
448 }
449
wdenk7ac16102004-08-01 22:48:16 +0000450 /* NIC Type: FASTETHER, HOMERUN, LONGRUN */
451 identify_nic();
452
453 /* GPIO0 on pre-activate PHY */
454 DM9000_iow(DM9000_GPR, 0x00); /*REG_1F bit0 activate phyxcer */
455
456 /* Set PHY */
457 set_PHY_mode();
458
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200459 /* Program operating register, only intern phy supported by now */
460 DM9000_iow(DM9000_NCR, 0x0);
461 /* TX Polling clear */
462 DM9000_iow(DM9000_TCR, 0);
463 /* Less 3Kb, 200us */
464 DM9000_iow(DM9000_BPTR, 0x3f);
465 /* Flow Control : High/Low Water */
466 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
467 /* SH FIXME: This looks strange! Flow Control */
468 DM9000_iow(DM9000_FCR, 0x0);
469 /* Special Mode */
470 DM9000_iow(DM9000_SMCR, 0);
471 /* clear TX status */
472 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
473 /* Clear interrupt status */
474 DM9000_iow(DM9000_ISR, 0x0f);
wdenk7ac16102004-08-01 22:48:16 +0000475
476 /* Set Node address */
477 for (i = 0; i < 6; i++)
478 ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300479
stefano babicedb06872007-08-21 15:50:33 +0200480 if (is_zero_ether_addr(bd->bi_enetaddr) ||
481 is_multicast_ether_addr(bd->bi_enetaddr)) {
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300482 /* try reading from environment */
483 u8 i;
484 char *s, *e;
485 s = getenv ("ethaddr");
486 for (i = 0; i < 6; ++i) {
487 bd->bi_enetaddr[i] = s ?
488 simple_strtoul (s, &e, 16) : 0;
489 if (s)
490 s = (*e) ? e + 1 : e;
491 }
492 }
493
wdenk7ac16102004-08-01 22:48:16 +0000494 printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
495 bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
496 bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
497 for (i = 0, oft = 0x10; i < 6; i++, oft++)
498 DM9000_iow(oft, bd->bi_enetaddr[i]);
499 for (i = 0, oft = 0x16; i < 8; i++, oft++)
500 DM9000_iow(oft, 0xff);
501
502 /* read back mac, just to be sure */
503 for (i = 0, oft = 0x10; i < 6; i++, oft++)
504 DM9000_DBG("%02x:", DM9000_ior(oft));
505 DM9000_DBG("\n");
506
507 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200508 /* RX enable */
509 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
510 /* Enable TX/RX interrupt mask */
511 DM9000_iow(DM9000_IMR, IMR_PAR);
512
wdenk7ac16102004-08-01 22:48:16 +0000513 i = 0;
514 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
515 udelay(1000);
516 i++;
517 if (i == 10000) {
518 printf("could not establish link\n");
519 return 0;
520 }
521 }
522
523 /* see what we've got */
524 lnk = phy_read(17) >> 12;
525 printf("operating at ");
526 switch (lnk) {
527 case 1:
528 printf("10M half duplex ");
529 break;
530 case 2:
531 printf("10M full duplex ");
532 break;
533 case 4:
534 printf("100M half duplex ");
535 break;
536 case 8:
537 printf("100M full duplex ");
538 break;
539 default:
540 printf("unknown: %d ", lnk);
541 break;
542 }
543 printf("mode\n");
544 return 0;
545}
546
547/*
548 Hardware start transmission.
549 Send a packet to media from the upper layer.
550*/
551int
552eth_send(volatile void *packet, int length)
553{
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 */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200562 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000563
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200564 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200565 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000566
567 /* Set TX length to DM9000 */
568 DM9000_iow(DM9000_TXPLL, length & 0xff);
569 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
570
571 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200572 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000573
574 /* wait for end of transmission */
575 tmo = get_timer(0) + 5 * CFG_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200576 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
577 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000578 if (get_timer(0) >= tmo) {
579 printf("transmission timeout\n");
580 break;
581 }
582 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200583 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
584
wdenk7ac16102004-08-01 22:48:16 +0000585 DM9000_DBG("transmit done\n\n");
586 return 0;
587}
588
589/*
590 Stop the interface.
591 The interface is stopped when it is brought.
592*/
593void
594eth_halt(void)
595{
596 DM9000_DBG("eth_halt\n");
597
598 /* RESET devie */
599 phy_write(0, 0x8000); /* PHY RESET */
600 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
601 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
602 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
603}
604
605/*
606 Received a packet and pass to upper layer
607*/
608int
609eth_rx(void)
610{
611 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
612 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200613 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000614
Remy Bohmereec38a12008-06-03 15:26:25 +0200615 /* Check packet ready or not, we must check
616 the ISR status first for DM9000A */
617 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000618 return 0;
619
Remy Bohmereec38a12008-06-03 15:26:25 +0200620 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000621
Remy Bohmereec38a12008-06-03 15:26:25 +0200622 /* There is _at least_ 1 package in the fifo, read them all */
623 for (;;) {
624 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000625
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200626 /* Get most updated data,
627 only look at bits 0:1, See application notes DM9000 */
628 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
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 */