blob: ccd2131f88f156eb61b03bc241e4b505b50d66c8 [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
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
wdenk7ac16102004-08-01 22:48:16 +00008
9 (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
10
11V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
Wolfgang Denka1be4762008-05-20 16:00:29 +020012 06/22/2001 Support DM9801 progrmming
13 E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
14 E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
15 R17 = (R17 & 0xfff0) | NF + 3
16 E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
17 R17 = (R17 & 0xfff0) | NF
wdenk7ac16102004-08-01 22:48:16 +000018
Wolfgang Denka1be4762008-05-20 16:00:29 +020019v1.00 modify by simon 2001.9.5
Wolfgang Denkec7fbf52013-10-04 17:43:24 +020020 change for kernel 2.4.x
wdenk7ac16102004-08-01 22:48:16 +000021
Wolfgang Denka1be4762008-05-20 16:00:29 +020022v1.1 11/09/2001 fix force mode bug
wdenk7ac16102004-08-01 22:48:16 +000023
24v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
25 Fixed phy reset.
26 Added tx/rx 32 bit mode.
27 Cleaned up for kernel merge.
28
29--------------------------------------
30
Remy Bohmer5f63bf42008-06-03 15:26:21 +020031 12/15/2003 Initial port to u-boot by
32 Sascha Hauer <saschahauer@web.de>
33
34 06/03/2008 Remy Bohmer <linux@bohmer.net>
Remy Bohmereec38a12008-06-03 15:26:25 +020035 - Fixed the driver to work with DM9000A.
36 (check on ISR receive status bit before reading the
37 FIFO as described in DM9000 programming guide and
38 application notes)
Remy Bohmer5f63bf42008-06-03 15:26:21 +020039 - Added autodetect of databus width.
Remy Bohmerf4329dc2008-06-03 15:26:22 +020040 - Made debug code compile again.
Remy Bohmer16cb2642008-06-03 15:26:23 +020041 - Adapt eth_send such that it matches the DM9000*
42 application notes. Needed to make it work properly
43 for DM9000A.
Remy Bohmer2f13d2c2008-06-03 15:26:24 +020044 - Adapted reset procedure to match DM9000 application
45 notes (i.e. double reset)
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020046 - some minor code cleanups
Remy Bohmer5f63bf42008-06-03 15:26:21 +020047 These changes are tested with DM9000{A,EP,E} together
Remy Bohmercd9a36c2009-05-03 12:11:40 +020048 with a 200MHz Atmel AT91SAM9261 core
wdenk7ac16102004-08-01 22:48:16 +000049
Andrew Dyera62f5d42008-08-26 17:03:38 -050050TODO: external MII is not functional, only internal at the moment.
wdenk7ac16102004-08-01 22:48:16 +000051*/
52
53#include <common.h>
54#include <command.h>
55#include <net.h>
56#include <asm/io.h>
Remy Bohmercd9a36c2009-05-03 12:11:40 +020057#include <dm9000.h>
wdenk7ac16102004-08-01 22:48:16 +000058
wdenk7ac16102004-08-01 22:48:16 +000059#include "dm9000x.h"
60
61/* Board/System/Debug information/definition ---------------- */
62
wdenk7ac16102004-08-01 22:48:16 +000063/* #define CONFIG_DM9000_DEBUG */
64
65#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020066#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
67#define DM9000_DMP_PACKET(func,packet,length) \
68 do { \
69 int i; \
Thomas Weberc1ff5292009-12-09 09:38:04 +010070 printf("%s: length: %d\n", func, length); \
Remy Bohmerf4329dc2008-06-03 15:26:22 +020071 for (i = 0; i < length; i++) { \
72 if (i % 8 == 0) \
73 printf("\n%s: %02x: ", func, i); \
74 printf("%02x ", ((unsigned char *) packet)[i]); \
75 } printf("\n"); \
76 } while(0)
77#else
wdenk7ac16102004-08-01 22:48:16 +000078#define DM9000_DBG(fmt,args...)
Remy Bohmerf4329dc2008-06-03 15:26:22 +020079#define DM9000_DMP_PACKET(func,packet,length)
80#endif
81
wdenk7ac16102004-08-01 22:48:16 +000082/* Structure/enum declaration ------------------------------- */
83typedef struct board_info {
84 u32 runt_length_counter; /* counter: RX length < 64byte */
85 u32 long_length_counter; /* counter: RX length > 1514byte */
86 u32 reset_counter; /* counter: RESET */
87 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
88 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
89 u16 tx_pkt_cnt;
90 u16 queue_start_addr;
91 u16 dbug_cnt;
92 u8 phy_addr;
93 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +000094 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +020095 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +020096 void (*inblk)(void *data_ptr, int count);
97 void (*rx_status)(u16 *RxStatus, u16 *RxLen);
Remy Bohmer7eefd922009-05-02 21:49:18 +020098 struct eth_device netdev;
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020099} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200100static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000101
Remy Bohmer7eefd922009-05-02 21:49:18 +0200102
wdenk7ac16102004-08-01 22:48:16 +0000103/* function declaration ------------------------------------- */
wdenk7ac16102004-08-01 22:48:16 +0000104static int dm9000_probe(void);
Andy Fleming0d2df962011-03-22 22:49:13 -0500105static u16 dm9000_phy_read(int);
106static void dm9000_phy_write(int, u16);
wdenk7ac16102004-08-01 22:48:16 +0000107static u8 DM9000_ior(int);
108static void DM9000_iow(int reg, u8 value);
109
110/* DM9000 network board routine ---------------------------- */
Jason Jinc74c4362011-08-25 15:46:43 +0800111#ifndef CONFIG_DM9000_BYTE_SWAPPED
Mike Frysinger6f6ce112010-07-05 02:29:21 -0400112#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
113#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
114#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
115#define DM9000_inb(r) readb((volatile u8 *)(r))
116#define DM9000_inw(r) readw((volatile u16 *)(r))
117#define DM9000_inl(r) readl((volatile u32 *)(r))
Jason Jinc74c4362011-08-25 15:46:43 +0800118#else
119#define DM9000_outb(d, r) __raw_writeb(d, r)
120#define DM9000_outw(d, r) __raw_writew(d, r)
121#define DM9000_outl(d, r) __raw_writel(d, r)
122#define DM9000_inb(r) __raw_readb(r)
123#define DM9000_inw(r) __raw_readw(r)
124#define DM9000_inl(r) __raw_readl(r)
125#endif
wdenk7ac16102004-08-01 22:48:16 +0000126
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;
287
Remy Bohmer7eefd922009-05-02 21:49:18 +0200288 DM9000_DBG("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000289
290 /* RESET device */
291 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500292
293 if (dm9000_probe() < 0)
294 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000295
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200296 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
297 io_mode = DM9000_ior(DM9000_ISR) >> 6;
298
299 switch (io_mode) {
300 case 0x0: /* 16-bit mode */
301 printf("DM9000: running in 16 bit mode\n");
302 db->outblk = dm9000_outblk_16bit;
303 db->inblk = dm9000_inblk_16bit;
304 db->rx_status = dm9000_rx_status_16bit;
305 break;
306 case 0x01: /* 32-bit mode */
307 printf("DM9000: running in 32 bit mode\n");
308 db->outblk = dm9000_outblk_32bit;
309 db->inblk = dm9000_inblk_32bit;
310 db->rx_status = dm9000_rx_status_32bit;
311 break;
312 case 0x02: /* 8 bit mode */
313 printf("DM9000: running in 8 bit mode\n");
314 db->outblk = dm9000_outblk_8bit;
315 db->inblk = dm9000_inblk_8bit;
316 db->rx_status = dm9000_rx_status_8bit;
317 break;
318 default:
319 /* Assume 8 bit mode, will probably not work anyway */
320 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
321 db->outblk = dm9000_outblk_8bit;
322 db->inblk = dm9000_inblk_8bit;
323 db->rx_status = dm9000_rx_status_8bit;
324 break;
325 }
326
Andrew Dyera62f5d42008-08-26 17:03:38 -0500327 /* Program operating register, only internal phy supported */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200328 DM9000_iow(DM9000_NCR, 0x0);
329 /* TX Polling clear */
330 DM9000_iow(DM9000_TCR, 0);
331 /* Less 3Kb, 200us */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500332 DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200333 /* Flow Control : High/Low Water */
334 DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
335 /* SH FIXME: This looks strange! Flow Control */
336 DM9000_iow(DM9000_FCR, 0x0);
337 /* Special Mode */
338 DM9000_iow(DM9000_SMCR, 0);
339 /* clear TX status */
340 DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
341 /* Clear interrupt status */
Andrew Dyera62f5d42008-08-26 17:03:38 -0500342 DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000343
Ben Warren8707f622009-10-21 21:53:39 -0700344 printf("MAC: %pM\n", dev->enetaddr);
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500345 if (!is_valid_ethaddr(dev->enetaddr)) {
Andrew Ruder1c377d12013-10-22 19:09:02 -0500346#ifdef CONFIG_RANDOM_MACADDR
347 printf("Bad MAC address (uninitialized EEPROM?), randomizing\n");
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500348 net_random_ethaddr(dev->enetaddr);
Andrew Ruder1c377d12013-10-22 19:09:02 -0500349 printf("MAC: %pM\n", dev->enetaddr);
350#else
351 printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
352#endif
353 }
Andrew Dyera62f5d42008-08-26 17:03:38 -0500354
355 /* fill device MAC address registers */
356 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Ben Warren8707f622009-10-21 21:53:39 -0700357 DM9000_iow(oft, dev->enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000358 for (i = 0, oft = 0x16; i < 8; i++, oft++)
359 DM9000_iow(oft, 0xff);
360
361 /* read back mac, just to be sure */
362 for (i = 0, oft = 0x10; i < 6; i++, oft++)
363 DM9000_DBG("%02x:", DM9000_ior(oft));
364 DM9000_DBG("\n");
365
366 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200367 /* RX enable */
368 DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
369 /* Enable TX/RX interrupt mask */
370 DM9000_iow(DM9000_IMR, IMR_PAR);
371
wdenk7ac16102004-08-01 22:48:16 +0000372 i = 0;
Andy Fleming0d2df962011-03-22 22:49:13 -0500373 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk7ac16102004-08-01 22:48:16 +0000374 udelay(1000);
375 i++;
376 if (i == 10000) {
377 printf("could not establish link\n");
378 return 0;
379 }
380 }
381
382 /* see what we've got */
Andy Fleming0d2df962011-03-22 22:49:13 -0500383 lnk = dm9000_phy_read(17) >> 12;
wdenk7ac16102004-08-01 22:48:16 +0000384 printf("operating at ");
385 switch (lnk) {
386 case 1:
387 printf("10M half duplex ");
388 break;
389 case 2:
390 printf("10M full duplex ");
391 break;
392 case 4:
393 printf("100M half duplex ");
394 break;
395 case 8:
396 printf("100M full duplex ");
397 break;
398 default:
399 printf("unknown: %d ", lnk);
400 break;
401 }
402 printf("mode\n");
403 return 0;
404}
405
406/*
407 Hardware start transmission.
408 Send a packet to media from the upper layer.
409*/
Joe Hershbergerab1ac412012-05-21 14:45:23 +0000410static int dm9000_send(struct eth_device *netdev, void *packet, 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{
Joe Hershberger9f09a362015-04-08 01:41:06 -0500467 u8 rxbyte;
468 u8 *rdptr = (u8 *)net_rx_packets[0];
wdenk7ac16102004-08-01 22:48:16 +0000469 u16 RxStatus, RxLen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200470 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000471
Remy Bohmereec38a12008-06-03 15:26:25 +0200472 /* Check packet ready or not, we must check
473 the ISR status first for DM9000A */
474 if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000475 return 0;
476
Remy Bohmereec38a12008-06-03 15:26:25 +0200477 DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000478
Remy Bohmereec38a12008-06-03 15:26:25 +0200479 /* There is _at least_ 1 package in the fifo, read them all */
480 for (;;) {
481 DM9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000482
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200483 /* Get most updated data,
484 only look at bits 0:1, See application notes DM9000 */
485 rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000486
Remy Bohmereec38a12008-06-03 15:26:25 +0200487 /* Status check: this byte must be 0 or 1 */
488 if (rxbyte > DM9000_PKT_RDY) {
489 DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
490 DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
491 printf("DM9000 error: status check fail: 0x%x\n",
492 rxbyte);
493 return 0;
494 }
wdenk7ac16102004-08-01 22:48:16 +0000495
Remy Bohmereec38a12008-06-03 15:26:25 +0200496 if (rxbyte != DM9000_PKT_RDY)
497 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000498
Remy Bohmereec38a12008-06-03 15:26:25 +0200499 DM9000_DBG("receiving packet\n");
500
501 /* A packet ready now & Get status/length */
502 (db->rx_status)(&RxStatus, &RxLen);
wdenk7ac16102004-08-01 22:48:16 +0000503
Remy Bohmereec38a12008-06-03 15:26:25 +0200504 DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
505
506 /* Move data from DM9000 */
507 /* Read received packet from RX SRAM */
508 (db->inblk)(rdptr, RxLen);
509
510 if ((RxStatus & 0xbf00) || (RxLen < 0x40)
511 || (RxLen > DM9000_PKT_MAX)) {
512 if (RxStatus & 0x100) {
513 printf("rx fifo error\n");
514 }
515 if (RxStatus & 0x200) {
516 printf("rx crc error\n");
517 }
518 if (RxStatus & 0x8000) {
519 printf("rx length error\n");
520 }
521 if (RxLen > DM9000_PKT_MAX) {
522 printf("rx length too big\n");
523 dm9000_reset();
524 }
525 } else {
Remy Bohmer7eefd922009-05-02 21:49:18 +0200526 DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200527
528 DM9000_DBG("passing packet to upper layer\n");
Joe Hershberger9f09a362015-04-08 01:41:06 -0500529 net_process_received_packet(net_rx_packets[0], RxLen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200530 }
wdenk7ac16102004-08-01 22:48:16 +0000531 }
532 return 0;
533}
534
535/*
536 Read a word data from SROM
537*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200538#if !defined(CONFIG_DM9000_NO_SROM)
539void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000540{
541 DM9000_iow(DM9000_EPAR, offset);
542 DM9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200543 udelay(8000);
wdenk7ac16102004-08-01 22:48:16 +0000544 DM9000_iow(DM9000_EPCR, 0x0);
David Brownell71907572009-04-16 23:15:15 -0700545 to[0] = DM9000_ior(DM9000_EPDRL);
546 to[1] = DM9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000547}
548
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200549void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200550{
551 DM9000_iow(DM9000_EPAR, offset);
552 DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
553 DM9000_iow(DM9000_EPDRL, (val & 0xff));
554 DM9000_iow(DM9000_EPCR, 0x12);
555 udelay(8000);
556 DM9000_iow(DM9000_EPCR, 0);
557}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200558#endif
Ben Warren8707f622009-10-21 21:53:39 -0700559
560static void dm9000_get_enetaddr(struct eth_device *dev)
561{
562#if !defined(CONFIG_DM9000_NO_SROM)
563 int i;
564 for (i = 0; i < 3; i++)
565 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
566#endif
567}
stefano babic6708a602007-08-30 23:01:49 +0200568
wdenk7ac16102004-08-01 22:48:16 +0000569/*
570 Read a byte from I/O port
571*/
572static u8
573DM9000_ior(int reg)
574{
575 DM9000_outb(reg, DM9000_IO);
576 return DM9000_inb(DM9000_DATA);
577}
578
579/*
580 Write a byte to I/O port
581*/
582static void
583DM9000_iow(int reg, u8 value)
584{
585 DM9000_outb(reg, DM9000_IO);
586 DM9000_outb(value, DM9000_DATA);
587}
588
589/*
590 Read a word from phyxcer
591*/
592static u16
Andy Fleming0d2df962011-03-22 22:49:13 -0500593dm9000_phy_read(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000594{
595 u16 val;
596
597 /* Fill the phyxcer register into REG_0C */
598 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
599 DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200600 udelay(100); /* Wait read complete */
wdenk7ac16102004-08-01 22:48:16 +0000601 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
602 val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
603
604 /* The read data keeps on REG_0D & REG_0E */
Andy Fleming0d2df962011-03-22 22:49:13 -0500605 DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000606 return val;
607}
608
609/*
610 Write a word to phyxcer
611*/
612static void
Andy Fleming0d2df962011-03-22 22:49:13 -0500613dm9000_phy_write(int reg, u16 value)
wdenk7ac16102004-08-01 22:48:16 +0000614{
615
616 /* Fill the phyxcer register into REG_0C */
617 DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
618
619 /* Fill the written data into REG_0D & REG_0E */
620 DM9000_iow(DM9000_EPDRL, (value & 0xff));
621 DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
622 DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200623 udelay(500); /* Wait write complete */
wdenk7ac16102004-08-01 22:48:16 +0000624 DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Andy Fleming0d2df962011-03-22 22:49:13 -0500625 DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000626}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200627
628int dm9000_initialize(bd_t *bis)
629{
630 struct eth_device *dev = &(dm9000_info.netdev);
631
Ben Warren8707f622009-10-21 21:53:39 -0700632 /* Load MAC address from EEPROM */
633 dm9000_get_enetaddr(dev);
634
Remy Bohmer7eefd922009-05-02 21:49:18 +0200635 dev->init = dm9000_init;
636 dev->halt = dm9000_halt;
637 dev->send = dm9000_send;
638 dev->recv = dm9000_rx;
639 sprintf(dev->name, "dm9000");
640
641 eth_register(dev);
642
643 return 0;
644}