xref: /rk3399_rockchip-uboot/drivers/net/ne2000_base.c (revision 6d0f6bcf337c5261c08fabe12982178c2c489d76)
1702c85b0SNobuhiro Iwamatsu /*
2702c85b0SNobuhiro Iwamatsu Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
3702c85b0SNobuhiro Iwamatsu 
4702c85b0SNobuhiro Iwamatsu Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
5702c85b0SNobuhiro Iwamatsu eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
6702c85b0SNobuhiro Iwamatsu are GPL, so this is, of course, GPL.
7702c85b0SNobuhiro Iwamatsu 
8702c85b0SNobuhiro Iwamatsu ==========================================================================
9702c85b0SNobuhiro Iwamatsu 
10702c85b0SNobuhiro Iwamatsu dev/if_dp83902a.c
11702c85b0SNobuhiro Iwamatsu 
12702c85b0SNobuhiro Iwamatsu Ethernet device driver for NS DP83902a ethernet controller
13702c85b0SNobuhiro Iwamatsu 
14702c85b0SNobuhiro Iwamatsu ==========================================================================
15702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTBEGIN####
16702c85b0SNobuhiro Iwamatsu -------------------------------------------
17702c85b0SNobuhiro Iwamatsu This file is part of eCos, the Embedded Configurable Operating System.
18702c85b0SNobuhiro Iwamatsu Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
19702c85b0SNobuhiro Iwamatsu 
20702c85b0SNobuhiro Iwamatsu eCos is free software; you can redistribute it and/or modify it under
21702c85b0SNobuhiro Iwamatsu the terms of the GNU General Public License as published by the Free
22702c85b0SNobuhiro Iwamatsu Software Foundation; either version 2 or (at your option) any later version.
23702c85b0SNobuhiro Iwamatsu 
24702c85b0SNobuhiro Iwamatsu eCos is distributed in the hope that it will be useful, but WITHOUT ANY
25702c85b0SNobuhiro Iwamatsu WARRANTY; without even the implied warranty of MERCHANTABILITY or
26702c85b0SNobuhiro Iwamatsu FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27702c85b0SNobuhiro Iwamatsu for more details.
28702c85b0SNobuhiro Iwamatsu 
29702c85b0SNobuhiro Iwamatsu You should have received a copy of the GNU General Public License along
30702c85b0SNobuhiro Iwamatsu with eCos; if not, write to the Free Software Foundation, Inc.,
31702c85b0SNobuhiro Iwamatsu 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32702c85b0SNobuhiro Iwamatsu 
33702c85b0SNobuhiro Iwamatsu As a special exception, if other files instantiate templates or use macros
34702c85b0SNobuhiro Iwamatsu or inline functions from this file, or you compile this file and link it
35702c85b0SNobuhiro Iwamatsu with other works to produce a work based on this file, this file does not
36702c85b0SNobuhiro Iwamatsu by itself cause the resulting work to be covered by the GNU General Public
37702c85b0SNobuhiro Iwamatsu License. However the source code for this file must still be made available
38702c85b0SNobuhiro Iwamatsu in accordance with section (3) of the GNU General Public License.
39702c85b0SNobuhiro Iwamatsu 
40702c85b0SNobuhiro Iwamatsu This exception does not invalidate any other reasons why a work based on
41702c85b0SNobuhiro Iwamatsu this file might be covered by the GNU General Public License.
42702c85b0SNobuhiro Iwamatsu 
43702c85b0SNobuhiro Iwamatsu Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
44702c85b0SNobuhiro Iwamatsu at http://sources.redhat.com/ecos/ecos-license/
45702c85b0SNobuhiro Iwamatsu -------------------------------------------
46702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTEND####
47702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTBEGIN####
48702c85b0SNobuhiro Iwamatsu 
49702c85b0SNobuhiro Iwamatsu -------------------------------------------
50702c85b0SNobuhiro Iwamatsu 
51702c85b0SNobuhiro Iwamatsu Portions of this software may have been derived from OpenBSD or other sources,
52702c85b0SNobuhiro Iwamatsu and are covered by the appropriate copyright disclaimers included herein.
53702c85b0SNobuhiro Iwamatsu 
54702c85b0SNobuhiro Iwamatsu -------------------------------------------
55702c85b0SNobuhiro Iwamatsu 
56702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTEND####
57702c85b0SNobuhiro Iwamatsu ==========================================================================
58702c85b0SNobuhiro Iwamatsu #####DESCRIPTIONBEGIN####
59702c85b0SNobuhiro Iwamatsu 
60702c85b0SNobuhiro Iwamatsu Author(s):	gthomas
61702c85b0SNobuhiro Iwamatsu Contributors:	gthomas, jskov, rsandifo
62702c85b0SNobuhiro Iwamatsu Date:		2001-06-13
63702c85b0SNobuhiro Iwamatsu Purpose:
64702c85b0SNobuhiro Iwamatsu Description:
65702c85b0SNobuhiro Iwamatsu 
66702c85b0SNobuhiro Iwamatsu FIXME:		Will fail if pinged with large packets (1520 bytes)
67702c85b0SNobuhiro Iwamatsu Add promisc config
68702c85b0SNobuhiro Iwamatsu Add SNMP
69702c85b0SNobuhiro Iwamatsu 
70702c85b0SNobuhiro Iwamatsu ####DESCRIPTIONEND####
71702c85b0SNobuhiro Iwamatsu 
72702c85b0SNobuhiro Iwamatsu ==========================================================================
73702c85b0SNobuhiro Iwamatsu */
74702c85b0SNobuhiro Iwamatsu 
75702c85b0SNobuhiro Iwamatsu #include <common.h>
76702c85b0SNobuhiro Iwamatsu #include <command.h>
77702c85b0SNobuhiro Iwamatsu #include <net.h>
78702c85b0SNobuhiro Iwamatsu #include <malloc.h>
79702c85b0SNobuhiro Iwamatsu 
80702c85b0SNobuhiro Iwamatsu #define mdelay(n)	udelay((n)*1000)
81702c85b0SNobuhiro Iwamatsu /* forward definition of function used for the uboot interface */
82702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len);
83702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val);
84702c85b0SNobuhiro Iwamatsu 
85702c85b0SNobuhiro Iwamatsu /* NE2000 base header file */
86702c85b0SNobuhiro Iwamatsu #include "ne2000_base.h"
87702c85b0SNobuhiro Iwamatsu 
88702c85b0SNobuhiro Iwamatsu #if defined(CONFIG_DRIVER_AX88796L)
89702c85b0SNobuhiro Iwamatsu /* AX88796L support */
90702c85b0SNobuhiro Iwamatsu #include "ax88796.h"
91702c85b0SNobuhiro Iwamatsu #else
92702c85b0SNobuhiro Iwamatsu /* Basic NE2000 chip support */
93702c85b0SNobuhiro Iwamatsu #include "ne2000.h"
94702c85b0SNobuhiro Iwamatsu #endif
95702c85b0SNobuhiro Iwamatsu 
96702c85b0SNobuhiro Iwamatsu static dp83902a_priv_data_t nic; /* just one instance of the card supported */
97702c85b0SNobuhiro Iwamatsu 
98702c85b0SNobuhiro Iwamatsu static bool
99702c85b0SNobuhiro Iwamatsu dp83902a_init(void)
100702c85b0SNobuhiro Iwamatsu {
101702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
102702c85b0SNobuhiro Iwamatsu 	u8* base;
103702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
104702c85b0SNobuhiro Iwamatsu 	int i;
105702c85b0SNobuhiro Iwamatsu #endif
106702c85b0SNobuhiro Iwamatsu 
107702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
108702c85b0SNobuhiro Iwamatsu 
109702c85b0SNobuhiro Iwamatsu 	base = dp->base;
110702c85b0SNobuhiro Iwamatsu 	if (!base)
111702c85b0SNobuhiro Iwamatsu 		return false;	/* No device found */
112702c85b0SNobuhiro Iwamatsu 
113702c85b0SNobuhiro Iwamatsu 	DEBUG_LINE();
114702c85b0SNobuhiro Iwamatsu 
115702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
116702c85b0SNobuhiro Iwamatsu 	/* AX88796L doesn't need */
117702c85b0SNobuhiro Iwamatsu 	/* Prepare ESA */
118702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);	/* Select page 1 */
119702c85b0SNobuhiro Iwamatsu 	/* Use the address from the serial EEPROM */
120702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 6; i++)
121702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
122702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);	/* Select page 0 */
123702c85b0SNobuhiro Iwamatsu 
124702c85b0SNobuhiro Iwamatsu 	printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
125702c85b0SNobuhiro Iwamatsu 		"eeprom",
126702c85b0SNobuhiro Iwamatsu 		dp->esa[0],
127702c85b0SNobuhiro Iwamatsu 		dp->esa[1],
128702c85b0SNobuhiro Iwamatsu 		dp->esa[2],
129702c85b0SNobuhiro Iwamatsu 		dp->esa[3],
130702c85b0SNobuhiro Iwamatsu 		dp->esa[4],
131702c85b0SNobuhiro Iwamatsu 		dp->esa[5] );
132702c85b0SNobuhiro Iwamatsu 
133702c85b0SNobuhiro Iwamatsu #endif	/* NE2000_BASIC_INIT */
134702c85b0SNobuhiro Iwamatsu 	return true;
135702c85b0SNobuhiro Iwamatsu }
136702c85b0SNobuhiro Iwamatsu 
137702c85b0SNobuhiro Iwamatsu static void
138702c85b0SNobuhiro Iwamatsu dp83902a_stop(void)
139702c85b0SNobuhiro Iwamatsu {
140702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
141702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
142702c85b0SNobuhiro Iwamatsu 
143702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
144702c85b0SNobuhiro Iwamatsu 
145702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);	/* Brutal */
146702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
147702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, 0x00);		/* Disable all interrupts */
148702c85b0SNobuhiro Iwamatsu 
149702c85b0SNobuhiro Iwamatsu 	dp->running = false;
150702c85b0SNobuhiro Iwamatsu }
151702c85b0SNobuhiro Iwamatsu 
152702c85b0SNobuhiro Iwamatsu /*
153702c85b0SNobuhiro Iwamatsu  * This function is called to "start up" the interface. It may be called
154702c85b0SNobuhiro Iwamatsu  * multiple times, even when the hardware is already running. It will be
155702c85b0SNobuhiro Iwamatsu  * called whenever something "hardware oriented" changes and should leave
156702c85b0SNobuhiro Iwamatsu  * the hardware ready to send/receive packets.
157702c85b0SNobuhiro Iwamatsu  */
158702c85b0SNobuhiro Iwamatsu static void
159702c85b0SNobuhiro Iwamatsu dp83902a_start(u8 * enaddr)
160702c85b0SNobuhiro Iwamatsu {
161702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
162702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
163702c85b0SNobuhiro Iwamatsu 	int i;
164702c85b0SNobuhiro Iwamatsu 
165702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
166702c85b0SNobuhiro Iwamatsu 
167702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
168702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_DCR, DP_DCR_INIT);
169702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);		/* Remote byte count */
170702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
171702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_MON);	/* Accept no packets */
172702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);	/* Transmitter [virtually] off */
173702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, dp->tx_buf1);	/* Transmitter start page */
174702c85b0SNobuhiro Iwamatsu 	dp->tx1 = dp->tx2 = 0;
175702c85b0SNobuhiro Iwamatsu 	dp->tx_next = dp->tx_buf1;
176702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
177702c85b0SNobuhiro Iwamatsu 	dp->running = true;
178702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
179702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
180702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTOP, dp->rx_buf_end);	/* Receive ring end page */
181702c85b0SNobuhiro Iwamatsu 	dp->rx_next = dp->rx_buf_start - 1;
182702c85b0SNobuhiro Iwamatsu 	dp->running = true;
183702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
184702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, DP_IMR_All);	/* Enable all interrupts */
185702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP);	/* Select page 1 */
186702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_P1_CURP, dp->rx_buf_start);	/* Current page - next free page for Rx */
187702c85b0SNobuhiro Iwamatsu 	dp->running = true;
188702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
189702c85b0SNobuhiro Iwamatsu 		/* FIXME */
190702c85b0SNobuhiro Iwamatsu 		/*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
191702c85b0SNobuhiro Iwamatsu 		 * 0x1400)) = enaddr[i];*/
192702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
193702c85b0SNobuhiro Iwamatsu 	}
194702c85b0SNobuhiro Iwamatsu 	/* Enable and start device */
195702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
196702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
197702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
198702c85b0SNobuhiro Iwamatsu 	dp->running = true;
199702c85b0SNobuhiro Iwamatsu }
200702c85b0SNobuhiro Iwamatsu 
201702c85b0SNobuhiro Iwamatsu /*
202702c85b0SNobuhiro Iwamatsu  * This routine is called to start the transmitter. It is split out from the
203702c85b0SNobuhiro Iwamatsu  * data handling routine so it may be called either when data becomes first
204702c85b0SNobuhiro Iwamatsu  * available or when an Tx interrupt occurs
205702c85b0SNobuhiro Iwamatsu  */
206702c85b0SNobuhiro Iwamatsu 
207702c85b0SNobuhiro Iwamatsu static void
208702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(int start_page, int len)
209702c85b0SNobuhiro Iwamatsu {
210702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
211702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
212702c85b0SNobuhiro Iwamatsu 
213702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
214702c85b0SNobuhiro Iwamatsu 
215702c85b0SNobuhiro Iwamatsu #if DEBUG & 1
216702c85b0SNobuhiro Iwamatsu 	printf("Tx pkt %d len %d\n", start_page, len);
217702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started)
218702c85b0SNobuhiro Iwamatsu 		printf("TX already started?!?\n");
219702c85b0SNobuhiro Iwamatsu #endif
220702c85b0SNobuhiro Iwamatsu 
221702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
222702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
223702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCL, len & 0xFF);
224702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCH, len >> 8);
225702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, start_page);
226702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
227702c85b0SNobuhiro Iwamatsu 
228702c85b0SNobuhiro Iwamatsu 	dp->tx_started = true;
229702c85b0SNobuhiro Iwamatsu }
230702c85b0SNobuhiro Iwamatsu 
231702c85b0SNobuhiro Iwamatsu /*
232702c85b0SNobuhiro Iwamatsu  * This routine is called to send data to the hardware. It is known a-priori
233702c85b0SNobuhiro Iwamatsu  * that there is free buffer space (dp->tx_next).
234702c85b0SNobuhiro Iwamatsu  */
235702c85b0SNobuhiro Iwamatsu static void
236702c85b0SNobuhiro Iwamatsu dp83902a_send(u8 *data, int total_len, u32 key)
237702c85b0SNobuhiro Iwamatsu {
238702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
239702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
240702c85b0SNobuhiro Iwamatsu 	int len, start_page, pkt_len, i, isr;
241702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
242702c85b0SNobuhiro Iwamatsu 	int dx;
243702c85b0SNobuhiro Iwamatsu #endif
244702c85b0SNobuhiro Iwamatsu 
245702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
246702c85b0SNobuhiro Iwamatsu 
247702c85b0SNobuhiro Iwamatsu 	len = pkt_len = total_len;
248702c85b0SNobuhiro Iwamatsu 	if (pkt_len < IEEE_8023_MIN_FRAME)
249702c85b0SNobuhiro Iwamatsu 		pkt_len = IEEE_8023_MIN_FRAME;
250702c85b0SNobuhiro Iwamatsu 
251702c85b0SNobuhiro Iwamatsu 	start_page = dp->tx_next;
252702c85b0SNobuhiro Iwamatsu 	if (dp->tx_next == dp->tx_buf1) {
253702c85b0SNobuhiro Iwamatsu 		dp->tx1 = start_page;
254702c85b0SNobuhiro Iwamatsu 		dp->tx1_len = pkt_len;
255702c85b0SNobuhiro Iwamatsu 		dp->tx1_key = key;
256702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf2;
257702c85b0SNobuhiro Iwamatsu 	} else {
258702c85b0SNobuhiro Iwamatsu 		dp->tx2 = start_page;
259702c85b0SNobuhiro Iwamatsu 		dp->tx2_len = pkt_len;
260702c85b0SNobuhiro Iwamatsu 		dp->tx2_key = key;
261702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf1;
262702c85b0SNobuhiro Iwamatsu 	}
263702c85b0SNobuhiro Iwamatsu 
264702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
265702c85b0SNobuhiro Iwamatsu 	printf("TX prep page %d len %d\n", start_page, pkt_len);
266702c85b0SNobuhiro Iwamatsu #endif
267702c85b0SNobuhiro Iwamatsu 
268702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC);	/* Clear end of DMA */
269702c85b0SNobuhiro Iwamatsu 	{
270702c85b0SNobuhiro Iwamatsu 		/*
271702c85b0SNobuhiro Iwamatsu 		 * Dummy read. The manual sez something slightly different,
272702c85b0SNobuhiro Iwamatsu 		 * but the code is extended a bit to do what Hitachi's monitor
273702c85b0SNobuhiro Iwamatsu 		 * does (i.e., also read data).
274702c85b0SNobuhiro Iwamatsu 		 */
275702c85b0SNobuhiro Iwamatsu 
276702c85b0SNobuhiro Iwamatsu 		u16 tmp;
277702c85b0SNobuhiro Iwamatsu 		int len = 1;
278702c85b0SNobuhiro Iwamatsu 
279702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0x100 - len);
280702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
281702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, len);
282702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
283702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
284702c85b0SNobuhiro Iwamatsu 		DP_IN_DATA(dp->data, tmp);
285702c85b0SNobuhiro Iwamatsu 	}
286702c85b0SNobuhiro Iwamatsu 
287702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
288702c85b0SNobuhiro Iwamatsu 	/*
289702c85b0SNobuhiro Iwamatsu 	 * Stall for a bit before continuing to work around random data
290702c85b0SNobuhiro Iwamatsu 	 * corruption problems on some platforms.
291702c85b0SNobuhiro Iwamatsu 	 */
292702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
293702c85b0SNobuhiro Iwamatsu #endif
294702c85b0SNobuhiro Iwamatsu 
295702c85b0SNobuhiro Iwamatsu 	/* Send data to device buffer(s) */
296702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 0);
297702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, start_page);
298702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
299702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, pkt_len >> 8);
300702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
301702c85b0SNobuhiro Iwamatsu 
302702c85b0SNobuhiro Iwamatsu 	/* Put data into buffer */
303702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
304702c85b0SNobuhiro Iwamatsu 	printf(" sg buf %08lx len %08x\n ", (u32)data, len);
305702c85b0SNobuhiro Iwamatsu 	dx = 0;
306702c85b0SNobuhiro Iwamatsu #endif
307702c85b0SNobuhiro Iwamatsu 	while (len > 0) {
308702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
309702c85b0SNobuhiro Iwamatsu 		printf(" %02x", *data);
310702c85b0SNobuhiro Iwamatsu 		if (0 == (++dx % 16)) printf("\n ");
311702c85b0SNobuhiro Iwamatsu #endif
312702c85b0SNobuhiro Iwamatsu 
313702c85b0SNobuhiro Iwamatsu 		DP_OUT_DATA(dp->data, *data++);
314702c85b0SNobuhiro Iwamatsu 		len--;
315702c85b0SNobuhiro Iwamatsu 	}
316702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
317702c85b0SNobuhiro Iwamatsu 	printf("\n");
318702c85b0SNobuhiro Iwamatsu #endif
319702c85b0SNobuhiro Iwamatsu 	if (total_len < pkt_len) {
320702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
321702c85b0SNobuhiro Iwamatsu 		printf("  + %d bytes of padding\n", pkt_len - total_len);
322702c85b0SNobuhiro Iwamatsu #endif
323702c85b0SNobuhiro Iwamatsu 		/* Padding to 802.3 length was required */
324702c85b0SNobuhiro Iwamatsu 		for (i = total_len; i < pkt_len;) {
325702c85b0SNobuhiro Iwamatsu 			i++;
326702c85b0SNobuhiro Iwamatsu 			DP_OUT_DATA(dp->data, 0);
327702c85b0SNobuhiro Iwamatsu 		}
328702c85b0SNobuhiro Iwamatsu 	}
329702c85b0SNobuhiro Iwamatsu 
330702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
331702c85b0SNobuhiro Iwamatsu 	/*
332702c85b0SNobuhiro Iwamatsu 	 * After last data write, delay for a bit before accessing the
333702c85b0SNobuhiro Iwamatsu 	 * device again, or we may get random data corruption in the last
334702c85b0SNobuhiro Iwamatsu 	 * datum (on some platforms).
335702c85b0SNobuhiro Iwamatsu 	 */
336702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
337702c85b0SNobuhiro Iwamatsu #endif
338702c85b0SNobuhiro Iwamatsu 
339702c85b0SNobuhiro Iwamatsu 	/* Wait for DMA to complete */
340702c85b0SNobuhiro Iwamatsu 	do {
341702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
342702c85b0SNobuhiro Iwamatsu 	} while ((isr & DP_ISR_RDC) == 0);
343702c85b0SNobuhiro Iwamatsu 
344702c85b0SNobuhiro Iwamatsu 	/* Then disable DMA */
345702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
346702c85b0SNobuhiro Iwamatsu 
347702c85b0SNobuhiro Iwamatsu 	/* Start transmit if not already going */
348702c85b0SNobuhiro Iwamatsu 	if (!dp->tx_started) {
349702c85b0SNobuhiro Iwamatsu 		if (start_page == dp->tx1) {
350702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 1; /* Expecting interrupt from BUF1 */
351702c85b0SNobuhiro Iwamatsu 		} else {
352702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 2; /* Expecting interrupt from BUF2 */
353702c85b0SNobuhiro Iwamatsu 		}
354702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(start_page, pkt_len);
355702c85b0SNobuhiro Iwamatsu 	}
356702c85b0SNobuhiro Iwamatsu }
357702c85b0SNobuhiro Iwamatsu 
358702c85b0SNobuhiro Iwamatsu /*
359702c85b0SNobuhiro Iwamatsu  * This function is called when a packet has been received. It's job is
360702c85b0SNobuhiro Iwamatsu  * to prepare to unload the packet from the hardware. Once the length of
361702c85b0SNobuhiro Iwamatsu  * the packet is known, the upper layer of the driver can be told. When
362702c85b0SNobuhiro Iwamatsu  * the upper layer is ready to unload the packet, the internal function
363702c85b0SNobuhiro Iwamatsu  * 'dp83902a_recv' will be called to actually fetch it from the hardware.
364702c85b0SNobuhiro Iwamatsu  */
365702c85b0SNobuhiro Iwamatsu static void
366702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(void)
367702c85b0SNobuhiro Iwamatsu {
368702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
369702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
370702c85b0SNobuhiro Iwamatsu 	u8 rsr;
371702c85b0SNobuhiro Iwamatsu 	u8 rcv_hdr[4];
372702c85b0SNobuhiro Iwamatsu 	int i, len, pkt, cur;
373702c85b0SNobuhiro Iwamatsu 
374702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
375702c85b0SNobuhiro Iwamatsu 
376702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_RSR, rsr);
377702c85b0SNobuhiro Iwamatsu 	while (true) {
378702c85b0SNobuhiro Iwamatsu 		/* Read incoming packet header */
379702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
380702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_CURP, cur);
381702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
382702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_BNDRY, pkt);
383702c85b0SNobuhiro Iwamatsu 
384702c85b0SNobuhiro Iwamatsu 		pkt += 1;
385702c85b0SNobuhiro Iwamatsu 		if (pkt == dp->rx_buf_end)
386702c85b0SNobuhiro Iwamatsu 			pkt = dp->rx_buf_start;
387702c85b0SNobuhiro Iwamatsu 
388702c85b0SNobuhiro Iwamatsu 		if (pkt == cur) {
389702c85b0SNobuhiro Iwamatsu 			break;
390702c85b0SNobuhiro Iwamatsu 		}
391702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
392702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
393702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0);
394702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, pkt);
395702c85b0SNobuhiro Iwamatsu 		if (dp->rx_next == pkt) {
396702c85b0SNobuhiro Iwamatsu 			if (cur == dp->rx_buf_start)
397702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
398702c85b0SNobuhiro Iwamatsu 			else
399702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
400702c85b0SNobuhiro Iwamatsu 			return;
401702c85b0SNobuhiro Iwamatsu 		}
402702c85b0SNobuhiro Iwamatsu 		dp->rx_next = pkt;
403702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
404702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
405702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
406702c85b0SNobuhiro Iwamatsu 		CYGACC_CALL_IF_DELAY_US(10);
407702c85b0SNobuhiro Iwamatsu #endif
408702c85b0SNobuhiro Iwamatsu 
409702c85b0SNobuhiro Iwamatsu 		/* read header (get data size)*/
410702c85b0SNobuhiro Iwamatsu 		for (i = 0; i < sizeof(rcv_hdr);) {
411702c85b0SNobuhiro Iwamatsu 			DP_IN_DATA(dp->data, rcv_hdr[i++]);
412702c85b0SNobuhiro Iwamatsu 		}
413702c85b0SNobuhiro Iwamatsu 
414702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
415702c85b0SNobuhiro Iwamatsu 		printf("rx hdr %02x %02x %02x %02x\n",
416702c85b0SNobuhiro Iwamatsu 			rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
417702c85b0SNobuhiro Iwamatsu #endif
418702c85b0SNobuhiro Iwamatsu 		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
419702c85b0SNobuhiro Iwamatsu 
420702c85b0SNobuhiro Iwamatsu 		/* data read */
421702c85b0SNobuhiro Iwamatsu 		uboot_push_packet_len(len);
422702c85b0SNobuhiro Iwamatsu 
423702c85b0SNobuhiro Iwamatsu 		if (rcv_hdr[1] == dp->rx_buf_start)
424702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
425702c85b0SNobuhiro Iwamatsu 		else
426702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
427702c85b0SNobuhiro Iwamatsu 	}
428702c85b0SNobuhiro Iwamatsu }
429702c85b0SNobuhiro Iwamatsu 
430702c85b0SNobuhiro Iwamatsu /*
431702c85b0SNobuhiro Iwamatsu  * This function is called as a result of the "eth_drv_recv()" call above.
432702c85b0SNobuhiro Iwamatsu  * It's job is to actually fetch data for a packet from the hardware once
433702c85b0SNobuhiro Iwamatsu  * memory buffers have been allocated for the packet. Note that the buffers
434702c85b0SNobuhiro Iwamatsu  * may come in pieces, using a scatter-gather list. This allows for more
435702c85b0SNobuhiro Iwamatsu  * efficient processing in the upper layers of the stack.
436702c85b0SNobuhiro Iwamatsu  */
437702c85b0SNobuhiro Iwamatsu static void
438702c85b0SNobuhiro Iwamatsu dp83902a_recv(u8 *data, int len)
439702c85b0SNobuhiro Iwamatsu {
440702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
441702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
442702c85b0SNobuhiro Iwamatsu 	int i, mlen;
443702c85b0SNobuhiro Iwamatsu 	u8 saved_char = 0;
444702c85b0SNobuhiro Iwamatsu 	bool saved;
445702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
446702c85b0SNobuhiro Iwamatsu 	int dx;
447702c85b0SNobuhiro Iwamatsu #endif
448702c85b0SNobuhiro Iwamatsu 
449702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
450702c85b0SNobuhiro Iwamatsu 
451702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
452702c85b0SNobuhiro Iwamatsu 	printf("Rx packet %d length %d\n", dp->rx_next, len);
453702c85b0SNobuhiro Iwamatsu #endif
454702c85b0SNobuhiro Iwamatsu 
455702c85b0SNobuhiro Iwamatsu 	/* Read incoming packet data */
456702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
457702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, len & 0xFF);
458702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, len >> 8);
459702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 4);		/* Past header */
460702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, dp->rx_next);
461702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
462702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
463702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
464702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(10);
465702c85b0SNobuhiro Iwamatsu #endif
466702c85b0SNobuhiro Iwamatsu 
467702c85b0SNobuhiro Iwamatsu 	saved = false;
468702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 1; i++) {
469702c85b0SNobuhiro Iwamatsu 		if (data) {
470702c85b0SNobuhiro Iwamatsu 			mlen = len;
471702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
472702c85b0SNobuhiro Iwamatsu 			printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
473702c85b0SNobuhiro Iwamatsu 			dx = 0;
474702c85b0SNobuhiro Iwamatsu #endif
475702c85b0SNobuhiro Iwamatsu 			while (0 < mlen) {
476702c85b0SNobuhiro Iwamatsu 				/* Saved byte from previous loop? */
477702c85b0SNobuhiro Iwamatsu 				if (saved) {
478702c85b0SNobuhiro Iwamatsu 					*data++ = saved_char;
479702c85b0SNobuhiro Iwamatsu 					mlen--;
480702c85b0SNobuhiro Iwamatsu 					saved = false;
481702c85b0SNobuhiro Iwamatsu 					continue;
482702c85b0SNobuhiro Iwamatsu 				}
483702c85b0SNobuhiro Iwamatsu 
484702c85b0SNobuhiro Iwamatsu 				{
485702c85b0SNobuhiro Iwamatsu 					u8 tmp;
486702c85b0SNobuhiro Iwamatsu 					DP_IN_DATA(dp->data, tmp);
487702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
488702c85b0SNobuhiro Iwamatsu 					printf(" %02x", tmp);
489702c85b0SNobuhiro Iwamatsu 					if (0 == (++dx % 16)) printf("\n ");
490702c85b0SNobuhiro Iwamatsu #endif
491702c85b0SNobuhiro Iwamatsu 					*data++ = tmp;;
492702c85b0SNobuhiro Iwamatsu 					mlen--;
493702c85b0SNobuhiro Iwamatsu 				}
494702c85b0SNobuhiro Iwamatsu 			}
495702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
496702c85b0SNobuhiro Iwamatsu 			printf("\n");
497702c85b0SNobuhiro Iwamatsu #endif
498702c85b0SNobuhiro Iwamatsu 		}
499702c85b0SNobuhiro Iwamatsu 	}
500702c85b0SNobuhiro Iwamatsu }
501702c85b0SNobuhiro Iwamatsu 
502702c85b0SNobuhiro Iwamatsu static void
503702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(void)
504702c85b0SNobuhiro Iwamatsu {
505702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
506702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
507702c85b0SNobuhiro Iwamatsu 	u8 tsr;
508702c85b0SNobuhiro Iwamatsu 	u32 key;
509702c85b0SNobuhiro Iwamatsu 
510702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
511702c85b0SNobuhiro Iwamatsu 
512702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_TSR, tsr);
513702c85b0SNobuhiro Iwamatsu 	if (dp->tx_int == 1) {
514702c85b0SNobuhiro Iwamatsu 		key = dp->tx1_key;
515702c85b0SNobuhiro Iwamatsu 		dp->tx1 = 0;
516702c85b0SNobuhiro Iwamatsu 	} else {
517702c85b0SNobuhiro Iwamatsu 		key = dp->tx2_key;
518702c85b0SNobuhiro Iwamatsu 		dp->tx2 = 0;
519702c85b0SNobuhiro Iwamatsu 	}
520702c85b0SNobuhiro Iwamatsu 	/* Start next packet if one is ready */
521702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
522702c85b0SNobuhiro Iwamatsu 	if (dp->tx1) {
523702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx1, dp->tx1_len);
524702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 1;
525702c85b0SNobuhiro Iwamatsu 	} else if (dp->tx2) {
526702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx2, dp->tx2_len);
527702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 2;
528702c85b0SNobuhiro Iwamatsu 	} else {
529702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 0;
530702c85b0SNobuhiro Iwamatsu 	}
531702c85b0SNobuhiro Iwamatsu 	/* Tell higher level we sent this packet */
532702c85b0SNobuhiro Iwamatsu 	uboot_push_tx_done(key, 0);
533702c85b0SNobuhiro Iwamatsu }
534702c85b0SNobuhiro Iwamatsu 
535702c85b0SNobuhiro Iwamatsu /*
536702c85b0SNobuhiro Iwamatsu  * Read the tally counters to clear them. Called in response to a CNT
537702c85b0SNobuhiro Iwamatsu  * interrupt.
538702c85b0SNobuhiro Iwamatsu  */
539702c85b0SNobuhiro Iwamatsu static void
540702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(void)
541702c85b0SNobuhiro Iwamatsu {
542702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
543702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
544702c85b0SNobuhiro Iwamatsu 	u8 cnt1, cnt2, cnt3;
545702c85b0SNobuhiro Iwamatsu 
546702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_FER, cnt1);
547702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_CER, cnt2);
548702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_MISSED, cnt3);
549702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_CNT);
550702c85b0SNobuhiro Iwamatsu }
551702c85b0SNobuhiro Iwamatsu 
552702c85b0SNobuhiro Iwamatsu /*
553702c85b0SNobuhiro Iwamatsu  * Deal with an overflow condition. This code follows the procedure set
554702c85b0SNobuhiro Iwamatsu  * out in section 7.0 of the datasheet.
555702c85b0SNobuhiro Iwamatsu  */
556702c85b0SNobuhiro Iwamatsu static void
557702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(void)
558702c85b0SNobuhiro Iwamatsu {
559702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
560702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
561702c85b0SNobuhiro Iwamatsu 	u8 isr;
562702c85b0SNobuhiro Iwamatsu 
563702c85b0SNobuhiro Iwamatsu 	/* Issue a stop command and wait 1.6ms for it to complete. */
564702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
565702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1600);
566702c85b0SNobuhiro Iwamatsu 
567702c85b0SNobuhiro Iwamatsu 	/* Clear the remote byte counter registers. */
568702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
569702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);
570702c85b0SNobuhiro Iwamatsu 
571702c85b0SNobuhiro Iwamatsu 	/* Enter loopback mode while we clear the buffer. */
572702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
573702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
574702c85b0SNobuhiro Iwamatsu 
575702c85b0SNobuhiro Iwamatsu 	/*
576702c85b0SNobuhiro Iwamatsu 	 * Read in as many packets as we can and acknowledge any and receive
577702c85b0SNobuhiro Iwamatsu 	 * interrupts. Since the buffer has overflowed, a receive event of
578702c85b0SNobuhiro Iwamatsu 	 * some kind will have occured.
579702c85b0SNobuhiro Iwamatsu 	 */
580702c85b0SNobuhiro Iwamatsu 	dp83902a_RxEvent();
581702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
582702c85b0SNobuhiro Iwamatsu 
583702c85b0SNobuhiro Iwamatsu 	/* Clear the overflow condition and leave loopback mode. */
584702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_OFLW);
585702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
586702c85b0SNobuhiro Iwamatsu 
587702c85b0SNobuhiro Iwamatsu 	/*
588702c85b0SNobuhiro Iwamatsu 	 * If a transmit command was issued, but no transmit event has occured,
589702c85b0SNobuhiro Iwamatsu 	 * restart it here.
590702c85b0SNobuhiro Iwamatsu 	 */
591702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
592702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
593702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
594702c85b0SNobuhiro Iwamatsu 	}
595702c85b0SNobuhiro Iwamatsu }
596702c85b0SNobuhiro Iwamatsu 
597702c85b0SNobuhiro Iwamatsu static void
598702c85b0SNobuhiro Iwamatsu dp83902a_poll(void)
599702c85b0SNobuhiro Iwamatsu {
600702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
601702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
602702c85b0SNobuhiro Iwamatsu 	u8 isr;
603702c85b0SNobuhiro Iwamatsu 
604702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
605702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
606702c85b0SNobuhiro Iwamatsu 	while (0 != isr) {
607702c85b0SNobuhiro Iwamatsu 		/*
608702c85b0SNobuhiro Iwamatsu 		 * The CNT interrupt triggers when the MSB of one of the error
609702c85b0SNobuhiro Iwamatsu 		 * counters is set. We don't much care about these counters, but
610702c85b0SNobuhiro Iwamatsu 		 * we should read their values to reset them.
611702c85b0SNobuhiro Iwamatsu 		 */
612702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_CNT) {
613702c85b0SNobuhiro Iwamatsu 			dp83902a_ClearCounters();
614702c85b0SNobuhiro Iwamatsu 		}
615702c85b0SNobuhiro Iwamatsu 		/*
616702c85b0SNobuhiro Iwamatsu 		 * Check for overflow. It's a special case, since there's a
617702c85b0SNobuhiro Iwamatsu 		 * particular procedure that must be followed to get back into
618702c85b0SNobuhiro Iwamatsu 		 * a running state.a
619702c85b0SNobuhiro Iwamatsu 		 */
620702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_OFLW) {
621702c85b0SNobuhiro Iwamatsu 			dp83902a_Overflow();
622702c85b0SNobuhiro Iwamatsu 		} else {
623702c85b0SNobuhiro Iwamatsu 			/*
624702c85b0SNobuhiro Iwamatsu 			 * Other kinds of interrupts can be acknowledged simply by
625702c85b0SNobuhiro Iwamatsu 			 * clearing the relevant bits of the ISR. Do that now, then
626702c85b0SNobuhiro Iwamatsu 			 * handle the interrupts we care about.
627702c85b0SNobuhiro Iwamatsu 			 */
628702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_ISR, isr);	/* Clear set bits */
629702c85b0SNobuhiro Iwamatsu 			if (!dp->running) break;	/* Is this necessary? */
630702c85b0SNobuhiro Iwamatsu 			/*
631702c85b0SNobuhiro Iwamatsu 			 * Check for tx_started on TX event since these may happen
632702c85b0SNobuhiro Iwamatsu 			 * spuriously it seems.
633702c85b0SNobuhiro Iwamatsu 			 */
634702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
635702c85b0SNobuhiro Iwamatsu 				dp83902a_TxEvent();
636702c85b0SNobuhiro Iwamatsu 			}
637702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
638702c85b0SNobuhiro Iwamatsu 				dp83902a_RxEvent();
639702c85b0SNobuhiro Iwamatsu 			}
640702c85b0SNobuhiro Iwamatsu 		}
641702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
642702c85b0SNobuhiro Iwamatsu 	}
643702c85b0SNobuhiro Iwamatsu }
644702c85b0SNobuhiro Iwamatsu 
645702c85b0SNobuhiro Iwamatsu 
646702c85b0SNobuhiro Iwamatsu /* U-boot specific routines */
647702c85b0SNobuhiro Iwamatsu static u8 *pbuf = NULL;
648702c85b0SNobuhiro Iwamatsu 
649702c85b0SNobuhiro Iwamatsu static int pkey = -1;
650702c85b0SNobuhiro Iwamatsu static int initialized = 0;
651702c85b0SNobuhiro Iwamatsu 
652702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len) {
653702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed len = %d\n", len);
654702c85b0SNobuhiro Iwamatsu 	if (len >= 2000) {
655702c85b0SNobuhiro Iwamatsu 		printf("NE2000: packet too big\n");
656702c85b0SNobuhiro Iwamatsu 		return;
657702c85b0SNobuhiro Iwamatsu 	}
658702c85b0SNobuhiro Iwamatsu 	dp83902a_recv(&pbuf[0], len);
659702c85b0SNobuhiro Iwamatsu 
660702c85b0SNobuhiro Iwamatsu 	/*Just pass it to the upper layer*/
661702c85b0SNobuhiro Iwamatsu 	NetReceive(&pbuf[0], len);
662702c85b0SNobuhiro Iwamatsu }
663702c85b0SNobuhiro Iwamatsu 
664702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val) {
665702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed key = %d\n", key);
666702c85b0SNobuhiro Iwamatsu 	pkey = key;
667702c85b0SNobuhiro Iwamatsu }
668702c85b0SNobuhiro Iwamatsu 
669702c85b0SNobuhiro Iwamatsu int eth_init(bd_t *bd) {
670702c85b0SNobuhiro Iwamatsu 	int r;
671702c85b0SNobuhiro Iwamatsu 	u8 dev_addr[6];
672702c85b0SNobuhiro Iwamatsu 	char ethaddr[20];
673702c85b0SNobuhiro Iwamatsu 
674702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_init\n");
675702c85b0SNobuhiro Iwamatsu 
676702c85b0SNobuhiro Iwamatsu 	if (!pbuf) {
677702c85b0SNobuhiro Iwamatsu 		pbuf = malloc(2000);
678702c85b0SNobuhiro Iwamatsu 		if (!pbuf) {
679702c85b0SNobuhiro Iwamatsu 			printf("Cannot allocate rx buffer\n");
680702c85b0SNobuhiro Iwamatsu 			return -1;
681702c85b0SNobuhiro Iwamatsu 		}
682702c85b0SNobuhiro Iwamatsu 	}
683702c85b0SNobuhiro Iwamatsu 
684702c85b0SNobuhiro Iwamatsu #ifdef CONFIG_DRIVER_NE2000_CCR
685702c85b0SNobuhiro Iwamatsu 	{
686702c85b0SNobuhiro Iwamatsu 		vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
687702c85b0SNobuhiro Iwamatsu 
688702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR before is %x\n", *p);
689702c85b0SNobuhiro Iwamatsu 		*p = CONFIG_DRIVER_NE2000_VAL;
690702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR after is %x\n", *p);
691702c85b0SNobuhiro Iwamatsu 	}
692702c85b0SNobuhiro Iwamatsu #endif
693702c85b0SNobuhiro Iwamatsu 
694702c85b0SNobuhiro Iwamatsu 	nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
695702c85b0SNobuhiro Iwamatsu 
696702c85b0SNobuhiro Iwamatsu 	r = get_prom(dev_addr, nic.base);
697702c85b0SNobuhiro Iwamatsu 	if (!r)
698702c85b0SNobuhiro Iwamatsu 		return -1;
699702c85b0SNobuhiro Iwamatsu 
700702c85b0SNobuhiro Iwamatsu 	sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
701702c85b0SNobuhiro Iwamatsu 		 dev_addr[0], dev_addr[1],
702702c85b0SNobuhiro Iwamatsu 		 dev_addr[2], dev_addr[3],
703702c85b0SNobuhiro Iwamatsu 		 dev_addr[4], dev_addr[5]) ;
704702c85b0SNobuhiro Iwamatsu 	PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
705702c85b0SNobuhiro Iwamatsu 	setenv ("ethaddr", ethaddr);
706702c85b0SNobuhiro Iwamatsu 
707702c85b0SNobuhiro Iwamatsu 	nic.data = nic.base + DP_DATA;
708702c85b0SNobuhiro Iwamatsu 	nic.tx_buf1 = START_PG;
709702c85b0SNobuhiro Iwamatsu 	nic.tx_buf2 = START_PG2;
710702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_start = RX_START;
711702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_end = RX_END;
712702c85b0SNobuhiro Iwamatsu 
713702c85b0SNobuhiro Iwamatsu 	if (dp83902a_init() == false)
714702c85b0SNobuhiro Iwamatsu 		return -1;
715702c85b0SNobuhiro Iwamatsu 
716702c85b0SNobuhiro Iwamatsu 	dp83902a_start(dev_addr);
717702c85b0SNobuhiro Iwamatsu 	initialized = 1;
718702c85b0SNobuhiro Iwamatsu 
719702c85b0SNobuhiro Iwamatsu 	return 0;
720702c85b0SNobuhiro Iwamatsu }
721702c85b0SNobuhiro Iwamatsu 
722702c85b0SNobuhiro Iwamatsu void eth_halt() {
723702c85b0SNobuhiro Iwamatsu 
724702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_halt\n");
725702c85b0SNobuhiro Iwamatsu 	if(initialized)
726702c85b0SNobuhiro Iwamatsu 		dp83902a_stop();
727702c85b0SNobuhiro Iwamatsu 	initialized = 0;
728702c85b0SNobuhiro Iwamatsu }
729702c85b0SNobuhiro Iwamatsu 
730702c85b0SNobuhiro Iwamatsu int eth_rx() {
731702c85b0SNobuhiro Iwamatsu 	dp83902a_poll();
732702c85b0SNobuhiro Iwamatsu 	return 1;
733702c85b0SNobuhiro Iwamatsu }
734702c85b0SNobuhiro Iwamatsu 
735702c85b0SNobuhiro Iwamatsu int eth_send(volatile void *packet, int length) {
736702c85b0SNobuhiro Iwamatsu 	int tmo;
737702c85b0SNobuhiro Iwamatsu 
738702c85b0SNobuhiro Iwamatsu 	PRINTK("### eth_send\n");
739702c85b0SNobuhiro Iwamatsu 
740702c85b0SNobuhiro Iwamatsu 	pkey = -1;
741702c85b0SNobuhiro Iwamatsu 
742702c85b0SNobuhiro Iwamatsu 	dp83902a_send((u8 *) packet, length, 666);
743*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tmo = get_timer (0) + TOUT * CONFIG_SYS_HZ;
744702c85b0SNobuhiro Iwamatsu 	while(1) {
745702c85b0SNobuhiro Iwamatsu 		dp83902a_poll();
746702c85b0SNobuhiro Iwamatsu 		if (pkey != -1) {
747702c85b0SNobuhiro Iwamatsu 			PRINTK("Packet sucesfully sent\n");
748702c85b0SNobuhiro Iwamatsu 			return 0;
749702c85b0SNobuhiro Iwamatsu 		}
750702c85b0SNobuhiro Iwamatsu 		if (get_timer (0) >= tmo) {
751702c85b0SNobuhiro Iwamatsu 			printf("transmission error (timoeut)\n");
752702c85b0SNobuhiro Iwamatsu 			return 0;
753702c85b0SNobuhiro Iwamatsu 		}
754702c85b0SNobuhiro Iwamatsu 
755702c85b0SNobuhiro Iwamatsu 	}
756702c85b0SNobuhiro Iwamatsu 	return 0;
757702c85b0SNobuhiro Iwamatsu }
758