blob: a6c0a2452f2c8bcb76019f2eaff401f6f760131e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk7ac16102004-08-01 22:48:16 +00002/*
3 dm9000.c: Version 1.2 12/15/2003
4
5 A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
6 Copyright (C) 1997 Sten Wang
7
wdenk7ac16102004-08-01 22:48:16 +00008 (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
9
10V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
Wolfgang Denka1be4762008-05-20 16:00:29 +020011 06/22/2001 Support DM9801 progrmming
12 E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
13 E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
14 R17 = (R17 & 0xfff0) | NF + 3
15 E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
16 R17 = (R17 & 0xfff0) | NF
wdenk7ac16102004-08-01 22:48:16 +000017
Wolfgang Denka1be4762008-05-20 16:00:29 +020018v1.00 modify by simon 2001.9.5
Wolfgang Denkec7fbf52013-10-04 17:43:24 +020019 change for kernel 2.4.x
wdenk7ac16102004-08-01 22:48:16 +000020
Wolfgang Denka1be4762008-05-20 16:00:29 +020021v1.1 11/09/2001 fix force mode bug
wdenk7ac16102004-08-01 22:48:16 +000022
23v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
24 Fixed phy reset.
25 Added tx/rx 32 bit mode.
26 Cleaned up for kernel merge.
27
28--------------------------------------
29
Remy Bohmer5f63bf42008-06-03 15:26:21 +020030 12/15/2003 Initial port to u-boot by
31 Sascha Hauer <saschahauer@web.de>
32
33 06/03/2008 Remy Bohmer <linux@bohmer.net>
Remy Bohmereec38a12008-06-03 15:26:25 +020034 - Fixed the driver to work with DM9000A.
35 (check on ISR receive status bit before reading the
36 FIFO as described in DM9000 programming guide and
37 application notes)
Remy Bohmer5f63bf42008-06-03 15:26:21 +020038 - Added autodetect of databus width.
Remy Bohmerf4329dc2008-06-03 15:26:22 +020039 - Made debug code compile again.
Remy Bohmer16cb2642008-06-03 15:26:23 +020040 - Adapt eth_send such that it matches the DM9000*
41 application notes. Needed to make it work properly
42 for DM9000A.
Remy Bohmer2f13d2c2008-06-03 15:26:24 +020043 - Adapted reset procedure to match DM9000 application
44 notes (i.e. double reset)
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020045 - some minor code cleanups
Remy Bohmer5f63bf42008-06-03 15:26:21 +020046 These changes are tested with DM9000{A,EP,E} together
Remy Bohmercd9a36c2009-05-03 12:11:40 +020047 with a 200MHz Atmel AT91SAM9261 core
wdenk7ac16102004-08-01 22:48:16 +000048
Andrew Dyera62f5d42008-08-26 17:03:38 -050049TODO: external MII is not functional, only internal at the moment.
wdenk7ac16102004-08-01 22:48:16 +000050*/
51
52#include <common.h>
53#include <command.h>
54#include <net.h>
55#include <asm/io.h>
Remy Bohmercd9a36c2009-05-03 12:11:40 +020056#include <dm9000.h>
wdenk7ac16102004-08-01 22:48:16 +000057
wdenk7ac16102004-08-01 22:48:16 +000058#include "dm9000x.h"
59
60/* Board/System/Debug information/definition ---------------- */
61
wdenk7ac16102004-08-01 22:48:16 +000062/* #define CONFIG_DM9000_DEBUG */
63
64#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020065#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
66#define DM9000_DMP_PACKET(func,packet,length) \
67 do { \
68 int i; \
Thomas Weberc1ff5292009-12-09 09:38:04 +010069 printf("%s: length: %d\n", func, length); \
Remy Bohmerf4329dc2008-06-03 15:26:22 +020070 for (i = 0; i < length; i++) { \
71 if (i % 8 == 0) \
72 printf("\n%s: %02x: ", func, i); \
73 printf("%02x ", ((unsigned char *) packet)[i]); \
74 } printf("\n"); \
75 } while(0)
76#else
wdenk7ac16102004-08-01 22:48:16 +000077#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020078#define DM9000_DMP_PACKET(func,packet,length)
79#endif
80
wdenk7ac16102004-08-01 22:48:16 +000081/* Structure/enum declaration ------------------------------- */
82typedef struct board_info {
83 u32 runt_length_counter; /* counter: RX length < 64byte */
84 u32 long_length_counter; /* counter: RX length > 1514byte */
85 u32 reset_counter; /* counter: RESET */
86 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
87 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
88 u16 tx_pkt_cnt;
89 u16 queue_start_addr;
90 u16 dbug_cnt;
91 u8 phy_addr;
92 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +000093 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +020094 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +020095 void (*inblk)(void *data_ptr, int count);
96 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer7eefd922009-05-02 21:49:18 +020097 struct eth_device netdev;
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020098} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +020099static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000100
Remy Bohmer7eefd922009-05-02 21:49:18 +0200101
wdenk7ac16102004-08-01 22:48:16 +0000102/* function declaration ------------------------------------- */
wdenk7ac16102004-08-01 22:48:16 +0000103static int dm9000_probe(void);
Andy Fleming0d2df962011-03-22 22:49:13 -0500104static u16 dm9000_phy_read(int);
105static void dm9000_phy_write(int, u16);
wdenk7ac16102004-08-01 22:48:16 +0000106static u8 DM9000_ior(int);
107static void DM9000_iow(int reg, u8 value);
108
109/* DM9000 network board routine ---------------------------- */
Jason Jinc74c4362011-08-25 15:46:43 +0800110#ifndef CONFIG_DM9000_BYTE_SWAPPED
Mike Frysinger6f6ce112010-07-05 02:29:21 -0400111#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
112#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
113#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
114#define DM9000_inb(r) readb((volatile u8 *)(r))
115#define DM9000_inw(r) readw((volatile u16 *)(r))
116#define DM9000_inl(r) readl((volatile u32 *)(r))
Jason Jinc74c4362011-08-25 15:46:43 +0800117#else
118#define DM9000_outb(d, r) __raw_writeb(d, r)
119#define DM9000_outw(d, r) __raw_writew(d, r)
120#define DM9000_outl(d, r) __raw_writel(d, r)
121#define DM9000_inb(r) __raw_readb(r)
122#define DM9000_inw(r) __raw_readw(r)
123#define DM9000_inl(r) __raw_readl(r)
124#endif
wdenk7ac16102004-08-01 22:48:16 +0000125
126#ifdef CONFIG_DM9000_DEBUG
127static void
128dump_regs(void)
129{
130 DM9000_DBG("\n");
131 DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
132 DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
133 DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
134 DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
135 DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
136 DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
137 DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
Remy Bohmerf4329dc2008-06-03 15:26:22 +0200138 DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
wdenk7ac16102004-08-01 22:48:16 +0000139 DM9000_DBG("\n");
140}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200141#endif
142
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200143static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200144{
145 int i;
146 for (i = 0; i < count; i++)
147 DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
148}
149
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200150static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200151{
152 int i;
153 u32 tmplen = (count + 1) / 2;
154
155 for (i = 0; i < tmplen; i++)
156 DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
157}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200158static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200159{
160 int i;
161 u32 tmplen = (count + 3) / 4;
162
163 for (i = 0; i < tmplen; i++)
164 DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
165}
166
167static void dm9000_inblk_8bit(void *data_ptr, int count)
168{
169 int i;
170 for (i = 0; i < count; i++)
171 ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
172}
173
174static void dm9000_inblk_16bit(void *data_ptr, int count)
175{
176 int i;
177 u32 tmplen = (count + 1) / 2;
178
179 for (i = 0; i < tmplen; i++)
180 ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
181}
182static void dm9000_inblk_32bit(void *data_ptr, int count)
183{
184 int i;
185 u32 tmplen = (count + 3) / 4;
186
187 for (i = 0; i < tmplen; i++)
188 ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
189}
190
191static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
192{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200193 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200194
195 DM9000_outb(DM9000_MRCMD, DM9000_IO);
196
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200197 tmpdata = DM9000_inl(DM9000_DATA);
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500198 *RxStatus = __le16_to_cpu(tmpdata);
199 *RxLen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200200}
201
202static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
203{
204 DM9000_outb(DM9000_MRCMD, DM9000_IO);
205
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500206 *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
207 *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200208}
209
210static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
211{
212 DM9000_outb(DM9000_MRCMD, DM9000_IO);
213
TsiChung Liew73dab3a2008-06-25 15:48:52 -0500214 *RxStatus =
215 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
216 (DM9000_inb(DM9000_DATA) << 8));
217 *RxLen =
218 __le16_to_cpu(DM9000_inb(DM9000_DATA) +
219 (DM9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200220}
wdenk7ac16102004-08-01 22:48:16 +0000221
222/*
223 Search DM9000 board, allocate space and register it
224*/
225int
226dm9000_probe(void)
227{
228 u32 id_val;
229 id_val = DM9000_ior(DM9000_VIDL);
230 id_val |= DM9000_ior(DM9000_VIDH) << 8;
231 id_val |= DM9000_ior(DM9000_PIDL) << 16;
232 id_val |= DM9000_ior(DM9000_PIDH) << 24;
233 if (id_val == DM9000_ID) {
234 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
235 id_val);
236 return 0;
237 } else {
238 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
239 CONFIG_DM9000_BASE, id_val);
240 return -1;
241 }
wdenk7ac16102004-08-01 22:48:16 +0000242}
243
244/* General Purpose dm9000 reset routine */
245static void
246dm9000_reset(void)
247{
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200248 DM9000_DBG("resetting DM9000\n");
249
250 /* Reset DM9000,
251 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
252
Andrew Dyera62f5d42008-08-26 17:03:38 -0500253 /* DEBUG: Make all GPIO0 outputs, all others inputs */
254 DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200255 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
256 DM9000_iow(DM9000_GPR, 0);
257 /* Step 2: Software reset */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500258 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200259
260 do {
261 DM9000_DBG("resetting the DM9000, 1st reset\n");
262 udelay(25); /* Wait at least 20 us */
263 } while (DM9000_ior(DM9000_NCR) & 1);
264
265 DM9000_iow(DM9000_NCR, 0);
Andrew Dyera62f5d42008-08-26 17:03:38 -0500266 DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200267
268 do {
269 DM9000_DBG("resetting the DM9000, 2nd reset\n");
270 udelay(25); /* Wait at least 20 us */
271 } while (DM9000_ior(DM9000_NCR) & 1);
272
273 /* Check whether the ethernet controller is present */
274 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
275 (DM9000_ior(DM9000_PIDH) != 0x90))
276 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000277}
278
Remy Bohmer7eefd922009-05-02 21:49:18 +0200279/* Initialize dm9000 board
wdenk7ac16102004-08-01 22:48:16 +0000280*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200281static int dm9000_init(struct eth_device *dev, bd_t *bd)
wdenk7ac16102004-08-01 22:48:16 +0000282{
283 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200284 u8 io_mode;
285 struct board_info *db = &dm9000_info;
286
Remy Bohmer7eefd922009-05-02 21:49:18 +0200287 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000288
289 /* RESET device */
290 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500291
292 if (dm9000_probe() < 0)
293 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000294
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200295 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
296 io_mode = DM9000_ior(DM9000_ISR) >> 6;
297
298 switch (io_mode) {
299 case 0x0: /* 16-bit mode */
300 printf("DM9000: running in 16 bit mode\n");
301 db->outblk = dm9000_outblk_16bit;
302 db->inblk = dm9000_inblk_16bit;
303 db->rx_status = dm9000_rx_status_16bit;
304 break;
305 case 0x01: /* 32-bit mode */
306 printf("DM9000: running in 32 bit mode\n");
307 db->outblk = dm9000_outblk_32bit;
308 db->inblk = dm9000_inblk_32bit;
309 db->rx_status = dm9000_rx_status_32bit;
310 break;
311 case 0x02: /* 8 bit mode */
312 printf("DM9000: running in 8 bit mode\n");
313 db->outblk = dm9000_outblk_8bit;
314 db->inblk = dm9000_inblk_8bit;
315 db->rx_status = dm9000_rx_status_8bit;
316 break;
317 default:
318 /* Assume 8 bit mode, will probably not work anyway */
319 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
320 db->outblk = dm9000_outblk_8bit;
321 db->inblk = dm9000_inblk_8bit;
322 db->rx_status = dm9000_rx_status_8bit;
323 break;
324 }
325
Andrew Dyera62f5d42008-08-26 17:03:38 -0500326 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200327 DM9000_iow(DM9000_NCR, 0x0);
328 /* TX Polling clear */
329 DM9000_iow(DM9000_TCR, 0);
330 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500331 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200332 /* Flow Control : High/Low Water */
333 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
334 /* SH FIXME: This looks strange! Flow Control */
335 DM9000_iow(DM9000_FCR, 0x0);
336 /* Special Mode */
337 DM9000_iow(DM9000_SMCR, 0);
338 /* clear TX status */
339 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
340 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500341 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000342
Ben Warren8707f622009-10-21 21:53:39 -0700343 printf("MAC: %pM\n", dev->enetaddr);
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500344 if (!is_valid_ethaddr(dev->enetaddr)) {
Andrew Ruder1c377d12013-10-22 19:09:02 -0500345 printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
Andrew Ruder1c377d12013-10-22 19:09:02 -0500346 }
Andrew Dyera62f5d42008-08-26 17:03:38 -0500347
348 /* fill device MAC address registers */
349 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Ben Warren8707f622009-10-21 21:53:39 -0700350 DM9000_iow(oft, dev->enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000351 for (i = 0, oft = 0x16; i < 8; i++, oft++)
352 DM9000_iow(oft, 0xff);
353
354 /* read back mac, just to be sure */
355 for (i = 0, oft = 0x10; i < 6; i++, oft++)
356 DM9000_DBG("%02x:", DM9000_ior(oft));
357 DM9000_DBG("\n");
358
359 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200360 /* RX enable */
361 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
362 /* Enable TX/RX interrupt mask */
363 DM9000_iow(DM9000_IMR, IMR_PAR);
364
wdenk7ac16102004-08-01 22:48:16 +0000365 i = 0;
Andy Fleming0d2df962011-03-22 22:49:13 -0500366 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk7ac16102004-08-01 22:48:16 +0000367 udelay(1000);
368 i++;
369 if (i == 10000) {
370 printf("could not establish link\n");
371 return 0;
372 }
373 }
374
375 /* see what we've got */
Andy Fleming0d2df962011-03-22 22:49:13 -0500376 lnk = dm9000_phy_read(17) >> 12;
wdenk7ac16102004-08-01 22:48:16 +0000377 printf("operating at ");
378 switch (lnk) {
379 case 1:
380 printf("10M half duplex ");
381 break;
382 case 2:
383 printf("10M full duplex ");
384 break;
385 case 4:
386 printf("100M half duplex ");
387 break;
388 case 8:
389 printf("100M full duplex ");
390 break;
391 default:
392 printf("unknown: %d ", lnk);
393 break;
394 }
395 printf("mode\n");
396 return 0;
397}
398
399/*
400 Hardware start transmission.
401 Send a packet to media from the upper layer.
402*/
Joe Hershbergerab1ac412012-05-21 14:45:23 +0000403static int dm9000_send(struct eth_device *netdev, void *packet, int length)
wdenk7ac16102004-08-01 22:48:16 +0000404{
wdenk7ac16102004-08-01 22:48:16 +0000405 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200406 struct board_info *db = &dm9000_info;
407
Remy Bohmer7eefd922009-05-02 21:49:18 +0200408 DM9000_DMP_PACKET(__func__ , packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000409
Remy Bohmer16cb2642008-06-03 15:26:23 +0200410 DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
411
wdenk7ac16102004-08-01 22:48:16 +0000412 /* Move data to DM9000 TX RAM */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200413 DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000414
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200415 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200416 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000417
418 /* Set TX length to DM9000 */
419 DM9000_iow(DM9000_TXPLL, length & 0xff);
420 DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
421
422 /* Issue TX polling command */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200423 DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000424
425 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200426 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Remy Bohmer16cb2642008-06-03 15:26:23 +0200427 while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
428 !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000429 if (get_timer(0) >= tmo) {
430 printf("transmission timeout\n");
431 break;
432 }
433 }
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 DM9000_DBG("transmit done\n\n");
437 return 0;
438}
439
440/*
441 Stop the interface.
442 The interface is stopped when it is brought.
443*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200444static void dm9000_halt(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000445{
Remy Bohmer7eefd922009-05-02 21:49:18 +0200446 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000447
448 /* RESET devie */
Andy Fleming0d2df962011-03-22 22:49:13 -0500449 dm9000_phy_write(0, 0x8000); /* PHY RESET */
wdenk7ac16102004-08-01 22:48:16 +0000450 DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
451 DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
452 DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
453}
454
455/*
456 Received a packet and pass to upper layer
457*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200458static int dm9000_rx(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000459{
Joe Hershberger9f09a362015-04-08 01:41:06 -0500460 u8 rxbyte;
461 u8 *rdptr = (u8 *)net_rx_packets[0];
wdenk7ac16102004-08-01 22:48:16 +0000462 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200463 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000464
Remy Bohmereec38a12008-06-03 15:26:25 +0200465 /* Check packet ready or not, we must check
466 the ISR status first for DM9000A */
467 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000468 return 0;
469
Remy Bohmereec38a12008-06-03 15:26:25 +0200470 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000471
Remy Bohmereec38a12008-06-03 15:26:25 +0200472 /* There is _at least_ 1 package in the fifo, read them all */
473 for (;;) {
474 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000475
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200476 /* Get most updated data,
477 only look at bits 0:1, See application notes DM9000 */
478 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000479
Remy Bohmereec38a12008-06-03 15:26:25 +0200480 /* Status check: this byte must be 0 or 1 */
481 if (rxbyte > DM9000_PKT_RDY) {
482 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
483 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
484 printf("DM9000 error: status check fail: 0x%x\n",
485 rxbyte);
486 return 0;
487 }
wdenk7ac16102004-08-01 22:48:16 +0000488
Remy Bohmereec38a12008-06-03 15:26:25 +0200489 if (rxbyte != DM9000_PKT_RDY)
490 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000491
Remy Bohmereec38a12008-06-03 15:26:25 +0200492 DM9000_DBG("receiving packet\n");
493
494 /* A packet ready now & Get status/length */
495 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000496
Remy Bohmereec38a12008-06-03 15:26:25 +0200497 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
498
499 /* Move data from DM9000 */
500 /* Read received packet from RX SRAM */
501 (db->inblk)(rdptr, RxLen);
502
503 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
504 || (RxLen > DM9000_PKT_MAX)) {
505 if (RxStatus & 0x100) {
506 printf("rx fifo error\n");
507 }
508 if (RxStatus & 0x200) {
509 printf("rx crc error\n");
510 }
511 if (RxStatus & 0x8000) {
512 printf("rx length error\n");
513 }
514 if (RxLen > DM9000_PKT_MAX) {
515 printf("rx length too big\n");
516 dm9000_reset();
517 }
518 } else {
Remy Bohmer7eefd922009-05-02 21:49:18 +0200519 DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200520
521 DM9000_DBG("passing packet to upper layer\n");
Joe Hershberger9f09a362015-04-08 01:41:06 -0500522 net_process_received_packet(net_rx_packets[0], RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200523 }
wdenk7ac16102004-08-01 22:48:16 +0000524 }
525 return 0;
526}
527
528/*
529 Read a word data from SROM
530*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200531#if !defined(CONFIG_DM9000_NO_SROM)
532void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000533{
534 DM9000_iow(DM9000_EPAR, offset);
535 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200536 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000537 DM9000_iow(DM9000_EPCR, 0x0);
David Brownell71907572009-04-16 23:15:15 -0700538 to[0] = DM9000_ior(DM9000_EPDRL);
539 to[1] = DM9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000540}
541
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200542void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200543{
544 DM9000_iow(DM9000_EPAR, offset);
545 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
546 DM9000_iow(DM9000_EPDRL, (val & 0xff));
547 DM9000_iow(DM9000_EPCR, 0x12);
548 udelay(8000);
549 DM9000_iow(DM9000_EPCR, 0);
550}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200551#endif
Ben Warren8707f622009-10-21 21:53:39 -0700552
553static void dm9000_get_enetaddr(struct eth_device *dev)
554{
555#if !defined(CONFIG_DM9000_NO_SROM)
556 int i;
557 for (i = 0; i < 3; i++)
558 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
559#endif
560}
stefano babic6708a602007-08-30 23:01:49 +0200561
wdenk7ac16102004-08-01 22:48:16 +0000562/*
563 Read a byte from I/O port
564*/
565static u8
566DM9000_ior(int reg)
567{
568 DM9000_outb(reg, DM9000_IO);
569 return DM9000_inb(DM9000_DATA);
570}
571
572/*
573 Write a byte to I/O port
574*/
575static void
576DM9000_iow(int reg, u8 value)
577{
578 DM9000_outb(reg, DM9000_IO);
579 DM9000_outb(value, DM9000_DATA);
580}
581
582/*
583 Read a word from phyxcer
584*/
585static u16
Andy Fleming0d2df962011-03-22 22:49:13 -0500586dm9000_phy_read(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000587{
588 u16 val;
589
590 /* Fill the phyxcer register into REG_0C */
591 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
592 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200593 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000594 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
595 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
596
597 /* The read data keeps on REG_0D & REG_0E */
Andy Fleming0d2df962011-03-22 22:49:13 -0500598 DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000599 return val;
600}
601
602/*
603 Write a word to phyxcer
604*/
605static void
Andy Fleming0d2df962011-03-22 22:49:13 -0500606dm9000_phy_write(int reg, u16 value)
wdenk7ac16102004-08-01 22:48:16 +0000607{
608
609 /* Fill the phyxcer register into REG_0C */
610 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
611
612 /* Fill the written data into REG_0D & REG_0E */
613 DM9000_iow(DM9000_EPDRL, (value & 0xff));
614 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
615 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200616 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000617 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Andy Fleming0d2df962011-03-22 22:49:13 -0500618 DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000619}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200620
621int dm9000_initialize(bd_t *bis)
622{
623 struct eth_device *dev = &(dm9000_info.netdev);
624
Ben Warren8707f622009-10-21 21:53:39 -0700625 /* Load MAC address from EEPROM */
626 dm9000_get_enetaddr(dev);
627
Remy Bohmer7eefd922009-05-02 21:49:18 +0200628 dev->init = dm9000_init;
629 dev->halt = dm9000_halt;
630 dev->send = dm9000_send;
631 dev->recv = dm9000_rx;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000632 strcpy(dev->name, "dm9000");
Remy Bohmer7eefd922009-05-02 21:49:18 +0200633
634 eth_register(dev);
635
636 return 0;
637}