blob: ec92485cbe78794423aff5e71ae623369f588a97 [file] [log] [blame]
wdenkf8062712005-01-09 23:16:25 +00001/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +02002Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
wdenkf8062712005-01-09 23:16:25 +00003
4Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
5eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
6are GPL, so this is, of course, GPL.
7
wdenkf8062712005-01-09 23:16:25 +00008==========================================================================
9
10dev/if_dp83902a.c
11
12Ethernet device driver for NS DP83902a ethernet controller
13
14==========================================================================
15####ECOSGPLCOPYRIGHTBEGIN####
16-------------------------------------------
17This file is part of eCos, the Embedded Configurable Operating System.
18Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
19
20eCos is free software; you can redistribute it and/or modify it under
21the terms of the GNU General Public License as published by the Free
22Software Foundation; either version 2 or (at your option) any later version.
23
24eCos is distributed in the hope that it will be useful, but WITHOUT ANY
25WARRANTY; without even the implied warranty of MERCHANTABILITY or
26FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27for more details.
28
29You should have received a copy of the GNU General Public License along
30with eCos; if not, write to the Free Software Foundation, Inc.,
3159 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32
33As a special exception, if other files instantiate templates or use macros
34or inline functions from this file, or you compile this file and link it
35with other works to produce a work based on this file, this file does not
36by itself cause the resulting work to be covered by the GNU General Public
37License. However the source code for this file must still be made available
38in accordance with section (3) of the GNU General Public License.
39
40This exception does not invalidate any other reasons why a work based on
41this file might be covered by the GNU General Public License.
42
43Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
44at http://sources.redhat.com/ecos/ecos-license/
45-------------------------------------------
46####ECOSGPLCOPYRIGHTEND####
47####BSDCOPYRIGHTBEGIN####
48
49-------------------------------------------
50
51Portions of this software may have been derived from OpenBSD or other sources,
52and are covered by the appropriate copyright disclaimers included herein.
53
54-------------------------------------------
55
56####BSDCOPYRIGHTEND####
57==========================================================================
58#####DESCRIPTIONBEGIN####
59
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +020060Author(s): gthomas
61Contributors: gthomas, jskov, rsandifo
62Date: 2001-06-13
wdenkf8062712005-01-09 23:16:25 +000063Purpose:
64Description:
65
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +020066FIXME: Will fail if pinged with large packets (1520 bytes)
wdenkf8062712005-01-09 23:16:25 +000067Add promisc config
68Add SNMP
69
70####DESCRIPTIONEND####
71
wdenkf8062712005-01-09 23:16:25 +000072==========================================================================
wdenkf8062712005-01-09 23:16:25 +000073*/
74
75#include <common.h>
76#include <command.h>
77#include <net.h>
78#include <malloc.h>
79
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +020080#define mdelay(n) udelay((n)*1000)
wdenkf8062712005-01-09 23:16:25 +000081/* forward definition of function used for the uboot interface */
82void uboot_push_packet_len(int len);
83void uboot_push_tx_done(int key, int val);
84
wdenkf8062712005-01-09 23:16:25 +000085/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +020086 * Debugging details
87 *
88 * Set to perms of:
89 * 0 disables all debug output
90 * 1 for process debug output
91 * 2 for added data IO output: get_reg, put_reg
92 * 4 for packet allocation/free output
93 * 8 for only startup status, so we can tell we're installed OK
94 */
95#if 0
96#define DEBUG 0xf
97#else
wdenkf8062712005-01-09 23:16:25 +000098#define DEBUG 0
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +020099#endif
wdenkf8062712005-01-09 23:16:25 +0000100
101#if DEBUG & 1
102#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
103#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
goda.yusuke7b603ad2008-03-05 17:08:20 +0900104#define PRINTK(args...) printf(args)
wdenkf8062712005-01-09 23:16:25 +0000105#else
106#define DEBUG_FUNCTION() do {} while(0)
107#define DEBUG_LINE() do {} while(0)
goda.yusuke7b603ad2008-03-05 17:08:20 +0900108#define PRINTK(args...)
wdenkf8062712005-01-09 23:16:25 +0000109#endif
110
goda.yusuke7b603ad2008-03-05 17:08:20 +0900111/* NE2000 base header file */
112#include "ne2000_base.h"
wdenkf8062712005-01-09 23:16:25 +0000113
goda.yusukeeb3def62008-03-05 17:08:33 +0900114#if defined(CONFIG_DRIVER_AX88796L)
115/* AX88796L support */
116#include "ax88796.h"
117#else
goda.yusuke7b603ad2008-03-05 17:08:20 +0900118/* Basic NE2000 chip support */
119#include "ne2000.h"
goda.yusukeeb3def62008-03-05 17:08:33 +0900120#endif
wdenkf8062712005-01-09 23:16:25 +0000121
122static dp83902a_priv_data_t nic; /* just one instance of the card supported */
123
124static bool
125dp83902a_init(void)
126{
127 dp83902a_priv_data_t *dp = &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900128 u8* base;
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200129#if defined(NE2000_BASIC_INIT)
130 int i;
131#endif
wdenkf8062712005-01-09 23:16:25 +0000132
133 DEBUG_FUNCTION();
134
135 base = dp->base;
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200136 if (!base)
137 return false; /* No device found */
wdenkf8062712005-01-09 23:16:25 +0000138
139 DEBUG_LINE();
140
goda.yusuke7b603ad2008-03-05 17:08:20 +0900141#if defined(NE2000_BASIC_INIT)
goda.yusukeeb3def62008-03-05 17:08:33 +0900142 /* AX88796L doesn't need */
wdenkf8062712005-01-09 23:16:25 +0000143 /* Prepare ESA */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200144 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
wdenkf8062712005-01-09 23:16:25 +0000145 /* Use the address from the serial EEPROM */
146 for (i = 0; i < 6; i++)
147 DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200148 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
wdenkf8062712005-01-09 23:16:25 +0000149
150 printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200151 "eeprom",
152 dp->esa[0],
153 dp->esa[1],
154 dp->esa[2],
155 dp->esa[3],
156 dp->esa[4],
157 dp->esa[5] );
wdenkf8062712005-01-09 23:16:25 +0000158
goda.yusuke7b603ad2008-03-05 17:08:20 +0900159#endif /* NE2000_BASIC_INIT */
wdenkf8062712005-01-09 23:16:25 +0000160 return true;
161}
162
163static void
164dp83902a_stop(void)
165{
166 dp83902a_priv_data_t *dp = &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900167 u8 *base = dp->base;
wdenkf8062712005-01-09 23:16:25 +0000168
169 DEBUG_FUNCTION();
170
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200171 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
wdenkf8062712005-01-09 23:16:25 +0000172 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
173 DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
174
175 dp->running = false;
176}
177
178/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200179 * This function is called to "start up" the interface. It may be called
180 * multiple times, even when the hardware is already running. It will be
181 * called whenever something "hardware oriented" changes and should leave
182 * the hardware ready to send/receive packets.
183 */
wdenkf8062712005-01-09 23:16:25 +0000184static void
goda.yusuke7b603ad2008-03-05 17:08:20 +0900185dp83902a_start(u8 * enaddr)
wdenkf8062712005-01-09 23:16:25 +0000186{
187 dp83902a_priv_data_t *dp = &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900188 u8 *base = dp->base;
wdenkf8062712005-01-09 23:16:25 +0000189 int i;
190
191 DEBUG_FUNCTION();
192
193 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
194 DP_OUT(base, DP_DCR, DP_DCR_INIT);
195 DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
196 DP_OUT(base, DP_RBCL, 0);
197 DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
198 DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
199 DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
200 dp->tx1 = dp->tx2 = 0;
201 dp->tx_next = dp->tx_buf1;
202 dp->tx_started = false;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900203 dp->running = true;
wdenkf8062712005-01-09 23:16:25 +0000204 DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200205 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
wdenkf8062712005-01-09 23:16:25 +0000206 DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200207 dp->rx_next = dp->rx_buf_start - 1;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900208 dp->running = true;
wdenkf8062712005-01-09 23:16:25 +0000209 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
210 DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200211 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
212 DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
goda.yusuke7b603ad2008-03-05 17:08:20 +0900213 dp->running = true;
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200214 for (i = 0; i < ETHER_ADDR_LEN; i++) {
goda.yusuke7b603ad2008-03-05 17:08:20 +0900215 /* FIXME */
Wolfgang Denk840a0d72008-03-26 00:52:10 +0100216 /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
217 * 0x1400)) = enaddr[i];*/
wdenkf8062712005-01-09 23:16:25 +0000218 DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
219 }
220 /* Enable and start device */
221 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
222 DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200223 DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
wdenkf8062712005-01-09 23:16:25 +0000224 dp->running = true;
225}
226
227/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200228 * This routine is called to start the transmitter. It is split out from the
229 * data handling routine so it may be called either when data becomes first
230 * available or when an Tx interrupt occurs
231 */
wdenkf8062712005-01-09 23:16:25 +0000232
233static void
234dp83902a_start_xmit(int start_page, int len)
235{
236 dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900237 u8 *base = dp->base;
wdenkf8062712005-01-09 23:16:25 +0000238
239 DEBUG_FUNCTION();
240
241#if DEBUG & 1
242 printf("Tx pkt %d len %d\n", start_page, len);
243 if (dp->tx_started)
244 printf("TX already started?!?\n");
245#endif
246
247 DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
248 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
249 DP_OUT(base, DP_TBCL, len & 0xFF);
250 DP_OUT(base, DP_TBCH, len >> 8);
251 DP_OUT(base, DP_TPSR, start_page);
252 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
253
254 dp->tx_started = true;
255}
256
257/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200258 * This routine is called to send data to the hardware. It is known a-priori
259 * that there is free buffer space (dp->tx_next).
260 */
wdenkf8062712005-01-09 23:16:25 +0000261static void
goda.yusuke7b603ad2008-03-05 17:08:20 +0900262dp83902a_send(u8 *data, int total_len, u32 key)
wdenkf8062712005-01-09 23:16:25 +0000263{
264 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900265 u8 *base = dp->base;
wdenkf8062712005-01-09 23:16:25 +0000266 int len, start_page, pkt_len, i, isr;
267#if DEBUG & 4
268 int dx;
269#endif
270
271 DEBUG_FUNCTION();
272
273 len = pkt_len = total_len;
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200274 if (pkt_len < IEEE_8023_MIN_FRAME)
275 pkt_len = IEEE_8023_MIN_FRAME;
wdenkf8062712005-01-09 23:16:25 +0000276
277 start_page = dp->tx_next;
278 if (dp->tx_next == dp->tx_buf1) {
279 dp->tx1 = start_page;
280 dp->tx1_len = pkt_len;
281 dp->tx1_key = key;
282 dp->tx_next = dp->tx_buf2;
283 } else {
284 dp->tx2 = start_page;
285 dp->tx2_len = pkt_len;
286 dp->tx2_key = key;
287 dp->tx_next = dp->tx_buf1;
288 }
289
290#if DEBUG & 5
291 printf("TX prep page %d len %d\n", start_page, pkt_len);
292#endif
293
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200294 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
wdenkf8062712005-01-09 23:16:25 +0000295 {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200296 /*
297 * Dummy read. The manual sez something slightly different,
298 * but the code is extended a bit to do what Hitachi's monitor
299 * does (i.e., also read data).
300 */
wdenkf8062712005-01-09 23:16:25 +0000301
goda.yusuke7b603ad2008-03-05 17:08:20 +0900302 u16 tmp;
wdenkf8062712005-01-09 23:16:25 +0000303 int len = 1;
304
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200305 DP_OUT(base, DP_RSAL, 0x100 - len);
306 DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
wdenkf8062712005-01-09 23:16:25 +0000307 DP_OUT(base, DP_RBCL, len);
308 DP_OUT(base, DP_RBCH, 0);
309 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
310 DP_IN_DATA(dp->data, tmp);
311 }
312
313#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200314 /*
315 * Stall for a bit before continuing to work around random data
316 * corruption problems on some platforms.
317 */
wdenkf8062712005-01-09 23:16:25 +0000318 CYGACC_CALL_IF_DELAY_US(1);
319#endif
320
321 /* Send data to device buffer(s) */
322 DP_OUT(base, DP_RSAL, 0);
323 DP_OUT(base, DP_RSAH, start_page);
324 DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
325 DP_OUT(base, DP_RBCH, pkt_len >> 8);
326 DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
327
328 /* Put data into buffer */
329#if DEBUG & 4
goda.yusuke7b603ad2008-03-05 17:08:20 +0900330 printf(" sg buf %08lx len %08x\n ", (u32)data, len);
wdenkf8062712005-01-09 23:16:25 +0000331 dx = 0;
332#endif
333 while (len > 0) {
334#if DEBUG & 4
335 printf(" %02x", *data);
336 if (0 == (++dx % 16)) printf("\n ");
337#endif
goda.yusuke7b603ad2008-03-05 17:08:20 +0900338
wdenkf8062712005-01-09 23:16:25 +0000339 DP_OUT_DATA(dp->data, *data++);
340 len--;
341 }
342#if DEBUG & 4
343 printf("\n");
344#endif
345 if (total_len < pkt_len) {
346#if DEBUG & 4
347 printf(" + %d bytes of padding\n", pkt_len - total_len);
348#endif
349 /* Padding to 802.3 length was required */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200350 for (i = total_len; i < pkt_len;) {
wdenkf8062712005-01-09 23:16:25 +0000351 i++;
352 DP_OUT_DATA(dp->data, 0);
353 }
354 }
355
356#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200357 /*
358 * After last data write, delay for a bit before accessing the
359 * device again, or we may get random data corruption in the last
360 * datum (on some platforms).
361 */
wdenkf8062712005-01-09 23:16:25 +0000362 CYGACC_CALL_IF_DELAY_US(1);
363#endif
364
365 /* Wait for DMA to complete */
366 do {
367 DP_IN(base, DP_ISR, isr);
368 } while ((isr & DP_ISR_RDC) == 0);
goda.yusuke7b603ad2008-03-05 17:08:20 +0900369
wdenkf8062712005-01-09 23:16:25 +0000370 /* Then disable DMA */
371 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
372
373 /* Start transmit if not already going */
374 if (!dp->tx_started) {
375 if (start_page == dp->tx1) {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200376 dp->tx_int = 1; /* Expecting interrupt from BUF1 */
wdenkf8062712005-01-09 23:16:25 +0000377 } else {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200378 dp->tx_int = 2; /* Expecting interrupt from BUF2 */
wdenkf8062712005-01-09 23:16:25 +0000379 }
380 dp83902a_start_xmit(start_page, pkt_len);
381 }
382}
383
384/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200385 * This function is called when a packet has been received. It's job is
386 * to prepare to unload the packet from the hardware. Once the length of
387 * the packet is known, the upper layer of the driver can be told. When
388 * the upper layer is ready to unload the packet, the internal function
389 * 'dp83902a_recv' will be called to actually fetch it from the hardware.
390 */
wdenkf8062712005-01-09 23:16:25 +0000391static void
392dp83902a_RxEvent(void)
393{
394 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900395 u8 *base = dp->base;
396 u8 rsr;
397 u8 rcv_hdr[4];
wdenkf8062712005-01-09 23:16:25 +0000398 int i, len, pkt, cur;
399
400 DEBUG_FUNCTION();
401
402 DP_IN(base, DP_RSR, rsr);
403 while (true) {
404 /* Read incoming packet header */
405 DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
406 DP_IN(base, DP_P1_CURP, cur);
407 DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
408 DP_IN(base, DP_BNDRY, pkt);
409
410 pkt += 1;
411 if (pkt == dp->rx_buf_end)
412 pkt = dp->rx_buf_start;
413
414 if (pkt == cur) {
415 break;
416 }
417 DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
418 DP_OUT(base, DP_RBCH, 0);
419 DP_OUT(base, DP_RSAL, 0);
420 DP_OUT(base, DP_RSAH, pkt);
421 if (dp->rx_next == pkt) {
422 if (cur == dp->rx_buf_start)
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200423 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
wdenkf8062712005-01-09 23:16:25 +0000424 else
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200425 DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
wdenkf8062712005-01-09 23:16:25 +0000426 return;
427 }
428 dp->rx_next = pkt;
429 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
430 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
431#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
432 CYGACC_CALL_IF_DELAY_US(10);
433#endif
434
goda.yusuke7b603ad2008-03-05 17:08:20 +0900435 /* read header (get data size)*/
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200436 for (i = 0; i < sizeof(rcv_hdr);) {
wdenkf8062712005-01-09 23:16:25 +0000437 DP_IN_DATA(dp->data, rcv_hdr[i++]);
438 }
439
440#if DEBUG & 5
441 printf("rx hdr %02x %02x %02x %02x\n",
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200442 rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
wdenkf8062712005-01-09 23:16:25 +0000443#endif
444 len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
goda.yusuke7b603ad2008-03-05 17:08:20 +0900445
446 /* data read */
wdenkf8062712005-01-09 23:16:25 +0000447 uboot_push_packet_len(len);
goda.yusuke7b603ad2008-03-05 17:08:20 +0900448
wdenkf8062712005-01-09 23:16:25 +0000449 if (rcv_hdr[1] == dp->rx_buf_start)
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200450 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
wdenkf8062712005-01-09 23:16:25 +0000451 else
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200452 DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
wdenkf8062712005-01-09 23:16:25 +0000453 }
454}
455
456/*
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200457 * This function is called as a result of the "eth_drv_recv()" call above.
458 * It's job is to actually fetch data for a packet from the hardware once
459 * memory buffers have been allocated for the packet. Note that the buffers
460 * may come in pieces, using a scatter-gather list. This allows for more
461 * efficient processing in the upper layers of the stack.
462 */
wdenkf8062712005-01-09 23:16:25 +0000463static void
goda.yusuke7b603ad2008-03-05 17:08:20 +0900464dp83902a_recv(u8 *data, int len)
wdenkf8062712005-01-09 23:16:25 +0000465{
466 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900467 u8 *base = dp->base;
wdenkf8062712005-01-09 23:16:25 +0000468 int i, mlen;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900469 u8 saved_char = 0;
wdenkf8062712005-01-09 23:16:25 +0000470 bool saved;
471#if DEBUG & 4
472 int dx;
473#endif
474
475 DEBUG_FUNCTION();
476
477#if DEBUG & 5
478 printf("Rx packet %d length %d\n", dp->rx_next, len);
479#endif
480
481 /* Read incoming packet data */
482 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
483 DP_OUT(base, DP_RBCL, len & 0xFF);
484 DP_OUT(base, DP_RBCH, len >> 8);
485 DP_OUT(base, DP_RSAL, 4); /* Past header */
486 DP_OUT(base, DP_RSAH, dp->rx_next);
487 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
488 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
489#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
490 CYGACC_CALL_IF_DELAY_US(10);
491#endif
492
493 saved = false;
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200494 for (i = 0; i < 1; i++) {
wdenkf8062712005-01-09 23:16:25 +0000495 if (data) {
496 mlen = len;
497#if DEBUG & 4
goda.yusuke7b603ad2008-03-05 17:08:20 +0900498 printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
wdenkf8062712005-01-09 23:16:25 +0000499 dx = 0;
500#endif
501 while (0 < mlen) {
502 /* Saved byte from previous loop? */
503 if (saved) {
504 *data++ = saved_char;
505 mlen--;
506 saved = false;
507 continue;
508 }
509
510 {
goda.yusuke7b603ad2008-03-05 17:08:20 +0900511 u8 tmp;
wdenkf8062712005-01-09 23:16:25 +0000512 DP_IN_DATA(dp->data, tmp);
513#if DEBUG & 4
514 printf(" %02x", tmp);
515 if (0 == (++dx % 16)) printf("\n ");
516#endif
517 *data++ = tmp;;
518 mlen--;
519 }
520 }
521#if DEBUG & 4
522 printf("\n");
523#endif
524 }
525 }
526}
527
528static void
529dp83902a_TxEvent(void)
530{
531 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900532 u8 *base = dp->base;
533 u8 tsr;
534 u32 key;
wdenkf8062712005-01-09 23:16:25 +0000535
536 DEBUG_FUNCTION();
537
538 DP_IN(base, DP_TSR, tsr);
539 if (dp->tx_int == 1) {
540 key = dp->tx1_key;
541 dp->tx1 = 0;
542 } else {
543 key = dp->tx2_key;
544 dp->tx2 = 0;
545 }
546 /* Start next packet if one is ready */
547 dp->tx_started = false;
548 if (dp->tx1) {
549 dp83902a_start_xmit(dp->tx1, dp->tx1_len);
550 dp->tx_int = 1;
551 } else if (dp->tx2) {
552 dp83902a_start_xmit(dp->tx2, dp->tx2_len);
553 dp->tx_int = 2;
554 } else {
555 dp->tx_int = 0;
556 }
557 /* Tell higher level we sent this packet */
558 uboot_push_tx_done(key, 0);
559}
560
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200561/*
562 * Read the tally counters to clear them. Called in response to a CNT
563 * interrupt.
564 */
wdenkf8062712005-01-09 23:16:25 +0000565static void
566dp83902a_ClearCounters(void)
567{
568 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900569 u8 *base = dp->base;
570 u8 cnt1, cnt2, cnt3;
wdenkf8062712005-01-09 23:16:25 +0000571
572 DP_IN(base, DP_FER, cnt1);
573 DP_IN(base, DP_CER, cnt2);
574 DP_IN(base, DP_MISSED, cnt3);
575 DP_OUT(base, DP_ISR, DP_ISR_CNT);
576}
577
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200578/*
579 * Deal with an overflow condition. This code follows the procedure set
580 * out in section 7.0 of the datasheet.
581 */
wdenkf8062712005-01-09 23:16:25 +0000582static void
583dp83902a_Overflow(void)
584{
585 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900586 u8 *base = dp->base;
587 u8 isr;
wdenkf8062712005-01-09 23:16:25 +0000588
589 /* Issue a stop command and wait 1.6ms for it to complete. */
590 DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
591 CYGACC_CALL_IF_DELAY_US(1600);
592
593 /* Clear the remote byte counter registers. */
594 DP_OUT(base, DP_RBCL, 0);
595 DP_OUT(base, DP_RBCH, 0);
596
597 /* Enter loopback mode while we clear the buffer. */
598 DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
599 DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
600
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200601 /*
602 * Read in as many packets as we can and acknowledge any and receive
603 * interrupts. Since the buffer has overflowed, a receive event of
604 * some kind will have occured.
605 */
wdenkf8062712005-01-09 23:16:25 +0000606 dp83902a_RxEvent();
607 DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
608
609 /* Clear the overflow condition and leave loopback mode. */
610 DP_OUT(base, DP_ISR, DP_ISR_OFLW);
611 DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
612
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200613 /*
614 * If a transmit command was issued, but no transmit event has occured,
615 * restart it here.
616 */
wdenkf8062712005-01-09 23:16:25 +0000617 DP_IN(base, DP_ISR, isr);
618 if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
619 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
620 }
621}
622
623static void
624dp83902a_poll(void)
625{
626 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900627 u8 *base = dp->base;
628 u8 isr;
wdenkf8062712005-01-09 23:16:25 +0000629
630 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
631 DP_IN(base, DP_ISR, isr);
632 while (0 != isr) {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200633 /*
634 * The CNT interrupt triggers when the MSB of one of the error
635 * counters is set. We don't much care about these counters, but
636 * we should read their values to reset them.
637 */
wdenkf8062712005-01-09 23:16:25 +0000638 if (isr & DP_ISR_CNT) {
639 dp83902a_ClearCounters();
640 }
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200641 /*
642 * Check for overflow. It's a special case, since there's a
643 * particular procedure that must be followed to get back into
644 * a running state.a
645 */
wdenkf8062712005-01-09 23:16:25 +0000646 if (isr & DP_ISR_OFLW) {
647 dp83902a_Overflow();
648 } else {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200649 /*
650 * Other kinds of interrupts can be acknowledged simply by
651 * clearing the relevant bits of the ISR. Do that now, then
652 * handle the interrupts we care about.
653 */
654 DP_OUT(base, DP_ISR, isr); /* Clear set bits */
wdenkf8062712005-01-09 23:16:25 +0000655 if (!dp->running) break; /* Is this necessary? */
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200656 /*
657 * Check for tx_started on TX event since these may happen
658 * spuriously it seems.
659 */
wdenkf8062712005-01-09 23:16:25 +0000660 if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
661 dp83902a_TxEvent();
662 }
663 if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
664 dp83902a_RxEvent();
665 }
666 }
667 DP_IN(base, DP_ISR, isr);
668 }
669}
670
671/* find prom (taken from pc_net_cs.c from Linux) */
672
673#include "8390.h"
goda.yusuke7b603ad2008-03-05 17:08:20 +0900674/*
wdenkf8062712005-01-09 23:16:25 +0000675typedef struct hw_info_t {
676 u_int offset;
677 u_char a0, a1, a2;
678 u_int flags;
679} hw_info_t;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900680*/
wdenkf8062712005-01-09 23:16:25 +0000681#define DELAY_OUTPUT 0x01
682#define HAS_MISC_REG 0x02
683#define USE_BIG_BUF 0x04
684#define HAS_IBM_MISC 0x08
685#define IS_DL10019 0x10
686#define IS_DL10022 0x20
687#define HAS_MII 0x40
688#define USE_SHMEM 0x80 /* autodetected */
689
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200690#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */
691#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */
wdenkf8062712005-01-09 23:16:25 +0000692#define MII_PHYID_REV_MASK 0xfffffff0
693#define MII_PHYID_REG1 0x02
694#define MII_PHYID_REG2 0x03
695
696static hw_info_t hw_info[] = {
697 { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
698 { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
699 { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
700 { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200701 DELAY_OUTPUT | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000702 { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
703 { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
704 { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
705 { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
706 { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
707 { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
708 { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200709 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000710 { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
711 { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
712 { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200713 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000714 { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200715 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000716 { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200717 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000718 { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200719 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000720 { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200721 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000722 { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200723 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000724 { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200725 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000726 { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200727 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000728 { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200729 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000730 { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200731 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000732 { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
733 { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
734 { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200735 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000736 { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200737 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000738 { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
739 { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
740 { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
741 { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
742 { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200743 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000744 { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200745 HAS_MISC_REG | HAS_IBM_MISC },
wdenkf8062712005-01-09 23:16:25 +0000746 { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
747 { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
748 { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
749 { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200750 DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
wdenkf8062712005-01-09 23:16:25 +0000751 { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
752 { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
753 { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
754 { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
Vlad Lungu4c113c32007-10-25 16:08:14 +0300755 { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
756 { /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 }
wdenkf8062712005-01-09 23:16:25 +0000757};
758
759#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
760
wdenkf8062712005-01-09 23:16:25 +0000761#define PCNET_CMD 0x00
762#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */
763#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */
764#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */
765
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200766static void pcnet_reset_8390(void)
767{
768 int i, r;
769
Nobuhiro Iwamatsu63eecdd2008-06-17 13:07:15 +0900770 PRINTK("nic base is %lx\n", nic.base);
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200771
772 n2k_outb(E8390_NODMA + E8390_PAGE0+E8390_STOP, E8390_CMD);
Nobuhiro Iwamatsu63eecdd2008-06-17 13:07:15 +0900773 PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200774 n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
Nobuhiro Iwamatsu63eecdd2008-06-17 13:07:15 +0900775 PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200776 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
Nobuhiro Iwamatsu63eecdd2008-06-17 13:07:15 +0900777 PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200778 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
779
780 n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
781
782 for (i = 0; i < 100; i++) {
783 if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0)
784 break;
785 PRINTK("got %x in reset\n", r);
786 udelay(100);
787 }
788 n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */
789
790 if (i == 100)
791 printf("pcnet_reset_8390() did not complete.\n");
792} /* pcnet_reset_8390 */
793
794int get_prom(u8* mac_addr) __attribute__ ((weak, alias ("__get_prom")));
795int __get_prom(u8* mac_addr)
796{
797 u8 prom[32];
798 int i, j;
799 struct {
800 u_char value, offset;
801 } program_seq[] = {
802 {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
803 {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
804 {0x00, EN0_RCNTLO}, /* Clear the count regs. */
805 {0x00, EN0_RCNTHI},
806 {0x00, EN0_IMR}, /* Mask completion irq. */
807 {0xFF, EN0_ISR},
808 {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
809 {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
810 {32, EN0_RCNTLO},
811 {0x00, EN0_RCNTHI},
812 {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
813 {0x00, EN0_RSARHI},
814 {E8390_RREAD+E8390_START, E8390_CMD},
815 };
816
817 PRINTK ("trying to get MAC via prom reading\n");
818
819 pcnet_reset_8390 ();
820
821 mdelay (10);
822
823 for (i = 0; i < sizeof (program_seq) / sizeof (program_seq[0]); i++)
824 n2k_outb (program_seq[i].value, program_seq[i].offset);
825
826 PRINTK ("PROM:");
827 for (i = 0; i < 32; i++) {
828 prom[i] = n2k_inb (PCNET_DATAPORT);
829 PRINTK (" %02x", prom[i]);
830 }
831 PRINTK ("\n");
832 for (i = 0; i < NR_INFO; i++) {
833 if ((prom[0] == hw_info[i].a0) &&
834 (prom[2] == hw_info[i].a1) &&
835 (prom[4] == hw_info[i].a2)) {
836 PRINTK ("matched board %d\n", i);
837 break;
838 }
839 }
840 if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
841 PRINTK ("on exit i is %d/%ld\n", i, NR_INFO);
842 PRINTK ("MAC address is ");
843 for (j = 0; j < 6; j++) {
844 mac_addr[j] = prom[j << 1];
845 PRINTK ("%02x:", mac_addr[i]);
846 }
847 PRINTK ("\n");
848 return (i < NR_INFO) ? i : 0;
849 }
850 return 0;
851}
852
wdenkf8062712005-01-09 23:16:25 +0000853/* U-boot specific routines */
goda.yusuke7b603ad2008-03-05 17:08:20 +0900854static u8 *pbuf = NULL;
wdenkf8062712005-01-09 23:16:25 +0000855
856static int pkey = -1;
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200857static int initialized = 0;
wdenkf8062712005-01-09 23:16:25 +0000858
859void uboot_push_packet_len(int len) {
Vlad Lungu4c113c32007-10-25 16:08:14 +0300860 PRINTK("pushed len = %d\n", len);
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200861 if (len >= 2000) {
wdenkf8062712005-01-09 23:16:25 +0000862 printf("NE2000: packet too big\n");
863 return;
864 }
Vlad Lungu4c113c32007-10-25 16:08:14 +0300865 dp83902a_recv(&pbuf[0], len);
Wolfgang Denkba930932007-10-21 01:01:17 +0200866
goda.yusuke7b603ad2008-03-05 17:08:20 +0900867 /*Just pass it to the upper layer*/
Vlad Lungu4c113c32007-10-25 16:08:14 +0300868 NetReceive(&pbuf[0], len);
wdenkf8062712005-01-09 23:16:25 +0000869}
870
871void uboot_push_tx_done(int key, int val) {
872 PRINTK("pushed key = %d\n", key);
873 pkey = key;
874}
875
876int eth_init(bd_t *bd) {
Jean-Christophe PLAGNIOL-VILLARDd87c24f2008-04-24 07:57:17 +0200877 int r;
Nobuhiro Iwamatsud1e51492008-06-17 13:07:11 +0900878 u8 dev_addr[6];
wdenkf8062712005-01-09 23:16:25 +0000879 char ethaddr[20];
880
881 PRINTK("### eth_init\n");
882
883 if (!pbuf) {
Vlad Lungu4c113c32007-10-25 16:08:14 +0300884 pbuf = malloc(2000);
wdenkf8062712005-01-09 23:16:25 +0000885 if (!pbuf) {
Vlad Lungu4c113c32007-10-25 16:08:14 +0300886 printf("Cannot allocate rx buffer\n");
wdenkf8062712005-01-09 23:16:25 +0000887 return -1;
888 }
889 }
890
891#ifdef CONFIG_DRIVER_NE2000_CCR
892 {
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200893 vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
wdenkf8062712005-01-09 23:16:25 +0000894
895 PRINTK("CCR before is %x\n", *p);
896 *p = CONFIG_DRIVER_NE2000_VAL;
897 PRINTK("CCR after is %x\n", *p);
898 }
899#endif
900
goda.yusuke7b603ad2008-03-05 17:08:20 +0900901 nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
wdenkf8062712005-01-09 23:16:25 +0000902
goda.yusuke7b603ad2008-03-05 17:08:20 +0900903 r = get_prom(dev_addr);
wdenkf8062712005-01-09 23:16:25 +0000904 if (!r)
905 return -1;
906
907 sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
908 dev_addr[0], dev_addr[1],
909 dev_addr[2], dev_addr[3],
910 dev_addr[4], dev_addr[5]) ;
911 PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
912 setenv ("ethaddr", ethaddr);
913
wdenkf8062712005-01-09 23:16:25 +0000914 nic.data = nic.base + DP_DATA;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900915 nic.tx_buf1 = START_PG;
916 nic.tx_buf2 = START_PG2;
917 nic.rx_buf_start = RX_START;
918 nic.rx_buf_end = RX_END;
wdenkf8062712005-01-09 23:16:25 +0000919
920 if (dp83902a_init() == false)
921 return -1;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900922
wdenkf8062712005-01-09 23:16:25 +0000923 dp83902a_start(dev_addr);
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200924 initialized = 1;
goda.yusuke7b603ad2008-03-05 17:08:20 +0900925
wdenkf8062712005-01-09 23:16:25 +0000926 return 0;
927}
928
929void eth_halt() {
goda.yusuke7b603ad2008-03-05 17:08:20 +0900930
wdenkf8062712005-01-09 23:16:25 +0000931 PRINTK("### eth_halt\n");
Vlad Lungua78b0cd2007-10-04 20:47:10 +0300932 if(initialized)
933 dp83902a_stop();
Jean-Christophe PLAGNIOL-VILLARD8ec5fcb2008-04-24 07:57:16 +0200934 initialized = 0;
wdenkf8062712005-01-09 23:16:25 +0000935}
936
937int eth_rx() {
Marcel Ziswiler00376352007-12-30 03:30:56 +0100938 dp83902a_poll();
939 return 1;
wdenkf8062712005-01-09 23:16:25 +0000940}
941
942int eth_send(volatile void *packet, int length) {
943 int tmo;
944
945 PRINTK("### eth_send\n");
946
947 pkey = -1;
948
goda.yusuke7b603ad2008-03-05 17:08:20 +0900949 dp83902a_send((u8 *) packet, length, 666);
wdenkf8062712005-01-09 23:16:25 +0000950 tmo = get_timer (0) + TOUT * CFG_HZ;
951 while(1) {
952 dp83902a_poll();
953 if (pkey != -1) {
954 PRINTK("Packet sucesfully sent\n");
955 return 0;
956 }
957 if (get_timer (0) >= tmo) {
958 printf("transmission error (timoeut)\n");
959 return 0;
960 }
961
962 }
963 return 0;
964}