blob: efe913589f2463f320dc7439ec9cc9ba89dec564 [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
Remy Bohmercd9a36c2009-05-03 12:11:40 +020056 with a 200MHz Atmel AT91SAM9261 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>
Remy Bohmercd9a36c2009-05-03 12:11:40 +020065#include <dm9000.h>
wdenk7ac16102004-08-01 22:48:16 +000066
wdenk7ac16102004-08-01 22:48:16 +000067#include "dm9000x.h"
68
69/* Board/System/Debug information/definition ---------------- */
70
wdenk7ac16102004-08-01 22:48:16 +000071/* #define CONFIG_DM9000_DEBUG */
72
73#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020074#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
75#define DM9000_DMP_PACKET(func,packet,length) \
76 do { \
77 int i; \
78 printf(func ": length: %d\n", length); \
79 for (i = 0; i < length; i++) { \
80 if (i % 8 == 0) \
81 printf("\n%s: %02x: ", func, i); \
82 printf("%02x ", ((unsigned char *) packet)[i]); \
83 } printf("\n"); \
84 } while(0)
85#else
wdenk7ac16102004-08-01 22:48:16 +000086#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020087#define DM9000_DMP_PACKET(func,packet,length)
88#endif
89
wdenk7ac16102004-08-01 22:48:16 +000090/* Structure/enum declaration ------------------------------- */
91typedef struct board_info {
92 u32 runt_length_counter; /* counter: RX length < 64byte */
93 u32 long_length_counter; /* counter: RX length > 1514byte */
94 u32 reset_counter; /* counter: RESET */
95 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
96 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
97 u16 tx_pkt_cnt;
98 u16 queue_start_addr;
99 u16 dbug_cnt;
100 u8 phy_addr;
101 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +0000102 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200103 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200104 void (*inblk)(void *data_ptr, int count);
105 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer7eefd922009-05-02 21:49:18 +0200106 struct eth_device netdev;
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200107} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200108static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000109
Remy Bohmer7eefd922009-05-02 21:49:18 +0200110
wdenk7ac16102004-08-01 22:48:16 +0000111/* function declaration ------------------------------------- */
wdenk7ac16102004-08-01 22:48:16 +0000112static int dm9000_probe(void);
113static u16 phy_read(int);
114static void phy_write(int, u16);
wdenk7ac16102004-08-01 22:48:16 +0000115static u8 DM9000_ior(int);
116static void DM9000_iow(int reg, u8 value);
117
118/* DM9000 network board routine ---------------------------- */
119
120#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
121#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
122#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
123#define DM9000_inb(r) (*(volatile u8 *)r)
124#define DM9000_inw(r) (*(volatile u16 *)r)
125#define DM9000_inl(r) (*(volatile u32 *)r)
126
127#ifdef CONFIG_DM9000_DEBUG
128static void
129dump_regs(void)
130{
131 DM9000_DBG("\n");
132 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
133 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
134 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
135 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
136 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
137 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
138 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200139 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000140 DM9000_DBG("\n");
141}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200142#endif
143
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200144static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200145{
146 int i;
147 for (i = 0; i < count; i++)
148 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
149}
150
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200151static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200152{
153 int i;
154 u32 tmplen = (count + 1) / 2;
155
156 for (i = 0; i < tmplen; i++)
157 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
158}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200159static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200160{
161 int i;
162 u32 tmplen = (count + 3) / 4;
163
164 for (i = 0; i < tmplen; i++)
165 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
166}
167
168static void dm9000_inblk_8bit(void *data_ptr, int count)
169{
170 int i;
171 for (i = 0; i < count; i++)
172 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
173}
174
175static void dm9000_inblk_16bit(void *data_ptr, int count)
176{
177 int i;
178 u32 tmplen = (count + 1) / 2;
179
180 for (i = 0; i < tmplen; i++)
181 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
182}
183static void dm9000_inblk_32bit(void *data_ptr, int count)
184{
185 int i;
186 u32 tmplen = (count + 3) / 4;
187
188 for (i = 0; i < tmplen; i++)
189 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
190}
191
192static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
193{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200194 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200195
196 DM9000_outb(DM9000_MRCMD, DM9000_IO);
197
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200198 tmpdata = DM9000_inl(DM9000_DATA);
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500199 *RxStatus = __le16_to_cpu(tmpdata);
200 *RxLen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200201}
202
203static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
204{
205 DM9000_outb(DM9000_MRCMD, DM9000_IO);
206
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500207 *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
208 *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200209}
210
211static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
212{
213 DM9000_outb(DM9000_MRCMD, DM9000_IO);
214
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500215 *RxStatus =
216 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
217 (DM9000_inb(DM9000_DATA) << 8));
218 *RxLen =
219 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
220 (DM9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200221}
wdenk7ac16102004-08-01 22:48:16 +0000222
223/*
224 Search DM9000 board, allocate space and register it
225*/
226int
227dm9000_probe(void)
228{
229 u32 id_val;
230 id_val = DM9000_ior(DM9000_VIDL);
231 id_val |= DM9000_ior(DM9000_VIDH) << 8;
232 id_val |= DM9000_ior(DM9000_PIDL) << 16;
233 id_val |= DM9000_ior(DM9000_PIDH) << 24;
234 if (id_val == DM9000_ID) {
235 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
236 id_val);
237 return 0;
238 } else {
239 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
240 CONFIG_DM9000_BASE, id_val);
241 return -1;
242 }
wdenk7ac16102004-08-01 22:48:16 +0000243}
244
245/* General Purpose dm9000 reset routine */
246static void
247dm9000_reset(void)
248{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200249 DM9000_DBG("resetting DM9000\n");
250
251 /* Reset DM9000,
252 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
253
Andrew Dyera62f5d42008-08-26 17:03:38 -0500254 /* DEBUG: Make all GPIO0 outputs, all others inputs */
255 DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200256 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
257 DM9000_iow(DM9000_GPR, 0);
258 /* Step 2: Software reset */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500259 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200260
261 do {
262 DM9000_DBG("resetting the DM9000, 1st reset\n");
263 udelay(25); /* Wait at least 20 us */
264 } while (DM9000_ior(DM9000_NCR) & 1);
265
266 DM9000_iow(DM9000_NCR, 0);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500267 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200268
269 do {
270 DM9000_DBG("resetting the DM9000, 2nd reset\n");
271 udelay(25); /* Wait at least 20 us */
272 } while (DM9000_ior(DM9000_NCR) & 1);
273
274 /* Check whether the ethernet controller is present */
275 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
276 (DM9000_ior(DM9000_PIDH) != 0x90))
277 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000278}
279
Remy Bohmer7eefd922009-05-02 21:49:18 +0200280/* Initialize dm9000 board
wdenk7ac16102004-08-01 22:48:16 +0000281*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200282static int dm9000_init(struct eth_device *dev, bd_t *bd)
wdenk7ac16102004-08-01 22:48:16 +0000283{
284 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200285 u8 io_mode;
286 struct board_info *db = &dm9000_info;
Mike Frysingerb2039652009-02-11 19:01:26 -0500287 uchar enetaddr[6];
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200288
Remy Bohmer7eefd922009-05-02 21:49:18 +0200289 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000290
291 /* RESET device */
292 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500293
294 if (dm9000_probe() < 0)
295 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000296
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200297 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
298 io_mode = DM9000_ior(DM9000_ISR) >> 6;
299
300 switch (io_mode) {
301 case 0x0: /* 16-bit mode */
302 printf("DM9000: running in 16 bit mode\n");
303 db->outblk = dm9000_outblk_16bit;
304 db->inblk = dm9000_inblk_16bit;
305 db->rx_status = dm9000_rx_status_16bit;
306 break;
307 case 0x01: /* 32-bit mode */
308 printf("DM9000: running in 32 bit mode\n");
309 db->outblk = dm9000_outblk_32bit;
310 db->inblk = dm9000_inblk_32bit;
311 db->rx_status = dm9000_rx_status_32bit;
312 break;
313 case 0x02: /* 8 bit mode */
314 printf("DM9000: running in 8 bit mode\n");
315 db->outblk = dm9000_outblk_8bit;
316 db->inblk = dm9000_inblk_8bit;
317 db->rx_status = dm9000_rx_status_8bit;
318 break;
319 default:
320 /* Assume 8 bit mode, will probably not work anyway */
321 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
322 db->outblk = dm9000_outblk_8bit;
323 db->inblk = dm9000_inblk_8bit;
324 db->rx_status = dm9000_rx_status_8bit;
325 break;
326 }
327
Andrew Dyera62f5d42008-08-26 17:03:38 -0500328 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200329 DM9000_iow(DM9000_NCR, 0x0);
330 /* TX Polling clear */
331 DM9000_iow(DM9000_TCR, 0);
332 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500333 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200334 /* Flow Control : High/Low Water */
335 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
336 /* SH FIXME: This looks strange! Flow Control */
337 DM9000_iow(DM9000_FCR, 0x0);
338 /* Special Mode */
339 DM9000_iow(DM9000_SMCR, 0);
340 /* clear TX status */
341 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
342 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500343 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000344
345 /* Set Node address */
Mike Frysingerb2039652009-02-11 19:01:26 -0500346 if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200347#if !defined(CONFIG_DM9000_NO_SROM)
David Brownell71907572009-04-16 23:15:15 -0700348 for (i = 0; i < 3; i++)
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200349 dm9000_read_srom_word(i, enetaddr + 2 * i);
Mike Frysingerb2039652009-02-11 19:01:26 -0500350 eth_setenv_enetaddr("ethaddr", enetaddr);
Stelian Pop61e69d72008-05-08 20:52:22 +0200351#endif
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300352 }
353
Mike Frysingerb2039652009-02-11 19:01:26 -0500354 printf("MAC: %pM\n", enetaddr);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500355
356 /* fill device MAC address registers */
357 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Mike Frysingerb2039652009-02-11 19:01:26 -0500358 DM9000_iow(oft, enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000359 for (i = 0, oft = 0x16; i < 8; i++, oft++)
360 DM9000_iow(oft, 0xff);
361
362 /* read back mac, just to be sure */
363 for (i = 0, oft = 0x10; i < 6; i++, oft++)
364 DM9000_DBG("%02x:", DM9000_ior(oft));
365 DM9000_DBG("\n");
366
367 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200368 /* RX enable */
369 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
370 /* Enable TX/RX interrupt mask */
371 DM9000_iow(DM9000_IMR, IMR_PAR);
372
wdenk7ac16102004-08-01 22:48:16 +0000373 i = 0;
374 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
375 udelay(1000);
376 i++;
377 if (i == 10000) {
378 printf("could not establish link\n");
379 return 0;
380 }
381 }
382
383 /* see what we've got */
384 lnk = phy_read(17) >> 12;
385 printf("operating at ");
386 switch (lnk) {
387 case 1:
388 printf("10M half duplex ");
389 break;
390 case 2:
391 printf("10M full duplex ");
392 break;
393 case 4:
394 printf("100M half duplex ");
395 break;
396 case 8:
397 printf("100M full duplex ");
398 break;
399 default:
400 printf("unknown: %d ", lnk);
401 break;
402 }
403 printf("mode\n");
404 return 0;
405}
406
407/*
408 Hardware start transmission.
409 Send a packet to media from the upper layer.
410*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200411static int dm9000_send(struct eth_device *netdev, volatile void *packet,
412 int length)
wdenk7ac16102004-08-01 22:48:16 +0000413{
wdenk7ac16102004-08-01 22:48:16 +0000414 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200415 struct board_info *db = &dm9000_info;
416
Remy Bohmer7eefd922009-05-02 21:49:18 +0200417 DM9000_DMP_PACKET(__func__ , packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000418
Remy Bohmer16cb2642008-06-03 15:26:23 +0200419 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
420
wdenk7ac16102004-08-01 22:48:16 +0000421 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200422 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000423
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200424 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200425 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000426
427 /* Set TX length to DM9000 */
428 DM9000_iow(DM9000_TXPLL, length & 0xff);
429 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
430
431 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200432 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000433
434 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200435 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200436 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
437 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000438 if (get_timer(0) >= tmo) {
439 printf("transmission timeout\n");
440 break;
441 }
442 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200443 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
444
wdenk7ac16102004-08-01 22:48:16 +0000445 DM9000_DBG("transmit done\n\n");
446 return 0;
447}
448
449/*
450 Stop the interface.
451 The interface is stopped when it is brought.
452*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200453static void dm9000_halt(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000454{
Remy Bohmer7eefd922009-05-02 21:49:18 +0200455 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000456
457 /* RESET devie */
458 phy_write(0, 0x8000); /* PHY RESET */
459 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
460 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
461 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
462}
463
464/*
465 Received a packet and pass to upper layer
466*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200467static int dm9000_rx(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000468{
469 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
470 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200471 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000472
Remy Bohmereec38a12008-06-03 15:26:25 +0200473 /* Check packet ready or not, we must check
474 the ISR status first for DM9000A */
475 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000476 return 0;
477
Remy Bohmereec38a12008-06-03 15:26:25 +0200478 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000479
Remy Bohmereec38a12008-06-03 15:26:25 +0200480 /* There is _at least_ 1 package in the fifo, read them all */
481 for (;;) {
482 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000483
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200484 /* Get most updated data,
485 only look at bits 0:1, See application notes DM9000 */
486 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000487
Remy Bohmereec38a12008-06-03 15:26:25 +0200488 /* Status check: this byte must be 0 or 1 */
489 if (rxbyte > DM9000_PKT_RDY) {
490 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
491 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
492 printf("DM9000 error: status check fail: 0x%x\n",
493 rxbyte);
494 return 0;
495 }
wdenk7ac16102004-08-01 22:48:16 +0000496
Remy Bohmereec38a12008-06-03 15:26:25 +0200497 if (rxbyte != DM9000_PKT_RDY)
498 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000499
Remy Bohmereec38a12008-06-03 15:26:25 +0200500 DM9000_DBG("receiving packet\n");
501
502 /* A packet ready now & Get status/length */
503 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000504
Remy Bohmereec38a12008-06-03 15:26:25 +0200505 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
506
507 /* Move data from DM9000 */
508 /* Read received packet from RX SRAM */
509 (db->inblk)(rdptr, RxLen);
510
511 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
512 || (RxLen > DM9000_PKT_MAX)) {
513 if (RxStatus & 0x100) {
514 printf("rx fifo error\n");
515 }
516 if (RxStatus & 0x200) {
517 printf("rx crc error\n");
518 }
519 if (RxStatus & 0x8000) {
520 printf("rx length error\n");
521 }
522 if (RxLen > DM9000_PKT_MAX) {
523 printf("rx length too big\n");
524 dm9000_reset();
525 }
526 } else {
Remy Bohmer7eefd922009-05-02 21:49:18 +0200527 DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200528
529 DM9000_DBG("passing packet to upper layer\n");
530 NetReceive(NetRxPackets[0], RxLen);
531 }
wdenk7ac16102004-08-01 22:48:16 +0000532 }
533 return 0;
534}
535
536/*
537 Read a word data from SROM
538*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200539#if !defined(CONFIG_DM9000_NO_SROM)
540void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000541{
542 DM9000_iow(DM9000_EPAR, offset);
543 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200544 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000545 DM9000_iow(DM9000_EPCR, 0x0);
David Brownell71907572009-04-16 23:15:15 -0700546 to[0] = DM9000_ior(DM9000_EPDRL);
547 to[1] = DM9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000548}
549
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200550void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200551{
552 DM9000_iow(DM9000_EPAR, offset);
553 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
554 DM9000_iow(DM9000_EPDRL, (val & 0xff));
555 DM9000_iow(DM9000_EPCR, 0x12);
556 udelay(8000);
557 DM9000_iow(DM9000_EPCR, 0);
558}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200559#endif
stefano babic6708a602007-08-30 23:01:49 +0200560
wdenk7ac16102004-08-01 22:48:16 +0000561/*
562 Read a byte from I/O port
563*/
564static u8
565DM9000_ior(int reg)
566{
567 DM9000_outb(reg, DM9000_IO);
568 return DM9000_inb(DM9000_DATA);
569}
570
571/*
572 Write a byte to I/O port
573*/
574static void
575DM9000_iow(int reg, u8 value)
576{
577 DM9000_outb(reg, DM9000_IO);
578 DM9000_outb(value, DM9000_DATA);
579}
580
581/*
582 Read a word from phyxcer
583*/
584static u16
585phy_read(int reg)
586{
587 u16 val;
588
589 /* Fill the phyxcer register into REG_0C */
590 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
591 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200592 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000593 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
594 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
595
596 /* The read data keeps on REG_0D & REG_0E */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200597 DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000598 return val;
599}
600
601/*
602 Write a word to phyxcer
603*/
604static void
605phy_write(int reg, u16 value)
606{
607
608 /* Fill the phyxcer register into REG_0C */
609 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
610
611 /* Fill the written data into REG_0D & REG_0E */
612 DM9000_iow(DM9000_EPDRL, (value & 0xff));
613 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
614 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200615 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000616 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200617 DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000618}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200619
620int dm9000_initialize(bd_t *bis)
621{
622 struct eth_device *dev = &(dm9000_info.netdev);
623
624 dev->init = dm9000_init;
625 dev->halt = dm9000_halt;
626 dev->send = dm9000_send;
627 dev->recv = dm9000_rx;
628 sprintf(dev->name, "dm9000");
629
630 eth_register(dev);
631
632 return 0;
633}