xref: /rk3399_rockchip-uboot/drivers/net/ne2000_base.c (revision 702c85b0e876d587c11acdbb55738ee52acd54f4)
1*702c85b0SNobuhiro Iwamatsu /*
2*702c85b0SNobuhiro Iwamatsu Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
3*702c85b0SNobuhiro Iwamatsu 
4*702c85b0SNobuhiro Iwamatsu Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
5*702c85b0SNobuhiro Iwamatsu eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
6*702c85b0SNobuhiro Iwamatsu are GPL, so this is, of course, GPL.
7*702c85b0SNobuhiro Iwamatsu 
8*702c85b0SNobuhiro Iwamatsu ==========================================================================
9*702c85b0SNobuhiro Iwamatsu 
10*702c85b0SNobuhiro Iwamatsu dev/if_dp83902a.c
11*702c85b0SNobuhiro Iwamatsu 
12*702c85b0SNobuhiro Iwamatsu Ethernet device driver for NS DP83902a ethernet controller
13*702c85b0SNobuhiro Iwamatsu 
14*702c85b0SNobuhiro Iwamatsu ==========================================================================
15*702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTBEGIN####
16*702c85b0SNobuhiro Iwamatsu -------------------------------------------
17*702c85b0SNobuhiro Iwamatsu This file is part of eCos, the Embedded Configurable Operating System.
18*702c85b0SNobuhiro Iwamatsu Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
19*702c85b0SNobuhiro Iwamatsu 
20*702c85b0SNobuhiro Iwamatsu eCos is free software; you can redistribute it and/or modify it under
21*702c85b0SNobuhiro Iwamatsu the terms of the GNU General Public License as published by the Free
22*702c85b0SNobuhiro Iwamatsu Software Foundation; either version 2 or (at your option) any later version.
23*702c85b0SNobuhiro Iwamatsu 
24*702c85b0SNobuhiro Iwamatsu eCos is distributed in the hope that it will be useful, but WITHOUT ANY
25*702c85b0SNobuhiro Iwamatsu WARRANTY; without even the implied warranty of MERCHANTABILITY or
26*702c85b0SNobuhiro Iwamatsu FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27*702c85b0SNobuhiro Iwamatsu for more details.
28*702c85b0SNobuhiro Iwamatsu 
29*702c85b0SNobuhiro Iwamatsu You should have received a copy of the GNU General Public License along
30*702c85b0SNobuhiro Iwamatsu with eCos; if not, write to the Free Software Foundation, Inc.,
31*702c85b0SNobuhiro Iwamatsu 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32*702c85b0SNobuhiro Iwamatsu 
33*702c85b0SNobuhiro Iwamatsu As a special exception, if other files instantiate templates or use macros
34*702c85b0SNobuhiro Iwamatsu or inline functions from this file, or you compile this file and link it
35*702c85b0SNobuhiro Iwamatsu with other works to produce a work based on this file, this file does not
36*702c85b0SNobuhiro Iwamatsu by itself cause the resulting work to be covered by the GNU General Public
37*702c85b0SNobuhiro Iwamatsu License. However the source code for this file must still be made available
38*702c85b0SNobuhiro Iwamatsu in accordance with section (3) of the GNU General Public License.
39*702c85b0SNobuhiro Iwamatsu 
40*702c85b0SNobuhiro Iwamatsu This exception does not invalidate any other reasons why a work based on
41*702c85b0SNobuhiro Iwamatsu this file might be covered by the GNU General Public License.
42*702c85b0SNobuhiro Iwamatsu 
43*702c85b0SNobuhiro Iwamatsu Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
44*702c85b0SNobuhiro Iwamatsu at http://sources.redhat.com/ecos/ecos-license/
45*702c85b0SNobuhiro Iwamatsu -------------------------------------------
46*702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTEND####
47*702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTBEGIN####
48*702c85b0SNobuhiro Iwamatsu 
49*702c85b0SNobuhiro Iwamatsu -------------------------------------------
50*702c85b0SNobuhiro Iwamatsu 
51*702c85b0SNobuhiro Iwamatsu Portions of this software may have been derived from OpenBSD or other sources,
52*702c85b0SNobuhiro Iwamatsu and are covered by the appropriate copyright disclaimers included herein.
53*702c85b0SNobuhiro Iwamatsu 
54*702c85b0SNobuhiro Iwamatsu -------------------------------------------
55*702c85b0SNobuhiro Iwamatsu 
56*702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTEND####
57*702c85b0SNobuhiro Iwamatsu ==========================================================================
58*702c85b0SNobuhiro Iwamatsu #####DESCRIPTIONBEGIN####
59*702c85b0SNobuhiro Iwamatsu 
60*702c85b0SNobuhiro Iwamatsu Author(s):	gthomas
61*702c85b0SNobuhiro Iwamatsu Contributors:	gthomas, jskov, rsandifo
62*702c85b0SNobuhiro Iwamatsu Date:		2001-06-13
63*702c85b0SNobuhiro Iwamatsu Purpose:
64*702c85b0SNobuhiro Iwamatsu Description:
65*702c85b0SNobuhiro Iwamatsu 
66*702c85b0SNobuhiro Iwamatsu FIXME:		Will fail if pinged with large packets (1520 bytes)
67*702c85b0SNobuhiro Iwamatsu Add promisc config
68*702c85b0SNobuhiro Iwamatsu Add SNMP
69*702c85b0SNobuhiro Iwamatsu 
70*702c85b0SNobuhiro Iwamatsu ####DESCRIPTIONEND####
71*702c85b0SNobuhiro Iwamatsu 
72*702c85b0SNobuhiro Iwamatsu ==========================================================================
73*702c85b0SNobuhiro Iwamatsu */
74*702c85b0SNobuhiro Iwamatsu 
75*702c85b0SNobuhiro Iwamatsu #include <common.h>
76*702c85b0SNobuhiro Iwamatsu #include <command.h>
77*702c85b0SNobuhiro Iwamatsu #include <net.h>
78*702c85b0SNobuhiro Iwamatsu #include <malloc.h>
79*702c85b0SNobuhiro Iwamatsu 
80*702c85b0SNobuhiro Iwamatsu #define mdelay(n)	udelay((n)*1000)
81*702c85b0SNobuhiro Iwamatsu /* forward definition of function used for the uboot interface */
82*702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len);
83*702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val);
84*702c85b0SNobuhiro Iwamatsu 
85*702c85b0SNobuhiro Iwamatsu /* NE2000 base header file */
86*702c85b0SNobuhiro Iwamatsu #include "ne2000_base.h"
87*702c85b0SNobuhiro Iwamatsu 
88*702c85b0SNobuhiro Iwamatsu #if defined(CONFIG_DRIVER_AX88796L)
89*702c85b0SNobuhiro Iwamatsu /* AX88796L support */
90*702c85b0SNobuhiro Iwamatsu #include "ax88796.h"
91*702c85b0SNobuhiro Iwamatsu #else
92*702c85b0SNobuhiro Iwamatsu /* Basic NE2000 chip support */
93*702c85b0SNobuhiro Iwamatsu #include "ne2000.h"
94*702c85b0SNobuhiro Iwamatsu #endif
95*702c85b0SNobuhiro Iwamatsu 
96*702c85b0SNobuhiro Iwamatsu static dp83902a_priv_data_t nic; /* just one instance of the card supported */
97*702c85b0SNobuhiro Iwamatsu 
98*702c85b0SNobuhiro Iwamatsu static bool
99*702c85b0SNobuhiro Iwamatsu dp83902a_init(void)
100*702c85b0SNobuhiro Iwamatsu {
101*702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
102*702c85b0SNobuhiro Iwamatsu 	u8* base;
103*702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
104*702c85b0SNobuhiro Iwamatsu 	int i;
105*702c85b0SNobuhiro Iwamatsu #endif
106*702c85b0SNobuhiro Iwamatsu 
107*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
108*702c85b0SNobuhiro Iwamatsu 
109*702c85b0SNobuhiro Iwamatsu 	base = dp->base;
110*702c85b0SNobuhiro Iwamatsu 	if (!base)
111*702c85b0SNobuhiro Iwamatsu 		return false;	/* No device found */
112*702c85b0SNobuhiro Iwamatsu 
113*702c85b0SNobuhiro Iwamatsu 	DEBUG_LINE();
114*702c85b0SNobuhiro Iwamatsu 
115*702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
116*702c85b0SNobuhiro Iwamatsu 	/* AX88796L doesn't need */
117*702c85b0SNobuhiro Iwamatsu 	/* Prepare ESA */
118*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);	/* Select page 1 */
119*702c85b0SNobuhiro Iwamatsu 	/* Use the address from the serial EEPROM */
120*702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 6; i++)
121*702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
122*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);	/* Select page 0 */
123*702c85b0SNobuhiro Iwamatsu 
124*702c85b0SNobuhiro Iwamatsu 	printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
125*702c85b0SNobuhiro Iwamatsu 		"eeprom",
126*702c85b0SNobuhiro Iwamatsu 		dp->esa[0],
127*702c85b0SNobuhiro Iwamatsu 		dp->esa[1],
128*702c85b0SNobuhiro Iwamatsu 		dp->esa[2],
129*702c85b0SNobuhiro Iwamatsu 		dp->esa[3],
130*702c85b0SNobuhiro Iwamatsu 		dp->esa[4],
131*702c85b0SNobuhiro Iwamatsu 		dp->esa[5] );
132*702c85b0SNobuhiro Iwamatsu 
133*702c85b0SNobuhiro Iwamatsu #endif	/* NE2000_BASIC_INIT */
134*702c85b0SNobuhiro Iwamatsu 	return true;
135*702c85b0SNobuhiro Iwamatsu }
136*702c85b0SNobuhiro Iwamatsu 
137*702c85b0SNobuhiro Iwamatsu static void
138*702c85b0SNobuhiro Iwamatsu dp83902a_stop(void)
139*702c85b0SNobuhiro Iwamatsu {
140*702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
141*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
142*702c85b0SNobuhiro Iwamatsu 
143*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
144*702c85b0SNobuhiro Iwamatsu 
145*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);	/* Brutal */
146*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
147*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, 0x00);		/* Disable all interrupts */
148*702c85b0SNobuhiro Iwamatsu 
149*702c85b0SNobuhiro Iwamatsu 	dp->running = false;
150*702c85b0SNobuhiro Iwamatsu }
151*702c85b0SNobuhiro Iwamatsu 
152*702c85b0SNobuhiro Iwamatsu /*
153*702c85b0SNobuhiro Iwamatsu  * This function is called to "start up" the interface. It may be called
154*702c85b0SNobuhiro Iwamatsu  * multiple times, even when the hardware is already running. It will be
155*702c85b0SNobuhiro Iwamatsu  * called whenever something "hardware oriented" changes and should leave
156*702c85b0SNobuhiro Iwamatsu  * the hardware ready to send/receive packets.
157*702c85b0SNobuhiro Iwamatsu  */
158*702c85b0SNobuhiro Iwamatsu static void
159*702c85b0SNobuhiro Iwamatsu dp83902a_start(u8 * enaddr)
160*702c85b0SNobuhiro Iwamatsu {
161*702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
162*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
163*702c85b0SNobuhiro Iwamatsu 	int i;
164*702c85b0SNobuhiro Iwamatsu 
165*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
166*702c85b0SNobuhiro Iwamatsu 
167*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
168*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_DCR, DP_DCR_INIT);
169*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);		/* Remote byte count */
170*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
171*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_MON);	/* Accept no packets */
172*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);	/* Transmitter [virtually] off */
173*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, dp->tx_buf1);	/* Transmitter start page */
174*702c85b0SNobuhiro Iwamatsu 	dp->tx1 = dp->tx2 = 0;
175*702c85b0SNobuhiro Iwamatsu 	dp->tx_next = dp->tx_buf1;
176*702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
177*702c85b0SNobuhiro Iwamatsu 	dp->running = true;
178*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
179*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
180*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTOP, dp->rx_buf_end);	/* Receive ring end page */
181*702c85b0SNobuhiro Iwamatsu 	dp->rx_next = dp->rx_buf_start - 1;
182*702c85b0SNobuhiro Iwamatsu 	dp->running = true;
183*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
184*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, DP_IMR_All);	/* Enable all interrupts */
185*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP);	/* Select page 1 */
186*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_P1_CURP, dp->rx_buf_start);	/* Current page - next free page for Rx */
187*702c85b0SNobuhiro Iwamatsu 	dp->running = true;
188*702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
189*702c85b0SNobuhiro Iwamatsu 		/* FIXME */
190*702c85b0SNobuhiro Iwamatsu 		/*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
191*702c85b0SNobuhiro Iwamatsu 		 * 0x1400)) = enaddr[i];*/
192*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
193*702c85b0SNobuhiro Iwamatsu 	}
194*702c85b0SNobuhiro Iwamatsu 	/* Enable and start device */
195*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
196*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
197*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
198*702c85b0SNobuhiro Iwamatsu 	dp->running = true;
199*702c85b0SNobuhiro Iwamatsu }
200*702c85b0SNobuhiro Iwamatsu 
201*702c85b0SNobuhiro Iwamatsu /*
202*702c85b0SNobuhiro Iwamatsu  * This routine is called to start the transmitter. It is split out from the
203*702c85b0SNobuhiro Iwamatsu  * data handling routine so it may be called either when data becomes first
204*702c85b0SNobuhiro Iwamatsu  * available or when an Tx interrupt occurs
205*702c85b0SNobuhiro Iwamatsu  */
206*702c85b0SNobuhiro Iwamatsu 
207*702c85b0SNobuhiro Iwamatsu static void
208*702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(int start_page, int len)
209*702c85b0SNobuhiro Iwamatsu {
210*702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
211*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
212*702c85b0SNobuhiro Iwamatsu 
213*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
214*702c85b0SNobuhiro Iwamatsu 
215*702c85b0SNobuhiro Iwamatsu #if DEBUG & 1
216*702c85b0SNobuhiro Iwamatsu 	printf("Tx pkt %d len %d\n", start_page, len);
217*702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started)
218*702c85b0SNobuhiro Iwamatsu 		printf("TX already started?!?\n");
219*702c85b0SNobuhiro Iwamatsu #endif
220*702c85b0SNobuhiro Iwamatsu 
221*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
222*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
223*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCL, len & 0xFF);
224*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCH, len >> 8);
225*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, start_page);
226*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
227*702c85b0SNobuhiro Iwamatsu 
228*702c85b0SNobuhiro Iwamatsu 	dp->tx_started = true;
229*702c85b0SNobuhiro Iwamatsu }
230*702c85b0SNobuhiro Iwamatsu 
231*702c85b0SNobuhiro Iwamatsu /*
232*702c85b0SNobuhiro Iwamatsu  * This routine is called to send data to the hardware. It is known a-priori
233*702c85b0SNobuhiro Iwamatsu  * that there is free buffer space (dp->tx_next).
234*702c85b0SNobuhiro Iwamatsu  */
235*702c85b0SNobuhiro Iwamatsu static void
236*702c85b0SNobuhiro Iwamatsu dp83902a_send(u8 *data, int total_len, u32 key)
237*702c85b0SNobuhiro Iwamatsu {
238*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
239*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
240*702c85b0SNobuhiro Iwamatsu 	int len, start_page, pkt_len, i, isr;
241*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
242*702c85b0SNobuhiro Iwamatsu 	int dx;
243*702c85b0SNobuhiro Iwamatsu #endif
244*702c85b0SNobuhiro Iwamatsu 
245*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
246*702c85b0SNobuhiro Iwamatsu 
247*702c85b0SNobuhiro Iwamatsu 	len = pkt_len = total_len;
248*702c85b0SNobuhiro Iwamatsu 	if (pkt_len < IEEE_8023_MIN_FRAME)
249*702c85b0SNobuhiro Iwamatsu 		pkt_len = IEEE_8023_MIN_FRAME;
250*702c85b0SNobuhiro Iwamatsu 
251*702c85b0SNobuhiro Iwamatsu 	start_page = dp->tx_next;
252*702c85b0SNobuhiro Iwamatsu 	if (dp->tx_next == dp->tx_buf1) {
253*702c85b0SNobuhiro Iwamatsu 		dp->tx1 = start_page;
254*702c85b0SNobuhiro Iwamatsu 		dp->tx1_len = pkt_len;
255*702c85b0SNobuhiro Iwamatsu 		dp->tx1_key = key;
256*702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf2;
257*702c85b0SNobuhiro Iwamatsu 	} else {
258*702c85b0SNobuhiro Iwamatsu 		dp->tx2 = start_page;
259*702c85b0SNobuhiro Iwamatsu 		dp->tx2_len = pkt_len;
260*702c85b0SNobuhiro Iwamatsu 		dp->tx2_key = key;
261*702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf1;
262*702c85b0SNobuhiro Iwamatsu 	}
263*702c85b0SNobuhiro Iwamatsu 
264*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
265*702c85b0SNobuhiro Iwamatsu 	printf("TX prep page %d len %d\n", start_page, pkt_len);
266*702c85b0SNobuhiro Iwamatsu #endif
267*702c85b0SNobuhiro Iwamatsu 
268*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC);	/* Clear end of DMA */
269*702c85b0SNobuhiro Iwamatsu 	{
270*702c85b0SNobuhiro Iwamatsu 		/*
271*702c85b0SNobuhiro Iwamatsu 		 * Dummy read. The manual sez something slightly different,
272*702c85b0SNobuhiro Iwamatsu 		 * but the code is extended a bit to do what Hitachi's monitor
273*702c85b0SNobuhiro Iwamatsu 		 * does (i.e., also read data).
274*702c85b0SNobuhiro Iwamatsu 		 */
275*702c85b0SNobuhiro Iwamatsu 
276*702c85b0SNobuhiro Iwamatsu 		u16 tmp;
277*702c85b0SNobuhiro Iwamatsu 		int len = 1;
278*702c85b0SNobuhiro Iwamatsu 
279*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0x100 - len);
280*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
281*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, len);
282*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
283*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
284*702c85b0SNobuhiro Iwamatsu 		DP_IN_DATA(dp->data, tmp);
285*702c85b0SNobuhiro Iwamatsu 	}
286*702c85b0SNobuhiro Iwamatsu 
287*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
288*702c85b0SNobuhiro Iwamatsu 	/*
289*702c85b0SNobuhiro Iwamatsu 	 * Stall for a bit before continuing to work around random data
290*702c85b0SNobuhiro Iwamatsu 	 * corruption problems on some platforms.
291*702c85b0SNobuhiro Iwamatsu 	 */
292*702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
293*702c85b0SNobuhiro Iwamatsu #endif
294*702c85b0SNobuhiro Iwamatsu 
295*702c85b0SNobuhiro Iwamatsu 	/* Send data to device buffer(s) */
296*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 0);
297*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, start_page);
298*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
299*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, pkt_len >> 8);
300*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
301*702c85b0SNobuhiro Iwamatsu 
302*702c85b0SNobuhiro Iwamatsu 	/* Put data into buffer */
303*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
304*702c85b0SNobuhiro Iwamatsu 	printf(" sg buf %08lx len %08x\n ", (u32)data, len);
305*702c85b0SNobuhiro Iwamatsu 	dx = 0;
306*702c85b0SNobuhiro Iwamatsu #endif
307*702c85b0SNobuhiro Iwamatsu 	while (len > 0) {
308*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
309*702c85b0SNobuhiro Iwamatsu 		printf(" %02x", *data);
310*702c85b0SNobuhiro Iwamatsu 		if (0 == (++dx % 16)) printf("\n ");
311*702c85b0SNobuhiro Iwamatsu #endif
312*702c85b0SNobuhiro Iwamatsu 
313*702c85b0SNobuhiro Iwamatsu 		DP_OUT_DATA(dp->data, *data++);
314*702c85b0SNobuhiro Iwamatsu 		len--;
315*702c85b0SNobuhiro Iwamatsu 	}
316*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
317*702c85b0SNobuhiro Iwamatsu 	printf("\n");
318*702c85b0SNobuhiro Iwamatsu #endif
319*702c85b0SNobuhiro Iwamatsu 	if (total_len < pkt_len) {
320*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
321*702c85b0SNobuhiro Iwamatsu 		printf("  + %d bytes of padding\n", pkt_len - total_len);
322*702c85b0SNobuhiro Iwamatsu #endif
323*702c85b0SNobuhiro Iwamatsu 		/* Padding to 802.3 length was required */
324*702c85b0SNobuhiro Iwamatsu 		for (i = total_len; i < pkt_len;) {
325*702c85b0SNobuhiro Iwamatsu 			i++;
326*702c85b0SNobuhiro Iwamatsu 			DP_OUT_DATA(dp->data, 0);
327*702c85b0SNobuhiro Iwamatsu 		}
328*702c85b0SNobuhiro Iwamatsu 	}
329*702c85b0SNobuhiro Iwamatsu 
330*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
331*702c85b0SNobuhiro Iwamatsu 	/*
332*702c85b0SNobuhiro Iwamatsu 	 * After last data write, delay for a bit before accessing the
333*702c85b0SNobuhiro Iwamatsu 	 * device again, or we may get random data corruption in the last
334*702c85b0SNobuhiro Iwamatsu 	 * datum (on some platforms).
335*702c85b0SNobuhiro Iwamatsu 	 */
336*702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
337*702c85b0SNobuhiro Iwamatsu #endif
338*702c85b0SNobuhiro Iwamatsu 
339*702c85b0SNobuhiro Iwamatsu 	/* Wait for DMA to complete */
340*702c85b0SNobuhiro Iwamatsu 	do {
341*702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
342*702c85b0SNobuhiro Iwamatsu 	} while ((isr & DP_ISR_RDC) == 0);
343*702c85b0SNobuhiro Iwamatsu 
344*702c85b0SNobuhiro Iwamatsu 	/* Then disable DMA */
345*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
346*702c85b0SNobuhiro Iwamatsu 
347*702c85b0SNobuhiro Iwamatsu 	/* Start transmit if not already going */
348*702c85b0SNobuhiro Iwamatsu 	if (!dp->tx_started) {
349*702c85b0SNobuhiro Iwamatsu 		if (start_page == dp->tx1) {
350*702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 1; /* Expecting interrupt from BUF1 */
351*702c85b0SNobuhiro Iwamatsu 		} else {
352*702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 2; /* Expecting interrupt from BUF2 */
353*702c85b0SNobuhiro Iwamatsu 		}
354*702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(start_page, pkt_len);
355*702c85b0SNobuhiro Iwamatsu 	}
356*702c85b0SNobuhiro Iwamatsu }
357*702c85b0SNobuhiro Iwamatsu 
358*702c85b0SNobuhiro Iwamatsu /*
359*702c85b0SNobuhiro Iwamatsu  * This function is called when a packet has been received. It's job is
360*702c85b0SNobuhiro Iwamatsu  * to prepare to unload the packet from the hardware. Once the length of
361*702c85b0SNobuhiro Iwamatsu  * the packet is known, the upper layer of the driver can be told. When
362*702c85b0SNobuhiro Iwamatsu  * the upper layer is ready to unload the packet, the internal function
363*702c85b0SNobuhiro Iwamatsu  * 'dp83902a_recv' will be called to actually fetch it from the hardware.
364*702c85b0SNobuhiro Iwamatsu  */
365*702c85b0SNobuhiro Iwamatsu static void
366*702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(void)
367*702c85b0SNobuhiro Iwamatsu {
368*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
369*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
370*702c85b0SNobuhiro Iwamatsu 	u8 rsr;
371*702c85b0SNobuhiro Iwamatsu 	u8 rcv_hdr[4];
372*702c85b0SNobuhiro Iwamatsu 	int i, len, pkt, cur;
373*702c85b0SNobuhiro Iwamatsu 
374*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
375*702c85b0SNobuhiro Iwamatsu 
376*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_RSR, rsr);
377*702c85b0SNobuhiro Iwamatsu 	while (true) {
378*702c85b0SNobuhiro Iwamatsu 		/* Read incoming packet header */
379*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
380*702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_CURP, cur);
381*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
382*702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_BNDRY, pkt);
383*702c85b0SNobuhiro Iwamatsu 
384*702c85b0SNobuhiro Iwamatsu 		pkt += 1;
385*702c85b0SNobuhiro Iwamatsu 		if (pkt == dp->rx_buf_end)
386*702c85b0SNobuhiro Iwamatsu 			pkt = dp->rx_buf_start;
387*702c85b0SNobuhiro Iwamatsu 
388*702c85b0SNobuhiro Iwamatsu 		if (pkt == cur) {
389*702c85b0SNobuhiro Iwamatsu 			break;
390*702c85b0SNobuhiro Iwamatsu 		}
391*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
392*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
393*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0);
394*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, pkt);
395*702c85b0SNobuhiro Iwamatsu 		if (dp->rx_next == pkt) {
396*702c85b0SNobuhiro Iwamatsu 			if (cur == dp->rx_buf_start)
397*702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
398*702c85b0SNobuhiro Iwamatsu 			else
399*702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
400*702c85b0SNobuhiro Iwamatsu 			return;
401*702c85b0SNobuhiro Iwamatsu 		}
402*702c85b0SNobuhiro Iwamatsu 		dp->rx_next = pkt;
403*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
404*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
405*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
406*702c85b0SNobuhiro Iwamatsu 		CYGACC_CALL_IF_DELAY_US(10);
407*702c85b0SNobuhiro Iwamatsu #endif
408*702c85b0SNobuhiro Iwamatsu 
409*702c85b0SNobuhiro Iwamatsu 		/* read header (get data size)*/
410*702c85b0SNobuhiro Iwamatsu 		for (i = 0; i < sizeof(rcv_hdr);) {
411*702c85b0SNobuhiro Iwamatsu 			DP_IN_DATA(dp->data, rcv_hdr[i++]);
412*702c85b0SNobuhiro Iwamatsu 		}
413*702c85b0SNobuhiro Iwamatsu 
414*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
415*702c85b0SNobuhiro Iwamatsu 		printf("rx hdr %02x %02x %02x %02x\n",
416*702c85b0SNobuhiro Iwamatsu 			rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
417*702c85b0SNobuhiro Iwamatsu #endif
418*702c85b0SNobuhiro Iwamatsu 		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
419*702c85b0SNobuhiro Iwamatsu 
420*702c85b0SNobuhiro Iwamatsu 		/* data read */
421*702c85b0SNobuhiro Iwamatsu 		uboot_push_packet_len(len);
422*702c85b0SNobuhiro Iwamatsu 
423*702c85b0SNobuhiro Iwamatsu 		if (rcv_hdr[1] == dp->rx_buf_start)
424*702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
425*702c85b0SNobuhiro Iwamatsu 		else
426*702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
427*702c85b0SNobuhiro Iwamatsu 	}
428*702c85b0SNobuhiro Iwamatsu }
429*702c85b0SNobuhiro Iwamatsu 
430*702c85b0SNobuhiro Iwamatsu /*
431*702c85b0SNobuhiro Iwamatsu  * This function is called as a result of the "eth_drv_recv()" call above.
432*702c85b0SNobuhiro Iwamatsu  * It's job is to actually fetch data for a packet from the hardware once
433*702c85b0SNobuhiro Iwamatsu  * memory buffers have been allocated for the packet. Note that the buffers
434*702c85b0SNobuhiro Iwamatsu  * may come in pieces, using a scatter-gather list. This allows for more
435*702c85b0SNobuhiro Iwamatsu  * efficient processing in the upper layers of the stack.
436*702c85b0SNobuhiro Iwamatsu  */
437*702c85b0SNobuhiro Iwamatsu static void
438*702c85b0SNobuhiro Iwamatsu dp83902a_recv(u8 *data, int len)
439*702c85b0SNobuhiro Iwamatsu {
440*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
441*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
442*702c85b0SNobuhiro Iwamatsu 	int i, mlen;
443*702c85b0SNobuhiro Iwamatsu 	u8 saved_char = 0;
444*702c85b0SNobuhiro Iwamatsu 	bool saved;
445*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
446*702c85b0SNobuhiro Iwamatsu 	int dx;
447*702c85b0SNobuhiro Iwamatsu #endif
448*702c85b0SNobuhiro Iwamatsu 
449*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
450*702c85b0SNobuhiro Iwamatsu 
451*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
452*702c85b0SNobuhiro Iwamatsu 	printf("Rx packet %d length %d\n", dp->rx_next, len);
453*702c85b0SNobuhiro Iwamatsu #endif
454*702c85b0SNobuhiro Iwamatsu 
455*702c85b0SNobuhiro Iwamatsu 	/* Read incoming packet data */
456*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
457*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, len & 0xFF);
458*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, len >> 8);
459*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 4);		/* Past header */
460*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, dp->rx_next);
461*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
462*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
463*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
464*702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(10);
465*702c85b0SNobuhiro Iwamatsu #endif
466*702c85b0SNobuhiro Iwamatsu 
467*702c85b0SNobuhiro Iwamatsu 	saved = false;
468*702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 1; i++) {
469*702c85b0SNobuhiro Iwamatsu 		if (data) {
470*702c85b0SNobuhiro Iwamatsu 			mlen = len;
471*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
472*702c85b0SNobuhiro Iwamatsu 			printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
473*702c85b0SNobuhiro Iwamatsu 			dx = 0;
474*702c85b0SNobuhiro Iwamatsu #endif
475*702c85b0SNobuhiro Iwamatsu 			while (0 < mlen) {
476*702c85b0SNobuhiro Iwamatsu 				/* Saved byte from previous loop? */
477*702c85b0SNobuhiro Iwamatsu 				if (saved) {
478*702c85b0SNobuhiro Iwamatsu 					*data++ = saved_char;
479*702c85b0SNobuhiro Iwamatsu 					mlen--;
480*702c85b0SNobuhiro Iwamatsu 					saved = false;
481*702c85b0SNobuhiro Iwamatsu 					continue;
482*702c85b0SNobuhiro Iwamatsu 				}
483*702c85b0SNobuhiro Iwamatsu 
484*702c85b0SNobuhiro Iwamatsu 				{
485*702c85b0SNobuhiro Iwamatsu 					u8 tmp;
486*702c85b0SNobuhiro Iwamatsu 					DP_IN_DATA(dp->data, tmp);
487*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
488*702c85b0SNobuhiro Iwamatsu 					printf(" %02x", tmp);
489*702c85b0SNobuhiro Iwamatsu 					if (0 == (++dx % 16)) printf("\n ");
490*702c85b0SNobuhiro Iwamatsu #endif
491*702c85b0SNobuhiro Iwamatsu 					*data++ = tmp;;
492*702c85b0SNobuhiro Iwamatsu 					mlen--;
493*702c85b0SNobuhiro Iwamatsu 				}
494*702c85b0SNobuhiro Iwamatsu 			}
495*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
496*702c85b0SNobuhiro Iwamatsu 			printf("\n");
497*702c85b0SNobuhiro Iwamatsu #endif
498*702c85b0SNobuhiro Iwamatsu 		}
499*702c85b0SNobuhiro Iwamatsu 	}
500*702c85b0SNobuhiro Iwamatsu }
501*702c85b0SNobuhiro Iwamatsu 
502*702c85b0SNobuhiro Iwamatsu static void
503*702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(void)
504*702c85b0SNobuhiro Iwamatsu {
505*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
506*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
507*702c85b0SNobuhiro Iwamatsu 	u8 tsr;
508*702c85b0SNobuhiro Iwamatsu 	u32 key;
509*702c85b0SNobuhiro Iwamatsu 
510*702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
511*702c85b0SNobuhiro Iwamatsu 
512*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_TSR, tsr);
513*702c85b0SNobuhiro Iwamatsu 	if (dp->tx_int == 1) {
514*702c85b0SNobuhiro Iwamatsu 		key = dp->tx1_key;
515*702c85b0SNobuhiro Iwamatsu 		dp->tx1 = 0;
516*702c85b0SNobuhiro Iwamatsu 	} else {
517*702c85b0SNobuhiro Iwamatsu 		key = dp->tx2_key;
518*702c85b0SNobuhiro Iwamatsu 		dp->tx2 = 0;
519*702c85b0SNobuhiro Iwamatsu 	}
520*702c85b0SNobuhiro Iwamatsu 	/* Start next packet if one is ready */
521*702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
522*702c85b0SNobuhiro Iwamatsu 	if (dp->tx1) {
523*702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx1, dp->tx1_len);
524*702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 1;
525*702c85b0SNobuhiro Iwamatsu 	} else if (dp->tx2) {
526*702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx2, dp->tx2_len);
527*702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 2;
528*702c85b0SNobuhiro Iwamatsu 	} else {
529*702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 0;
530*702c85b0SNobuhiro Iwamatsu 	}
531*702c85b0SNobuhiro Iwamatsu 	/* Tell higher level we sent this packet */
532*702c85b0SNobuhiro Iwamatsu 	uboot_push_tx_done(key, 0);
533*702c85b0SNobuhiro Iwamatsu }
534*702c85b0SNobuhiro Iwamatsu 
535*702c85b0SNobuhiro Iwamatsu /*
536*702c85b0SNobuhiro Iwamatsu  * Read the tally counters to clear them. Called in response to a CNT
537*702c85b0SNobuhiro Iwamatsu  * interrupt.
538*702c85b0SNobuhiro Iwamatsu  */
539*702c85b0SNobuhiro Iwamatsu static void
540*702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(void)
541*702c85b0SNobuhiro Iwamatsu {
542*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
543*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
544*702c85b0SNobuhiro Iwamatsu 	u8 cnt1, cnt2, cnt3;
545*702c85b0SNobuhiro Iwamatsu 
546*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_FER, cnt1);
547*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_CER, cnt2);
548*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_MISSED, cnt3);
549*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_CNT);
550*702c85b0SNobuhiro Iwamatsu }
551*702c85b0SNobuhiro Iwamatsu 
552*702c85b0SNobuhiro Iwamatsu /*
553*702c85b0SNobuhiro Iwamatsu  * Deal with an overflow condition. This code follows the procedure set
554*702c85b0SNobuhiro Iwamatsu  * out in section 7.0 of the datasheet.
555*702c85b0SNobuhiro Iwamatsu  */
556*702c85b0SNobuhiro Iwamatsu static void
557*702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(void)
558*702c85b0SNobuhiro Iwamatsu {
559*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
560*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
561*702c85b0SNobuhiro Iwamatsu 	u8 isr;
562*702c85b0SNobuhiro Iwamatsu 
563*702c85b0SNobuhiro Iwamatsu 	/* Issue a stop command and wait 1.6ms for it to complete. */
564*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
565*702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1600);
566*702c85b0SNobuhiro Iwamatsu 
567*702c85b0SNobuhiro Iwamatsu 	/* Clear the remote byte counter registers. */
568*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
569*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);
570*702c85b0SNobuhiro Iwamatsu 
571*702c85b0SNobuhiro Iwamatsu 	/* Enter loopback mode while we clear the buffer. */
572*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
573*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
574*702c85b0SNobuhiro Iwamatsu 
575*702c85b0SNobuhiro Iwamatsu 	/*
576*702c85b0SNobuhiro Iwamatsu 	 * Read in as many packets as we can and acknowledge any and receive
577*702c85b0SNobuhiro Iwamatsu 	 * interrupts. Since the buffer has overflowed, a receive event of
578*702c85b0SNobuhiro Iwamatsu 	 * some kind will have occured.
579*702c85b0SNobuhiro Iwamatsu 	 */
580*702c85b0SNobuhiro Iwamatsu 	dp83902a_RxEvent();
581*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
582*702c85b0SNobuhiro Iwamatsu 
583*702c85b0SNobuhiro Iwamatsu 	/* Clear the overflow condition and leave loopback mode. */
584*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_OFLW);
585*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
586*702c85b0SNobuhiro Iwamatsu 
587*702c85b0SNobuhiro Iwamatsu 	/*
588*702c85b0SNobuhiro Iwamatsu 	 * If a transmit command was issued, but no transmit event has occured,
589*702c85b0SNobuhiro Iwamatsu 	 * restart it here.
590*702c85b0SNobuhiro Iwamatsu 	 */
591*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
592*702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
593*702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
594*702c85b0SNobuhiro Iwamatsu 	}
595*702c85b0SNobuhiro Iwamatsu }
596*702c85b0SNobuhiro Iwamatsu 
597*702c85b0SNobuhiro Iwamatsu static void
598*702c85b0SNobuhiro Iwamatsu dp83902a_poll(void)
599*702c85b0SNobuhiro Iwamatsu {
600*702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
601*702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
602*702c85b0SNobuhiro Iwamatsu 	u8 isr;
603*702c85b0SNobuhiro Iwamatsu 
604*702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
605*702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
606*702c85b0SNobuhiro Iwamatsu 	while (0 != isr) {
607*702c85b0SNobuhiro Iwamatsu 		/*
608*702c85b0SNobuhiro Iwamatsu 		 * The CNT interrupt triggers when the MSB of one of the error
609*702c85b0SNobuhiro Iwamatsu 		 * counters is set. We don't much care about these counters, but
610*702c85b0SNobuhiro Iwamatsu 		 * we should read their values to reset them.
611*702c85b0SNobuhiro Iwamatsu 		 */
612*702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_CNT) {
613*702c85b0SNobuhiro Iwamatsu 			dp83902a_ClearCounters();
614*702c85b0SNobuhiro Iwamatsu 		}
615*702c85b0SNobuhiro Iwamatsu 		/*
616*702c85b0SNobuhiro Iwamatsu 		 * Check for overflow. It's a special case, since there's a
617*702c85b0SNobuhiro Iwamatsu 		 * particular procedure that must be followed to get back into
618*702c85b0SNobuhiro Iwamatsu 		 * a running state.a
619*702c85b0SNobuhiro Iwamatsu 		 */
620*702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_OFLW) {
621*702c85b0SNobuhiro Iwamatsu 			dp83902a_Overflow();
622*702c85b0SNobuhiro Iwamatsu 		} else {
623*702c85b0SNobuhiro Iwamatsu 			/*
624*702c85b0SNobuhiro Iwamatsu 			 * Other kinds of interrupts can be acknowledged simply by
625*702c85b0SNobuhiro Iwamatsu 			 * clearing the relevant bits of the ISR. Do that now, then
626*702c85b0SNobuhiro Iwamatsu 			 * handle the interrupts we care about.
627*702c85b0SNobuhiro Iwamatsu 			 */
628*702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_ISR, isr);	/* Clear set bits */
629*702c85b0SNobuhiro Iwamatsu 			if (!dp->running) break;	/* Is this necessary? */
630*702c85b0SNobuhiro Iwamatsu 			/*
631*702c85b0SNobuhiro Iwamatsu 			 * Check for tx_started on TX event since these may happen
632*702c85b0SNobuhiro Iwamatsu 			 * spuriously it seems.
633*702c85b0SNobuhiro Iwamatsu 			 */
634*702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
635*702c85b0SNobuhiro Iwamatsu 				dp83902a_TxEvent();
636*702c85b0SNobuhiro Iwamatsu 			}
637*702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
638*702c85b0SNobuhiro Iwamatsu 				dp83902a_RxEvent();
639*702c85b0SNobuhiro Iwamatsu 			}
640*702c85b0SNobuhiro Iwamatsu 		}
641*702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
642*702c85b0SNobuhiro Iwamatsu 	}
643*702c85b0SNobuhiro Iwamatsu }
644*702c85b0SNobuhiro Iwamatsu 
645*702c85b0SNobuhiro Iwamatsu 
646*702c85b0SNobuhiro Iwamatsu /* U-boot specific routines */
647*702c85b0SNobuhiro Iwamatsu static u8 *pbuf = NULL;
648*702c85b0SNobuhiro Iwamatsu 
649*702c85b0SNobuhiro Iwamatsu static int pkey = -1;
650*702c85b0SNobuhiro Iwamatsu static int initialized = 0;
651*702c85b0SNobuhiro Iwamatsu 
652*702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len) {
653*702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed len = %d\n", len);
654*702c85b0SNobuhiro Iwamatsu 	if (len >= 2000) {
655*702c85b0SNobuhiro Iwamatsu 		printf("NE2000: packet too big\n");
656*702c85b0SNobuhiro Iwamatsu 		return;
657*702c85b0SNobuhiro Iwamatsu 	}
658*702c85b0SNobuhiro Iwamatsu 	dp83902a_recv(&pbuf[0], len);
659*702c85b0SNobuhiro Iwamatsu 
660*702c85b0SNobuhiro Iwamatsu 	/*Just pass it to the upper layer*/
661*702c85b0SNobuhiro Iwamatsu 	NetReceive(&pbuf[0], len);
662*702c85b0SNobuhiro Iwamatsu }
663*702c85b0SNobuhiro Iwamatsu 
664*702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val) {
665*702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed key = %d\n", key);
666*702c85b0SNobuhiro Iwamatsu 	pkey = key;
667*702c85b0SNobuhiro Iwamatsu }
668*702c85b0SNobuhiro Iwamatsu 
669*702c85b0SNobuhiro Iwamatsu int eth_init(bd_t *bd) {
670*702c85b0SNobuhiro Iwamatsu 	int r;
671*702c85b0SNobuhiro Iwamatsu 	u8 dev_addr[6];
672*702c85b0SNobuhiro Iwamatsu 	char ethaddr[20];
673*702c85b0SNobuhiro Iwamatsu 
674*702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_init\n");
675*702c85b0SNobuhiro Iwamatsu 
676*702c85b0SNobuhiro Iwamatsu 	if (!pbuf) {
677*702c85b0SNobuhiro Iwamatsu 		pbuf = malloc(2000);
678*702c85b0SNobuhiro Iwamatsu 		if (!pbuf) {
679*702c85b0SNobuhiro Iwamatsu 			printf("Cannot allocate rx buffer\n");
680*702c85b0SNobuhiro Iwamatsu 			return -1;
681*702c85b0SNobuhiro Iwamatsu 		}
682*702c85b0SNobuhiro Iwamatsu 	}
683*702c85b0SNobuhiro Iwamatsu 
684*702c85b0SNobuhiro Iwamatsu #ifdef CONFIG_DRIVER_NE2000_CCR
685*702c85b0SNobuhiro Iwamatsu 	{
686*702c85b0SNobuhiro Iwamatsu 		vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
687*702c85b0SNobuhiro Iwamatsu 
688*702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR before is %x\n", *p);
689*702c85b0SNobuhiro Iwamatsu 		*p = CONFIG_DRIVER_NE2000_VAL;
690*702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR after is %x\n", *p);
691*702c85b0SNobuhiro Iwamatsu 	}
692*702c85b0SNobuhiro Iwamatsu #endif
693*702c85b0SNobuhiro Iwamatsu 
694*702c85b0SNobuhiro Iwamatsu 	nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
695*702c85b0SNobuhiro Iwamatsu 
696*702c85b0SNobuhiro Iwamatsu 	r = get_prom(dev_addr, nic.base);
697*702c85b0SNobuhiro Iwamatsu 	if (!r)
698*702c85b0SNobuhiro Iwamatsu 		return -1;
699*702c85b0SNobuhiro Iwamatsu 
700*702c85b0SNobuhiro Iwamatsu 	sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
701*702c85b0SNobuhiro Iwamatsu 		 dev_addr[0], dev_addr[1],
702*702c85b0SNobuhiro Iwamatsu 		 dev_addr[2], dev_addr[3],
703*702c85b0SNobuhiro Iwamatsu 		 dev_addr[4], dev_addr[5]) ;
704*702c85b0SNobuhiro Iwamatsu 	PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
705*702c85b0SNobuhiro Iwamatsu 	setenv ("ethaddr", ethaddr);
706*702c85b0SNobuhiro Iwamatsu 
707*702c85b0SNobuhiro Iwamatsu 	nic.data = nic.base + DP_DATA;
708*702c85b0SNobuhiro Iwamatsu 	nic.tx_buf1 = START_PG;
709*702c85b0SNobuhiro Iwamatsu 	nic.tx_buf2 = START_PG2;
710*702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_start = RX_START;
711*702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_end = RX_END;
712*702c85b0SNobuhiro Iwamatsu 
713*702c85b0SNobuhiro Iwamatsu 	if (dp83902a_init() == false)
714*702c85b0SNobuhiro Iwamatsu 		return -1;
715*702c85b0SNobuhiro Iwamatsu 
716*702c85b0SNobuhiro Iwamatsu 	dp83902a_start(dev_addr);
717*702c85b0SNobuhiro Iwamatsu 	initialized = 1;
718*702c85b0SNobuhiro Iwamatsu 
719*702c85b0SNobuhiro Iwamatsu 	return 0;
720*702c85b0SNobuhiro Iwamatsu }
721*702c85b0SNobuhiro Iwamatsu 
722*702c85b0SNobuhiro Iwamatsu void eth_halt() {
723*702c85b0SNobuhiro Iwamatsu 
724*702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_halt\n");
725*702c85b0SNobuhiro Iwamatsu 	if(initialized)
726*702c85b0SNobuhiro Iwamatsu 		dp83902a_stop();
727*702c85b0SNobuhiro Iwamatsu 	initialized = 0;
728*702c85b0SNobuhiro Iwamatsu }
729*702c85b0SNobuhiro Iwamatsu 
730*702c85b0SNobuhiro Iwamatsu int eth_rx() {
731*702c85b0SNobuhiro Iwamatsu 	dp83902a_poll();
732*702c85b0SNobuhiro Iwamatsu 	return 1;
733*702c85b0SNobuhiro Iwamatsu }
734*702c85b0SNobuhiro Iwamatsu 
735*702c85b0SNobuhiro Iwamatsu int eth_send(volatile void *packet, int length) {
736*702c85b0SNobuhiro Iwamatsu 	int tmo;
737*702c85b0SNobuhiro Iwamatsu 
738*702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_send\n");
739*702c85b0SNobuhiro Iwamatsu 
740*702c85b0SNobuhiro Iwamatsu 	pkey = -1;
741*702c85b0SNobuhiro Iwamatsu 
742*702c85b0SNobuhiro Iwamatsu 	dp83902a_send((u8 *) packet, length, 666);
743*702c85b0SNobuhiro Iwamatsu 	tmo = get_timer (0) + TOUT * CFG_HZ;
744*702c85b0SNobuhiro Iwamatsu 	while(1) {
745*702c85b0SNobuhiro Iwamatsu 		dp83902a_poll();
746*702c85b0SNobuhiro Iwamatsu 		if (pkey != -1) {
747*702c85b0SNobuhiro Iwamatsu 			PRINTK("Packet sucesfully sent\n");
748*702c85b0SNobuhiro Iwamatsu 			return 0;
749*702c85b0SNobuhiro Iwamatsu 		}
750*702c85b0SNobuhiro Iwamatsu 		if (get_timer (0) >= tmo) {
751*702c85b0SNobuhiro Iwamatsu 			printf("transmission error (timoeut)\n");
752*702c85b0SNobuhiro Iwamatsu 			return 0;
753*702c85b0SNobuhiro Iwamatsu 		}
754*702c85b0SNobuhiro Iwamatsu 
755*702c85b0SNobuhiro Iwamatsu 	}
756*702c85b0SNobuhiro Iwamatsu 	return 0;
757*702c85b0SNobuhiro Iwamatsu }
758