blob: 3a61b802e66c47eab510f9e881068312bc0c9cb1 [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
Andrew Dyera62f5d42008-08-26 17:03:38 -050058TODO: external MII is not functional, only internal at the moment.
wdenk7ac16102004-08-01 22:48:16 +000059*/
60
61#include <common.h>
62#include <command.h>
63#include <net.h>
64#include <asm/io.h>
65
wdenk7ac16102004-08-01 22:48:16 +000066#include "dm9000x.h"
67
68/* Board/System/Debug information/definition ---------------- */
69
wdenk7ac16102004-08-01 22:48:16 +000070/* #define CONFIG_DM9000_DEBUG */
71
72#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020073#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
74#define DM9000_DMP_PACKET(func,packet,length) \
75 do { \
76 int i; \
77 printf(func ": length: %d\n", length); \
78 for (i = 0; i < length; i++) { \
79 if (i % 8 == 0) \
80 printf("\n%s: %02x: ", func, i); \
81 printf("%02x ", ((unsigned char *) packet)[i]); \
82 } printf("\n"); \
83 } while(0)
84#else
wdenk7ac16102004-08-01 22:48:16 +000085#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020086#define DM9000_DMP_PACKET(func,packet,length)
87#endif
88
wdenk7ac16102004-08-01 22:48:16 +000089/* Structure/enum declaration ------------------------------- */
90typedef struct board_info {
91 u32 runt_length_counter; /* counter: RX length < 64byte */
92 u32 long_length_counter; /* counter: RX length > 1514byte */
93 u32 reset_counter; /* counter: RESET */
94 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
95 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
96 u16 tx_pkt_cnt;
97 u16 queue_start_addr;
98 u16 dbug_cnt;
99 u8 phy_addr;
100 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +0000101 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200102 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200103 void (*inblk)(void *data_ptr, int count);
104 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200105} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200106static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000107
wdenk7ac16102004-08-01 22:48:16 +0000108/* function declaration ------------------------------------- */
109int eth_init(bd_t * bd);
110int eth_send(volatile void *, int);
111int eth_rx(void);
112void eth_halt(void);
113static int dm9000_probe(void);
114static u16 phy_read(int);
115static void phy_write(int, u16);
stefano babic6708a602007-08-30 23:01:49 +0200116u16 read_srom_word(int);
wdenk7ac16102004-08-01 22:48:16 +0000117static u8 DM9000_ior(int);
118static void DM9000_iow(int reg, u8 value);
119
120/* DM9000 network board routine ---------------------------- */
121
122#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
123#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
124#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
125#define DM9000_inb(r) (*(volatile u8 *)r)
126#define DM9000_inw(r) (*(volatile u16 *)r)
127#define DM9000_inl(r) (*(volatile u32 *)r)
128
129#ifdef CONFIG_DM9000_DEBUG
130static void
131dump_regs(void)
132{
133 DM9000_DBG("\n");
134 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
135 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
136 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
137 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
138 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
139 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
140 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200141 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000142 DM9000_DBG("\n");
143}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200144#endif
145
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200146static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200147{
148 int i;
149 for (i = 0; i < count; i++)
150 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
151}
152
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200153static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200154{
155 int i;
156 u32 tmplen = (count + 1) / 2;
157
158 for (i = 0; i < tmplen; i++)
159 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
160}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200161static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200162{
163 int i;
164 u32 tmplen = (count + 3) / 4;
165
166 for (i = 0; i < tmplen; i++)
167 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
168}
169
170static void dm9000_inblk_8bit(void *data_ptr, int count)
171{
172 int i;
173 for (i = 0; i < count; i++)
174 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
175}
176
177static void dm9000_inblk_16bit(void *data_ptr, int count)
178{
179 int i;
180 u32 tmplen = (count + 1) / 2;
181
182 for (i = 0; i < tmplen; i++)
183 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
184}
185static void dm9000_inblk_32bit(void *data_ptr, int count)
186{
187 int i;
188 u32 tmplen = (count + 3) / 4;
189
190 for (i = 0; i < tmplen; i++)
191 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
192}
193
194static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
195{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200196 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200197
198 DM9000_outb(DM9000_MRCMD, DM9000_IO);
199
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200200 tmpdata = DM9000_inl(DM9000_DATA);
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500201 *RxStatus = __le16_to_cpu(tmpdata);
202 *RxLen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200203}
204
205static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
206{
207 DM9000_outb(DM9000_MRCMD, DM9000_IO);
208
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500209 *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
210 *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200211}
212
213static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
214{
215 DM9000_outb(DM9000_MRCMD, DM9000_IO);
216
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500217 *RxStatus =
218 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
219 (DM9000_inb(DM9000_DATA) << 8));
220 *RxLen =
221 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
222 (DM9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200223}
wdenk7ac16102004-08-01 22:48:16 +0000224
225/*
226 Search DM9000 board, allocate space and register it
227*/
228int
229dm9000_probe(void)
230{
231 u32 id_val;
232 id_val = DM9000_ior(DM9000_VIDL);
233 id_val |= DM9000_ior(DM9000_VIDH) << 8;
234 id_val |= DM9000_ior(DM9000_PIDL) << 16;
235 id_val |= DM9000_ior(DM9000_PIDH) << 24;
236 if (id_val == DM9000_ID) {
237 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
238 id_val);
239 return 0;
240 } else {
241 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
242 CONFIG_DM9000_BASE, id_val);
243 return -1;
244 }
wdenk7ac16102004-08-01 22:48:16 +0000245}
246
247/* General Purpose dm9000 reset routine */
248static void
249dm9000_reset(void)
250{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200251 DM9000_DBG("resetting DM9000\n");
252
253 /* Reset DM9000,
254 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
255
Andrew Dyera62f5d42008-08-26 17:03:38 -0500256 /* DEBUG: Make all GPIO0 outputs, all others inputs */
257 DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200258 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
259 DM9000_iow(DM9000_GPR, 0);
260 /* Step 2: Software reset */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500261 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200262
263 do {
264 DM9000_DBG("resetting the DM9000, 1st reset\n");
265 udelay(25); /* Wait at least 20 us */
266 } while (DM9000_ior(DM9000_NCR) & 1);
267
268 DM9000_iow(DM9000_NCR, 0);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500269 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200270
271 do {
272 DM9000_DBG("resetting the DM9000, 2nd reset\n");
273 udelay(25); /* Wait at least 20 us */
274 } while (DM9000_ior(DM9000_NCR) & 1);
275
276 /* Check whether the ethernet controller is present */
277 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
278 (DM9000_ior(DM9000_PIDH) != 0x90))
279 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000280}
281
282/* Initilize dm9000 board
283*/
284int
285eth_init(bd_t * bd)
286{
287 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200288 u8 io_mode;
289 struct board_info *db = &dm9000_info;
290
wdenk7ac16102004-08-01 22:48:16 +0000291 DM9000_DBG("eth_init()\n");
292
293 /* RESET device */
294 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500295
296 if (dm9000_probe() < 0)
297 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000298
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200299 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
300 io_mode = DM9000_ior(DM9000_ISR) >> 6;
301
302 switch (io_mode) {
303 case 0x0: /* 16-bit mode */
304 printf("DM9000: running in 16 bit mode\n");
305 db->outblk = dm9000_outblk_16bit;
306 db->inblk = dm9000_inblk_16bit;
307 db->rx_status = dm9000_rx_status_16bit;
308 break;
309 case 0x01: /* 32-bit mode */
310 printf("DM9000: running in 32 bit mode\n");
311 db->outblk = dm9000_outblk_32bit;
312 db->inblk = dm9000_inblk_32bit;
313 db->rx_status = dm9000_rx_status_32bit;
314 break;
315 case 0x02: /* 8 bit mode */
316 printf("DM9000: running in 8 bit mode\n");
317 db->outblk = dm9000_outblk_8bit;
318 db->inblk = dm9000_inblk_8bit;
319 db->rx_status = dm9000_rx_status_8bit;
320 break;
321 default:
322 /* Assume 8 bit mode, will probably not work anyway */
323 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
324 db->outblk = dm9000_outblk_8bit;
325 db->inblk = dm9000_inblk_8bit;
326 db->rx_status = dm9000_rx_status_8bit;
327 break;
328 }
329
Andrew Dyera62f5d42008-08-26 17:03:38 -0500330 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200331 DM9000_iow(DM9000_NCR, 0x0);
332 /* TX Polling clear */
333 DM9000_iow(DM9000_TCR, 0);
334 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500335 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200336 /* Flow Control : High/Low Water */
337 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
338 /* SH FIXME: This looks strange! Flow Control */
339 DM9000_iow(DM9000_FCR, 0x0);
340 /* Special Mode */
341 DM9000_iow(DM9000_SMCR, 0);
342 /* clear TX status */
343 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
344 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500345 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000346
347 /* Set Node address */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500348#if !defined(CONFIG_AT91SAM9261EK)
wdenk7ac16102004-08-01 22:48:16 +0000349 for (i = 0; i < 6; i++)
350 ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
Stelian Pop61e69d72008-05-08 20:52:22 +0200351#endif
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300352
stefano babicedb06872007-08-21 15:50:33 +0200353 if (is_zero_ether_addr(bd->bi_enetaddr) ||
354 is_multicast_ether_addr(bd->bi_enetaddr)) {
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300355 /* try reading from environment */
356 u8 i;
357 char *s, *e;
358 s = getenv ("ethaddr");
359 for (i = 0; i < 6; ++i) {
360 bd->bi_enetaddr[i] = s ?
361 simple_strtoul (s, &e, 16) : 0;
362 if (s)
363 s = (*e) ? e + 1 : e;
364 }
365 }
366
wdenk7ac16102004-08-01 22:48:16 +0000367 printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
368 bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
369 bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500370
371 /* fill device MAC address registers */
372 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
wdenk7ac16102004-08-01 22:48:16 +0000373 DM9000_iow(oft, bd->bi_enetaddr[i]);
374 for (i = 0, oft = 0x16; i < 8; i++, oft++)
375 DM9000_iow(oft, 0xff);
376
377 /* read back mac, just to be sure */
378 for (i = 0, oft = 0x10; i < 6; i++, oft++)
379 DM9000_DBG("%02x:", DM9000_ior(oft));
380 DM9000_DBG("\n");
381
382 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200383 /* RX enable */
384 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
385 /* Enable TX/RX interrupt mask */
386 DM9000_iow(DM9000_IMR, IMR_PAR);
387
wdenk7ac16102004-08-01 22:48:16 +0000388 i = 0;
389 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
390 udelay(1000);
391 i++;
392 if (i == 10000) {
393 printf("could not establish link\n");
394 return 0;
395 }
396 }
397
398 /* see what we've got */
399 lnk = phy_read(17) >> 12;
400 printf("operating at ");
401 switch (lnk) {
402 case 1:
403 printf("10M half duplex ");
404 break;
405 case 2:
406 printf("10M full duplex ");
407 break;
408 case 4:
409 printf("100M half duplex ");
410 break;
411 case 8:
412 printf("100M full duplex ");
413 break;
414 default:
415 printf("unknown: %d ", lnk);
416 break;
417 }
418 printf("mode\n");
419 return 0;
420}
421
422/*
423 Hardware start transmission.
424 Send a packet to media from the upper layer.
425*/
426int
427eth_send(volatile void *packet, int length)
428{
wdenk7ac16102004-08-01 22:48:16 +0000429 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200430 struct board_info *db = &dm9000_info;
431
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200432 DM9000_DMP_PACKET("eth_send", packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000433
Remy Bohmer16cb2642008-06-03 15:26:23 +0200434 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
435
wdenk7ac16102004-08-01 22:48:16 +0000436 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200437 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000438
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200439 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200440 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000441
442 /* Set TX length to DM9000 */
443 DM9000_iow(DM9000_TXPLL, length & 0xff);
444 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
445
446 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200447 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000448
449 /* wait for end of transmission */
450 tmo = get_timer(0) + 5 * CFG_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200451 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
452 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000453 if (get_timer(0) >= tmo) {
454 printf("transmission timeout\n");
455 break;
456 }
457 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200458 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
459
wdenk7ac16102004-08-01 22:48:16 +0000460 DM9000_DBG("transmit done\n\n");
461 return 0;
462}
463
464/*
465 Stop the interface.
466 The interface is stopped when it is brought.
467*/
468void
469eth_halt(void)
470{
471 DM9000_DBG("eth_halt\n");
472
473 /* RESET devie */
474 phy_write(0, 0x8000); /* PHY RESET */
475 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
476 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
477 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
478}
479
480/*
481 Received a packet and pass to upper layer
482*/
483int
484eth_rx(void)
485{
486 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
487 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200488 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000489
Remy Bohmereec38a12008-06-03 15:26:25 +0200490 /* Check packet ready or not, we must check
491 the ISR status first for DM9000A */
492 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000493 return 0;
494
Remy Bohmereec38a12008-06-03 15:26:25 +0200495 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000496
Remy Bohmereec38a12008-06-03 15:26:25 +0200497 /* There is _at least_ 1 package in the fifo, read them all */
498 for (;;) {
499 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000500
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200501 /* Get most updated data,
502 only look at bits 0:1, See application notes DM9000 */
503 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000504
Remy Bohmereec38a12008-06-03 15:26:25 +0200505 /* Status check: this byte must be 0 or 1 */
506 if (rxbyte > DM9000_PKT_RDY) {
507 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
508 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
509 printf("DM9000 error: status check fail: 0x%x\n",
510 rxbyte);
511 return 0;
512 }
wdenk7ac16102004-08-01 22:48:16 +0000513
Remy Bohmereec38a12008-06-03 15:26:25 +0200514 if (rxbyte != DM9000_PKT_RDY)
515 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000516
Remy Bohmereec38a12008-06-03 15:26:25 +0200517 DM9000_DBG("receiving packet\n");
518
519 /* A packet ready now & Get status/length */
520 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000521
Remy Bohmereec38a12008-06-03 15:26:25 +0200522 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
523
524 /* Move data from DM9000 */
525 /* Read received packet from RX SRAM */
526 (db->inblk)(rdptr, RxLen);
527
528 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
529 || (RxLen > DM9000_PKT_MAX)) {
530 if (RxStatus & 0x100) {
531 printf("rx fifo error\n");
532 }
533 if (RxStatus & 0x200) {
534 printf("rx crc error\n");
535 }
536 if (RxStatus & 0x8000) {
537 printf("rx length error\n");
538 }
539 if (RxLen > DM9000_PKT_MAX) {
540 printf("rx length too big\n");
541 dm9000_reset();
542 }
543 } else {
544 DM9000_DMP_PACKET("eth_rx", rdptr, RxLen);
545
546 DM9000_DBG("passing packet to upper layer\n");
547 NetReceive(NetRxPackets[0], RxLen);
548 }
wdenk7ac16102004-08-01 22:48:16 +0000549 }
550 return 0;
551}
552
553/*
554 Read a word data from SROM
555*/
stefano babic6708a602007-08-30 23:01:49 +0200556u16
wdenk7ac16102004-08-01 22:48:16 +0000557read_srom_word(int offset)
558{
559 DM9000_iow(DM9000_EPAR, offset);
560 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200561 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000562 DM9000_iow(DM9000_EPCR, 0x0);
563 return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
564}
565
stefano babic6708a602007-08-30 23:01:49 +0200566void
567write_srom_word(int offset, u16 val)
568{
569 DM9000_iow(DM9000_EPAR, offset);
570 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
571 DM9000_iow(DM9000_EPDRL, (val & 0xff));
572 DM9000_iow(DM9000_EPCR, 0x12);
573 udelay(8000);
574 DM9000_iow(DM9000_EPCR, 0);
575}
576
577
wdenk7ac16102004-08-01 22:48:16 +0000578/*
579 Read a byte from I/O port
580*/
581static u8
582DM9000_ior(int reg)
583{
584 DM9000_outb(reg, DM9000_IO);
585 return DM9000_inb(DM9000_DATA);
586}
587
588/*
589 Write a byte to I/O port
590*/
591static void
592DM9000_iow(int reg, u8 value)
593{
594 DM9000_outb(reg, DM9000_IO);
595 DM9000_outb(value, DM9000_DATA);
596}
597
598/*
599 Read a word from phyxcer
600*/
601static u16
602phy_read(int reg)
603{
604 u16 val;
605
606 /* Fill the phyxcer register into REG_0C */
607 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
608 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200609 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000610 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
611 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
612
613 /* The read data keeps on REG_0D & REG_0E */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200614 DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000615 return val;
616}
617
618/*
619 Write a word to phyxcer
620*/
621static void
622phy_write(int reg, u16 value)
623{
624
625 /* Fill the phyxcer register into REG_0C */
626 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
627
628 /* Fill the written data into REG_0D & REG_0E */
629 DM9000_iow(DM9000_EPDRL, (value & 0xff));
630 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
631 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200632 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000633 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200634 DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000635}