blob: 8ca2bf715c0bd203ae6c960c5a449ad257e97849 [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);
David Brownell71907572009-04-16 23:15:15 -0700116static void read_srom_word(int, u8 *);
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;
Mike Frysingerb2039652009-02-11 19:01:26 -0500290 uchar enetaddr[6];
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200291
wdenk7ac16102004-08-01 22:48:16 +0000292 DM9000_DBG("eth_init()\n");
293
294 /* RESET device */
295 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500296
297 if (dm9000_probe() < 0)
298 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000299
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200300 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
301 io_mode = DM9000_ior(DM9000_ISR) >> 6;
302
303 switch (io_mode) {
304 case 0x0: /* 16-bit mode */
305 printf("DM9000: running in 16 bit mode\n");
306 db->outblk = dm9000_outblk_16bit;
307 db->inblk = dm9000_inblk_16bit;
308 db->rx_status = dm9000_rx_status_16bit;
309 break;
310 case 0x01: /* 32-bit mode */
311 printf("DM9000: running in 32 bit mode\n");
312 db->outblk = dm9000_outblk_32bit;
313 db->inblk = dm9000_inblk_32bit;
314 db->rx_status = dm9000_rx_status_32bit;
315 break;
316 case 0x02: /* 8 bit mode */
317 printf("DM9000: running in 8 bit mode\n");
318 db->outblk = dm9000_outblk_8bit;
319 db->inblk = dm9000_inblk_8bit;
320 db->rx_status = dm9000_rx_status_8bit;
321 break;
322 default:
323 /* Assume 8 bit mode, will probably not work anyway */
324 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
325 db->outblk = dm9000_outblk_8bit;
326 db->inblk = dm9000_inblk_8bit;
327 db->rx_status = dm9000_rx_status_8bit;
328 break;
329 }
330
Andrew Dyera62f5d42008-08-26 17:03:38 -0500331 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200332 DM9000_iow(DM9000_NCR, 0x0);
333 /* TX Polling clear */
334 DM9000_iow(DM9000_TCR, 0);
335 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500336 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200337 /* Flow Control : High/Low Water */
338 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
339 /* SH FIXME: This looks strange! Flow Control */
340 DM9000_iow(DM9000_FCR, 0x0);
341 /* Special Mode */
342 DM9000_iow(DM9000_SMCR, 0);
343 /* clear TX status */
344 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
345 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500346 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000347
348 /* Set Node address */
Mike Frysingerb2039652009-02-11 19:01:26 -0500349 if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
Andrew Dyera62f5d42008-08-26 17:03:38 -0500350#if !defined(CONFIG_AT91SAM9261EK)
David Brownell71907572009-04-16 23:15:15 -0700351 for (i = 0; i < 3; i++)
352 read_srom_word(i, enetaddr + 2 * i);
Mike Frysingerb2039652009-02-11 19:01:26 -0500353 eth_setenv_enetaddr("ethaddr", enetaddr);
Stelian Pop61e69d72008-05-08 20:52:22 +0200354#endif
Mike Rapoporte54d6c12007-08-12 08:48:27 +0300355 }
356
Mike Frysingerb2039652009-02-11 19:01:26 -0500357 printf("MAC: %pM\n", enetaddr);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500358
359 /* fill device MAC address registers */
360 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Mike Frysingerb2039652009-02-11 19:01:26 -0500361 DM9000_iow(oft, enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000362 for (i = 0, oft = 0x16; i < 8; i++, oft++)
363 DM9000_iow(oft, 0xff);
364
365 /* read back mac, just to be sure */
366 for (i = 0, oft = 0x10; i < 6; i++, oft++)
367 DM9000_DBG("%02x:", DM9000_ior(oft));
368 DM9000_DBG("\n");
369
370 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200371 /* RX enable */
372 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
373 /* Enable TX/RX interrupt mask */
374 DM9000_iow(DM9000_IMR, IMR_PAR);
375
wdenk7ac16102004-08-01 22:48:16 +0000376 i = 0;
377 while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
378 udelay(1000);
379 i++;
380 if (i == 10000) {
381 printf("could not establish link\n");
382 return 0;
383 }
384 }
385
386 /* see what we've got */
387 lnk = phy_read(17) >> 12;
388 printf("operating at ");
389 switch (lnk) {
390 case 1:
391 printf("10M half duplex ");
392 break;
393 case 2:
394 printf("10M full duplex ");
395 break;
396 case 4:
397 printf("100M half duplex ");
398 break;
399 case 8:
400 printf("100M full duplex ");
401 break;
402 default:
403 printf("unknown: %d ", lnk);
404 break;
405 }
406 printf("mode\n");
407 return 0;
408}
409
410/*
411 Hardware start transmission.
412 Send a packet to media from the upper layer.
413*/
414int
415eth_send(volatile void *packet, int length)
416{
wdenk7ac16102004-08-01 22:48:16 +0000417 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200418 struct board_info *db = &dm9000_info;
419
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200420 DM9000_DMP_PACKET("eth_send", packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000421
Remy Bohmer16cb2642008-06-03 15:26:23 +0200422 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
423
wdenk7ac16102004-08-01 22:48:16 +0000424 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200425 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000426
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200427 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200428 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000429
430 /* Set TX length to DM9000 */
431 DM9000_iow(DM9000_TXPLL, length & 0xff);
432 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
433
434 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200435 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000436
437 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200438 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200439 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
440 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000441 if (get_timer(0) >= tmo) {
442 printf("transmission timeout\n");
443 break;
444 }
445 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200446 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
447
wdenk7ac16102004-08-01 22:48:16 +0000448 DM9000_DBG("transmit done\n\n");
449 return 0;
450}
451
452/*
453 Stop the interface.
454 The interface is stopped when it is brought.
455*/
456void
457eth_halt(void)
458{
459 DM9000_DBG("eth_halt\n");
460
461 /* RESET devie */
462 phy_write(0, 0x8000); /* PHY RESET */
463 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
464 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
465 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
466}
467
468/*
469 Received a packet and pass to upper layer
470*/
471int
472eth_rx(void)
473{
474 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
475 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200476 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000477
Remy Bohmereec38a12008-06-03 15:26:25 +0200478 /* Check packet ready or not, we must check
479 the ISR status first for DM9000A */
480 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000481 return 0;
482
Remy Bohmereec38a12008-06-03 15:26:25 +0200483 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000484
Remy Bohmereec38a12008-06-03 15:26:25 +0200485 /* There is _at least_ 1 package in the fifo, read them all */
486 for (;;) {
487 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000488
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200489 /* Get most updated data,
490 only look at bits 0:1, See application notes DM9000 */
491 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000492
Remy Bohmereec38a12008-06-03 15:26:25 +0200493 /* Status check: this byte must be 0 or 1 */
494 if (rxbyte > DM9000_PKT_RDY) {
495 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
496 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
497 printf("DM9000 error: status check fail: 0x%x\n",
498 rxbyte);
499 return 0;
500 }
wdenk7ac16102004-08-01 22:48:16 +0000501
Remy Bohmereec38a12008-06-03 15:26:25 +0200502 if (rxbyte != DM9000_PKT_RDY)
503 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000504
Remy Bohmereec38a12008-06-03 15:26:25 +0200505 DM9000_DBG("receiving packet\n");
506
507 /* A packet ready now & Get status/length */
508 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000509
Remy Bohmereec38a12008-06-03 15:26:25 +0200510 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
511
512 /* Move data from DM9000 */
513 /* Read received packet from RX SRAM */
514 (db->inblk)(rdptr, RxLen);
515
516 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
517 || (RxLen > DM9000_PKT_MAX)) {
518 if (RxStatus & 0x100) {
519 printf("rx fifo error\n");
520 }
521 if (RxStatus & 0x200) {
522 printf("rx crc error\n");
523 }
524 if (RxStatus & 0x8000) {
525 printf("rx length error\n");
526 }
527 if (RxLen > DM9000_PKT_MAX) {
528 printf("rx length too big\n");
529 dm9000_reset();
530 }
531 } else {
532 DM9000_DMP_PACKET("eth_rx", rdptr, RxLen);
533
534 DM9000_DBG("passing packet to upper layer\n");
535 NetReceive(NetRxPackets[0], RxLen);
536 }
wdenk7ac16102004-08-01 22:48:16 +0000537 }
538 return 0;
539}
540
541/*
542 Read a word data from SROM
543*/
David Brownell71907572009-04-16 23:15:15 -0700544static void read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000545{
546 DM9000_iow(DM9000_EPAR, offset);
547 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200548 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000549 DM9000_iow(DM9000_EPCR, 0x0);
David Brownell71907572009-04-16 23:15:15 -0700550 to[0] = DM9000_ior(DM9000_EPDRL);
551 to[1] = DM9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000552}
553
stefano babic6708a602007-08-30 23:01:49 +0200554void
555write_srom_word(int offset, u16 val)
556{
557 DM9000_iow(DM9000_EPAR, offset);
558 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
559 DM9000_iow(DM9000_EPDRL, (val & 0xff));
560 DM9000_iow(DM9000_EPCR, 0x12);
561 udelay(8000);
562 DM9000_iow(DM9000_EPCR, 0);
563}
564
565
wdenk7ac16102004-08-01 22:48:16 +0000566/*
567 Read a byte from I/O port
568*/
569static u8
570DM9000_ior(int reg)
571{
572 DM9000_outb(reg, DM9000_IO);
573 return DM9000_inb(DM9000_DATA);
574}
575
576/*
577 Write a byte to I/O port
578*/
579static void
580DM9000_iow(int reg, u8 value)
581{
582 DM9000_outb(reg, DM9000_IO);
583 DM9000_outb(value, DM9000_DATA);
584}
585
586/*
587 Read a word from phyxcer
588*/
589static u16
590phy_read(int reg)
591{
592 u16 val;
593
594 /* Fill the phyxcer register into REG_0C */
595 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
596 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200597 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000598 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
599 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
600
601 /* The read data keeps on REG_0D & REG_0E */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200602 DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000603 return val;
604}
605
606/*
607 Write a word to phyxcer
608*/
609static void
610phy_write(int reg, u16 value)
611{
612
613 /* Fill the phyxcer register into REG_0C */
614 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
615
616 /* Fill the written data into REG_0D & REG_0E */
617 DM9000_iow(DM9000_EPDRL, (value & 0xff));
618 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
619 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200620 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000621 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200622 DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000623}