blob: 04241109cc016798ed9e37f1fa9721e0aa976bac [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; \
Thomas Weberc1ff5292009-12-09 09:38:04 +010078 printf("%s: length: %d\n", func, length); \
Remy Bohmerf4329dc2008-06-03 15:26:22 +020079 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);
Andy Fleming0d2df962011-03-22 22:49:13 -0500113static u16 dm9000_phy_read(int);
114static void dm9000_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 ---------------------------- */
Jason Jinc74c4362011-08-25 15:46:43 +0800119#ifndef CONFIG_DM9000_BYTE_SWAPPED
Mike Frysinger6f6ce112010-07-05 02:29:21 -0400120#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
121#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
122#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
123#define DM9000_inb(r) readb((volatile u8 *)(r))
124#define DM9000_inw(r) readw((volatile u16 *)(r))
125#define DM9000_inl(r) readl((volatile u32 *)(r))
Jason Jinc74c4362011-08-25 15:46:43 +0800126#else
127#define DM9000_outb(d, r) __raw_writeb(d, r)
128#define DM9000_outw(d, r) __raw_writew(d, r)
129#define DM9000_outl(d, r) __raw_writel(d, r)
130#define DM9000_inb(r) __raw_readb(r)
131#define DM9000_inw(r) __raw_readw(r)
132#define DM9000_inl(r) __raw_readl(r)
133#endif
wdenk7ac16102004-08-01 22:48:16 +0000134
135#ifdef CONFIG_DM9000_DEBUG
136static void
137dump_regs(void)
138{
139 DM9000_DBG("\n");
140 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
141 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
142 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
143 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
144 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
145 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
146 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200147 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000148 DM9000_DBG("\n");
149}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200150#endif
151
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200152static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200153{
154 int i;
155 for (i = 0; i < count; i++)
156 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
157}
158
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200159static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200160{
161 int i;
162 u32 tmplen = (count + 1) / 2;
163
164 for (i = 0; i < tmplen; i++)
165 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
166}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200167static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200168{
169 int i;
170 u32 tmplen = (count + 3) / 4;
171
172 for (i = 0; i < tmplen; i++)
173 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
174}
175
176static void dm9000_inblk_8bit(void *data_ptr, int count)
177{
178 int i;
179 for (i = 0; i < count; i++)
180 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
181}
182
183static void dm9000_inblk_16bit(void *data_ptr, int count)
184{
185 int i;
186 u32 tmplen = (count + 1) / 2;
187
188 for (i = 0; i < tmplen; i++)
189 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
190}
191static void dm9000_inblk_32bit(void *data_ptr, int count)
192{
193 int i;
194 u32 tmplen = (count + 3) / 4;
195
196 for (i = 0; i < tmplen; i++)
197 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
198}
199
200static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
201{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200202 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200203
204 DM9000_outb(DM9000_MRCMD, DM9000_IO);
205
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200206 tmpdata = DM9000_inl(DM9000_DATA);
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500207 *RxStatus = __le16_to_cpu(tmpdata);
208 *RxLen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200209}
210
211static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
212{
213 DM9000_outb(DM9000_MRCMD, DM9000_IO);
214
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500215 *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
216 *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200217}
218
219static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
220{
221 DM9000_outb(DM9000_MRCMD, DM9000_IO);
222
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500223 *RxStatus =
224 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
225 (DM9000_inb(DM9000_DATA) << 8));
226 *RxLen =
227 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
228 (DM9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200229}
wdenk7ac16102004-08-01 22:48:16 +0000230
231/*
232 Search DM9000 board, allocate space and register it
233*/
234int
235dm9000_probe(void)
236{
237 u32 id_val;
238 id_val = DM9000_ior(DM9000_VIDL);
239 id_val |= DM9000_ior(DM9000_VIDH) << 8;
240 id_val |= DM9000_ior(DM9000_PIDL) << 16;
241 id_val |= DM9000_ior(DM9000_PIDH) << 24;
242 if (id_val == DM9000_ID) {
243 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
244 id_val);
245 return 0;
246 } else {
247 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
248 CONFIG_DM9000_BASE, id_val);
249 return -1;
250 }
wdenk7ac16102004-08-01 22:48:16 +0000251}
252
253/* General Purpose dm9000 reset routine */
254static void
255dm9000_reset(void)
256{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200257 DM9000_DBG("resetting DM9000\n");
258
259 /* Reset DM9000,
260 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
261
Andrew Dyera62f5d42008-08-26 17:03:38 -0500262 /* DEBUG: Make all GPIO0 outputs, all others inputs */
263 DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200264 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
265 DM9000_iow(DM9000_GPR, 0);
266 /* Step 2: Software reset */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500267 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200268
269 do {
270 DM9000_DBG("resetting the DM9000, 1st reset\n");
271 udelay(25); /* Wait at least 20 us */
272 } while (DM9000_ior(DM9000_NCR) & 1);
273
274 DM9000_iow(DM9000_NCR, 0);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500275 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200276
277 do {
278 DM9000_DBG("resetting the DM9000, 2nd reset\n");
279 udelay(25); /* Wait at least 20 us */
280 } while (DM9000_ior(DM9000_NCR) & 1);
281
282 /* Check whether the ethernet controller is present */
283 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
284 (DM9000_ior(DM9000_PIDH) != 0x90))
285 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000286}
287
Remy Bohmer7eefd922009-05-02 21:49:18 +0200288/* Initialize dm9000 board
wdenk7ac16102004-08-01 22:48:16 +0000289*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200290static int dm9000_init(struct eth_device *dev, bd_t *bd)
wdenk7ac16102004-08-01 22:48:16 +0000291{
292 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200293 u8 io_mode;
294 struct board_info *db = &dm9000_info;
295
Remy Bohmer7eefd922009-05-02 21:49:18 +0200296 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000297
298 /* RESET device */
299 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500300
301 if (dm9000_probe() < 0)
302 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000303
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200304 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
305 io_mode = DM9000_ior(DM9000_ISR) >> 6;
306
307 switch (io_mode) {
308 case 0x0: /* 16-bit mode */
309 printf("DM9000: running in 16 bit mode\n");
310 db->outblk = dm9000_outblk_16bit;
311 db->inblk = dm9000_inblk_16bit;
312 db->rx_status = dm9000_rx_status_16bit;
313 break;
314 case 0x01: /* 32-bit mode */
315 printf("DM9000: running in 32 bit mode\n");
316 db->outblk = dm9000_outblk_32bit;
317 db->inblk = dm9000_inblk_32bit;
318 db->rx_status = dm9000_rx_status_32bit;
319 break;
320 case 0x02: /* 8 bit mode */
321 printf("DM9000: running in 8 bit mode\n");
322 db->outblk = dm9000_outblk_8bit;
323 db->inblk = dm9000_inblk_8bit;
324 db->rx_status = dm9000_rx_status_8bit;
325 break;
326 default:
327 /* Assume 8 bit mode, will probably not work anyway */
328 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
329 db->outblk = dm9000_outblk_8bit;
330 db->inblk = dm9000_inblk_8bit;
331 db->rx_status = dm9000_rx_status_8bit;
332 break;
333 }
334
Andrew Dyera62f5d42008-08-26 17:03:38 -0500335 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200336 DM9000_iow(DM9000_NCR, 0x0);
337 /* TX Polling clear */
338 DM9000_iow(DM9000_TCR, 0);
339 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500340 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200341 /* Flow Control : High/Low Water */
342 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
343 /* SH FIXME: This looks strange! Flow Control */
344 DM9000_iow(DM9000_FCR, 0x0);
345 /* Special Mode */
346 DM9000_iow(DM9000_SMCR, 0);
347 /* clear TX status */
348 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
349 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500350 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000351
Ben Warren8707f622009-10-21 21:53:39 -0700352 printf("MAC: %pM\n", dev->enetaddr);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500353
354 /* fill device MAC address registers */
355 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Ben Warren8707f622009-10-21 21:53:39 -0700356 DM9000_iow(oft, dev->enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000357 for (i = 0, oft = 0x16; i < 8; i++, oft++)
358 DM9000_iow(oft, 0xff);
359
360 /* read back mac, just to be sure */
361 for (i = 0, oft = 0x10; i < 6; i++, oft++)
362 DM9000_DBG("%02x:", DM9000_ior(oft));
363 DM9000_DBG("\n");
364
365 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200366 /* RX enable */
367 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
368 /* Enable TX/RX interrupt mask */
369 DM9000_iow(DM9000_IMR, IMR_PAR);
370
wdenk7ac16102004-08-01 22:48:16 +0000371 i = 0;
Andy Fleming0d2df962011-03-22 22:49:13 -0500372 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk7ac16102004-08-01 22:48:16 +0000373 udelay(1000);
374 i++;
375 if (i == 10000) {
376 printf("could not establish link\n");
377 return 0;
378 }
379 }
380
381 /* see what we've got */
Andy Fleming0d2df962011-03-22 22:49:13 -0500382 lnk = dm9000_phy_read(17) >> 12;
wdenk7ac16102004-08-01 22:48:16 +0000383 printf("operating at ");
384 switch (lnk) {
385 case 1:
386 printf("10M half duplex ");
387 break;
388 case 2:
389 printf("10M full duplex ");
390 break;
391 case 4:
392 printf("100M half duplex ");
393 break;
394 case 8:
395 printf("100M full duplex ");
396 break;
397 default:
398 printf("unknown: %d ", lnk);
399 break;
400 }
401 printf("mode\n");
402 return 0;
403}
404
405/*
406 Hardware start transmission.
407 Send a packet to media from the upper layer.
408*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200409static int dm9000_send(struct eth_device *netdev, volatile void *packet,
410 int length)
wdenk7ac16102004-08-01 22:48:16 +0000411{
wdenk7ac16102004-08-01 22:48:16 +0000412 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200413 struct board_info *db = &dm9000_info;
414
Remy Bohmer7eefd922009-05-02 21:49:18 +0200415 DM9000_DMP_PACKET(__func__ , packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000416
Remy Bohmer16cb2642008-06-03 15:26:23 +0200417 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
418
wdenk7ac16102004-08-01 22:48:16 +0000419 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200420 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000421
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200422 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200423 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000424
425 /* Set TX length to DM9000 */
426 DM9000_iow(DM9000_TXPLL, length & 0xff);
427 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
428
429 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200430 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000431
432 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200433 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200434 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
435 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000436 if (get_timer(0) >= tmo) {
437 printf("transmission timeout\n");
438 break;
439 }
440 }
Remy Bohmer16cb2642008-06-03 15:26:23 +0200441 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
442
wdenk7ac16102004-08-01 22:48:16 +0000443 DM9000_DBG("transmit done\n\n");
444 return 0;
445}
446
447/*
448 Stop the interface.
449 The interface is stopped when it is brought.
450*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200451static void dm9000_halt(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000452{
Remy Bohmer7eefd922009-05-02 21:49:18 +0200453 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000454
455 /* RESET devie */
Andy Fleming0d2df962011-03-22 22:49:13 -0500456 dm9000_phy_write(0, 0x8000); /* PHY RESET */
wdenk7ac16102004-08-01 22:48:16 +0000457 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
458 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
459 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
460}
461
462/*
463 Received a packet and pass to upper layer
464*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200465static int dm9000_rx(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000466{
467 u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
468 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200469 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000470
Remy Bohmereec38a12008-06-03 15:26:25 +0200471 /* Check packet ready or not, we must check
472 the ISR status first for DM9000A */
473 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000474 return 0;
475
Remy Bohmereec38a12008-06-03 15:26:25 +0200476 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000477
Remy Bohmereec38a12008-06-03 15:26:25 +0200478 /* There is _at least_ 1 package in the fifo, read them all */
479 for (;;) {
480 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000481
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200482 /* Get most updated data,
483 only look at bits 0:1, See application notes DM9000 */
484 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000485
Remy Bohmereec38a12008-06-03 15:26:25 +0200486 /* Status check: this byte must be 0 or 1 */
487 if (rxbyte > DM9000_PKT_RDY) {
488 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
489 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
490 printf("DM9000 error: status check fail: 0x%x\n",
491 rxbyte);
492 return 0;
493 }
wdenk7ac16102004-08-01 22:48:16 +0000494
Remy Bohmereec38a12008-06-03 15:26:25 +0200495 if (rxbyte != DM9000_PKT_RDY)
496 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000497
Remy Bohmereec38a12008-06-03 15:26:25 +0200498 DM9000_DBG("receiving packet\n");
499
500 /* A packet ready now & Get status/length */
501 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000502
Remy Bohmereec38a12008-06-03 15:26:25 +0200503 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
504
505 /* Move data from DM9000 */
506 /* Read received packet from RX SRAM */
507 (db->inblk)(rdptr, RxLen);
508
509 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
510 || (RxLen > DM9000_PKT_MAX)) {
511 if (RxStatus & 0x100) {
512 printf("rx fifo error\n");
513 }
514 if (RxStatus & 0x200) {
515 printf("rx crc error\n");
516 }
517 if (RxStatus & 0x8000) {
518 printf("rx length error\n");
519 }
520 if (RxLen > DM9000_PKT_MAX) {
521 printf("rx length too big\n");
522 dm9000_reset();
523 }
524 } else {
Remy Bohmer7eefd922009-05-02 21:49:18 +0200525 DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200526
527 DM9000_DBG("passing packet to upper layer\n");
528 NetReceive(NetRxPackets[0], RxLen);
529 }
wdenk7ac16102004-08-01 22:48:16 +0000530 }
531 return 0;
532}
533
534/*
535 Read a word data from SROM
536*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200537#if !defined(CONFIG_DM9000_NO_SROM)
538void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000539{
540 DM9000_iow(DM9000_EPAR, offset);
541 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200542 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000543 DM9000_iow(DM9000_EPCR, 0x0);
David Brownell71907572009-04-16 23:15:15 -0700544 to[0] = DM9000_ior(DM9000_EPDRL);
545 to[1] = DM9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000546}
547
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200548void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200549{
550 DM9000_iow(DM9000_EPAR, offset);
551 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
552 DM9000_iow(DM9000_EPDRL, (val & 0xff));
553 DM9000_iow(DM9000_EPCR, 0x12);
554 udelay(8000);
555 DM9000_iow(DM9000_EPCR, 0);
556}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200557#endif
Ben Warren8707f622009-10-21 21:53:39 -0700558
559static void dm9000_get_enetaddr(struct eth_device *dev)
560{
561#if !defined(CONFIG_DM9000_NO_SROM)
562 int i;
563 for (i = 0; i < 3; i++)
564 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
565#endif
566}
stefano babic6708a602007-08-30 23:01:49 +0200567
wdenk7ac16102004-08-01 22:48:16 +0000568/*
569 Read a byte from I/O port
570*/
571static u8
572DM9000_ior(int reg)
573{
574 DM9000_outb(reg, DM9000_IO);
575 return DM9000_inb(DM9000_DATA);
576}
577
578/*
579 Write a byte to I/O port
580*/
581static void
582DM9000_iow(int reg, u8 value)
583{
584 DM9000_outb(reg, DM9000_IO);
585 DM9000_outb(value, DM9000_DATA);
586}
587
588/*
589 Read a word from phyxcer
590*/
591static u16
Andy Fleming0d2df962011-03-22 22:49:13 -0500592dm9000_phy_read(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000593{
594 u16 val;
595
596 /* Fill the phyxcer register into REG_0C */
597 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
598 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200599 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000600 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
601 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
602
603 /* The read data keeps on REG_0D & REG_0E */
Andy Fleming0d2df962011-03-22 22:49:13 -0500604 DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000605 return val;
606}
607
608/*
609 Write a word to phyxcer
610*/
611static void
Andy Fleming0d2df962011-03-22 22:49:13 -0500612dm9000_phy_write(int reg, u16 value)
wdenk7ac16102004-08-01 22:48:16 +0000613{
614
615 /* Fill the phyxcer register into REG_0C */
616 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
617
618 /* Fill the written data into REG_0D & REG_0E */
619 DM9000_iow(DM9000_EPDRL, (value & 0xff));
620 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
621 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200622 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000623 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Andy Fleming0d2df962011-03-22 22:49:13 -0500624 DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000625}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200626
627int dm9000_initialize(bd_t *bis)
628{
629 struct eth_device *dev = &(dm9000_info.netdev);
630
Ben Warren8707f622009-10-21 21:53:39 -0700631 /* Load MAC address from EEPROM */
632 dm9000_get_enetaddr(dev);
633
Remy Bohmer7eefd922009-05-02 21:49:18 +0200634 dev->init = dm9000_init;
635 dev->halt = dm9000_halt;
636 dev->send = dm9000_send;
637 dev->recv = dm9000_rx;
638 sprintf(dev->name, "dm9000");
639
640 eth_register(dev);
641
642 return 0;
643}